diff --git a/CHANGELOG.md b/CHANGELOG.md index 093e56294e3..347b162dabd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,74 @@ +# [2026-09-18] (Chart Release 5.36.0) + +## Release notes + + +* `preventAdminlessGroups` is unlocked by default (#5496) + + +## API changes + + +* Finalize API version v18 and create development version v19. (#5531, #5536) + + +## Features + + +* Add federation support for `preventAdminlessGroups` system notifications, with capability-aware handling for older remote backends. (#5525, #5540) + +* Add `ssoIdpChangeDetectionEnabled` to `GET /system/settings`. (#5527) + +* Change the default value of totalLimitBytes from one terrabyte to unlimited (#5519) + +* Meeting events (`meeting.create`, `meeting.update`, `meeting.delete`, `meeting.member-add`) are now delivered to all push channels, including native push (APNs/FCM), so offline or backgrounded clients learn about meeting changes via native push instead of waiting for the next foreground sync. (#5537) + +* Support migrating user data to postgresql from cassandra (#5324) + + +## Bug fixes and other updates + + +* Revoking a pending SCIM invitation now removes the associated Brig account and + Spar SCIM metadata synchronously, allowing the same SCIM user to be invited + again. (#5510) + +* MLS message validation has been hardened. (#5517) + +* Account pages now use the correct backend URL and CSP header on each multi-ingress domain. This applies to both ingress charts: `nginx-ingress-services` no longer includes the account-pages host in its generic CSP snippet, and `wire-ingress` (envoy-gateway) no longer injects a Content-Security-Policy response header on the account-pages route. The same fix is applied to the webapp route in `wire-ingress`, which had the same problem (`nginx-ingress-services` already skipped it). (#5534) + +* Deleted SCIM users could still have pending team invitations. These are now + deleted (invalidated) with the SCIM user. (#5492) + +* Postgresql connection strings with mismatched host/port counts in service + configurations now lead to immediate failure with a clear error message instead + of silently producing an erroneous connection. (#5494) + + +## Documentation + + +* Remove cabal update from build steps and fix some typos in developer docs (#5523) + + +## Internal changes + + +* Script listing all commits and releases in which given files have been touched. (#5509) + +* MLS commit-bundles are processed with less sequential I/O: proposal references are resolved from a single store read, client and client-store updates fan out concurrently, and welcome pushes no longer block the response. (#5528) + +* Add diagnostic logging for failed MLS commit-bundle operations, including typed failures and exceptions during commit-lock handling. (#5544) + + +## Federation changes + + +* Add an opt-in policy for dropping queued federation notifications when the target backend supports no compatible API version. (#5501) + +* Remove stale local memberships when a remote conversation is definitively reported as not found. (#5504) + + # [2026-08-27] (Chart Release 5.35.0) ## Release notes diff --git a/cassandra-schema.cql b/cassandra-schema.cql index 9e5e1528992..160a310f39b 100644 --- a/cassandra-schema.cql +++ b/cassandra-schema.cql @@ -738,7 +738,7 @@ CREATE TABLE brig_test.rich_info ( AND crc_check_chance = 1.0 AND default_time_to_live = 0 AND extensions = {} - AND gc_grace_seconds = 864000 + AND gc_grace_seconds = 86400 AND max_index_interval = 2048 AND memtable_flush_period_in_ms = 0 AND min_index_interval = 128 @@ -848,7 +848,7 @@ CREATE TABLE brig_test.service_team ( AND crc_check_chance = 1.0 AND default_time_to_live = 0 AND extensions = {} - AND gc_grace_seconds = 864000 + AND gc_grace_seconds = 86400 AND max_index_interval = 2048 AND memtable_flush_period_in_ms = 0 AND min_index_interval = 128 @@ -874,7 +874,7 @@ CREATE TABLE brig_test.service_user ( AND crc_check_chance = 1.0 AND default_time_to_live = 0 AND extensions = {} - AND gc_grace_seconds = 864000 + AND gc_grace_seconds = 86400 AND max_index_interval = 2048 AND memtable_flush_period_in_ms = 0 AND min_index_interval = 128 @@ -1088,7 +1088,7 @@ CREATE TABLE brig_test.user ( AND crc_check_chance = 1.0 AND default_time_to_live = 0 AND extensions = {} - AND gc_grace_seconds = 864000 + AND gc_grace_seconds = 86400 AND max_index_interval = 2048 AND memtable_flush_period_in_ms = 0 AND min_index_interval = 128 @@ -1137,7 +1137,7 @@ CREATE TABLE brig_test.user_handle ( AND crc_check_chance = 1.0 AND default_time_to_live = 0 AND extensions = {} - AND gc_grace_seconds = 864000 + AND gc_grace_seconds = 86400 AND max_index_interval = 2048 AND memtable_flush_period_in_ms = 0 AND min_index_interval = 128 diff --git a/charts/nginx-ingress-services/templates/ingress.yaml b/charts/nginx-ingress-services/templates/ingress.yaml index c0f1635efdc..77d07967fe9 100644 --- a/charts/nginx-ingress-services/templates/ingress.yaml +++ b/charts/nginx-ingress-services/templates/ingress.yaml @@ -1,3 +1,7 @@ +{{- $accountPagesDns := "" -}} +{{- if .Values.accountPages.enabled -}} +{{- $accountPagesDns = required "Need a 'config.dns.accountPages' name when accountPages.enabled is true." .Values.config.dns.accountPages -}} +{{- end -}} apiVersion: networking.k8s.io/v1 kind: Ingress metadata: @@ -46,6 +50,13 @@ metadata: if ($http_host = "{{ .Values.config.dns.webapp }}") { set $skip_csp 1; } + {{ if .Values.accountPages.enabled }} + # Like the webapp, account-pages provides multi-ingress aware CSP headers + # itself, so the approximation below must not overwrite them. + if ($http_host = "{{ $accountPagesDns }}") { + set $skip_csp 1; + } + {{ end }} if ($uri ~ "^(/v[0-9]+)?/sso/(finalize-login|initiate-login)(/[a-zA-Z0-9-]*)?$|^/favicon\.ico$") { set $skip_csp 1; } @@ -91,7 +102,7 @@ spec: - {{ .Values.config.dns.teamSettings }} {{- end }} {{- if .Values.accountPages.enabled }} - - {{ .Values.config.dns.accountPages }} + - {{ $accountPagesDns }} {{- end }} secretName: {{ include "nginx-ingress-services.getCertificateSecretName" . | quote }} rules: @@ -142,7 +153,7 @@ spec: number: {{ .Values.service.teamSettings.externalPort }} {{- end }} {{- if .Values.accountPages.enabled }} - - host: {{ .Values.config.dns.accountPages }} + - host: {{ $accountPagesDns }} http: paths: - path: / diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 73433734acc..7b31b398477 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -103,7 +103,7 @@ name overrides, etc.) can be found in `values.yaml`. | `config.ingressClass` | | | `ingressName` | Replaced by `config.domains[].name` — see [Multi-ingress (multiple backend domains)](#multi-ingress-multiple-backend-domains) | | `config.isAdditionalIngress` | Implicit — every `config.domains` entry after the first is an additional ingress | -| `config.renderCSPInIngress` | CSP is injected automatically on additional domains; opt out per-domain with `config.domains[].renderCSP: false` | +| `config.renderCSPInIngress` | CSP is injected automatically on additional domains (team-settings route only); opt out per-domain with `config.domains[].renderCSP: false` | | `config.dns.base` | Replaced by `config.domains[].base` (used for the per-domain CSP wildcard) | | `tls.verify_depth` | Envoy Gateway `ClientTrafficPolicy` does not expose a direct verify-depth knob; the CA chain itself controls this | | `tls.enabled` | Removed — had no effect; all routes are always TLS-terminated | @@ -250,8 +250,12 @@ config: First entry = primary (listener `https`, un-suffixed names, no injected CSP — apps set their own). Each additional entry gets its own listener `https-`, cert/secret, suffixed routes, and an -injected per-domain CSP header on the webapp/team-settings/account-pages routes (opt out with -`renderCSP: false`). +injected per-domain CSP header on the team-settings route (opt out with `renderCSP: false`). + +The webapp and account-pages routes never get an injected CSP, on any domain: both apps emit +correct per-domain headers themselves, and the injected header would replace them with a weaker +approximation. This matches the hosts the legacy `nginx-ingress-services` chart skips in its CSP +snippet. Team-settings does not yet support this, hence the approximation there. Multi-ingress is mutually exclusive with federation: `config.domains` cannot be combined with `federator.enabled: true`. Use federation with a single backend diff --git a/charts/wire-ingress/templates/_helpers.tpl b/charts/wire-ingress/templates/_helpers.tpl index f780f7f35c5..8990fcc5011 100644 --- a/charts/wire-ingress/templates/_helpers.tpl +++ b/charts/wire-ingress/templates/_helpers.tpl @@ -86,7 +86,9 @@ Multi-domain: `config.domains` is a list; the FIRST entry is the primary (its resources keep the un-suffixed names, and its frontend apps set their own CSP so no CSP is injected). Every additional entry gets a `-` suffix, its own Gateway listener (`https-`), its own certificate/secret, and — being -an "additional ingress" — a per-domain CSP header injected on the app routes. +an "additional ingress" — a per-domain CSP header injected on the team-settings +route. The webapp and account-pages routes never get an injected CSP: those +apps set multi-ingress aware headers themselves (see the httproute templates). Each entry has: suffix, section, hostname, https, ssl, webapp, teamSettings, accountPages, fakeS3, base, secretName, certName, issuerName, issuerKind, @@ -183,6 +185,10 @@ for multi-ingress domains (charts/nginx-ingress-services/templates/ingress.yaml) where the primary domain's frontend apps set CSP themselves but additional domains need the header set at the front door. +Only the team-settings route uses this. The webapp and account-pages routes are +excluded, matching the `$skip_csp` hosts in the nginx chart's snippet, because +those apps emit correct per-domain headers on their own. + Call with a dict: {https, ssl, base, websockets (bool)}. */}} {{- define "wire-ingress.cspHeader" -}} diff --git a/charts/wire-ingress/templates/httproute-account-pages.yaml b/charts/wire-ingress/templates/httproute-account-pages.yaml index 385876a2e31..c1115985b91 100644 --- a/charts/wire-ingress/templates/httproute-account-pages.yaml +++ b/charts/wire-ingress/templates/httproute-account-pages.yaml @@ -30,14 +30,11 @@ spec: - path: type: PathPrefix value: / - {{- if $domain.csp }} - filters: - - type: ResponseHeaderModifier - responseHeaderModifier: - set: - - name: Content-Security-Policy - value: {{ include "wire-ingress.cspHeader" (dict "https" $domain.https "ssl" $domain.ssl "base" $domain.base "websockets" $root.Values.websockets.enabled) | quote }} - {{- end }} + {{/* No CSP header is injected here. Unlike team-settings, account-pages + sets multi-ingress aware CSP headers itself, and a ResponseHeaderModifier + "set" filter would replace them with the weaker approximation from + wire-ingress.cspHeader. This mirrors the legacy nginx-ingress-services + chart, which skips its CSP snippet for this host. */}} backendRefs: - name: account-pages-http port: {{ $root.Values.service.accountPages.externalPort }} diff --git a/charts/wire-ingress/templates/httproute-webapp.yaml b/charts/wire-ingress/templates/httproute-webapp.yaml index 07844ec80a9..f66cb1b8c2d 100644 --- a/charts/wire-ingress/templates/httproute-webapp.yaml +++ b/charts/wire-ingress/templates/httproute-webapp.yaml @@ -30,14 +30,11 @@ spec: - path: type: PathPrefix value: / - {{- if $domain.csp }} - filters: - - type: ResponseHeaderModifier - responseHeaderModifier: - set: - - name: Content-Security-Policy - value: {{ include "wire-ingress.cspHeader" (dict "https" $domain.https "ssl" $domain.ssl "base" $domain.base "websockets" $root.Values.websockets.enabled) | quote }} - {{- end }} + {{/* No CSP header is injected here. Unlike team-settings, the webapp + sets multi-ingress aware CSP headers itself, and a ResponseHeaderModifier + "set" filter would replace them with the weaker approximation from + wire-ingress.cspHeader. This mirrors the legacy nginx-ingress-services + chart, which skips its CSP snippet for this host. */}} backendRefs: - name: webapp-http port: {{ $root.Values.service.webapp.externalPort }} diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml index bcd14ac911b..b4d665a54d7 100644 --- a/charts/wire-ingress/values.yaml +++ b/charts/wire-ingress/values.yaml @@ -125,8 +125,10 @@ gateway: # the un-suffixed names, and its frontend apps set their own CSP). Every # additional entry gets its own Gateway HTTPS listener (`https-`), its own # certificate/secret, and — being an "additional ingress" — a per-domain -# Content-Security-Policy header injected on the webapp/team-settings/ -# account-pages routes (mirrors the legacy nginx-ingress-services behaviour). +# Content-Security-Policy header injected on the team-settings route (mirrors +# the legacy nginx-ingress-services behaviour). The webapp and account-pages +# routes are left alone: those apps set multi-ingress aware CSP headers +# themselves, and injecting here would overwrite them. # # config.dns and config.domains are mutually exclusive; config.domains wins. # @@ -153,7 +155,7 @@ gateway: # https: nginz-https.red.example.org # ssl: nginz-ssl.red.example.org # webapp: webapp.red.example.org -# # renderCSP: false # optional: disable the injected CSP for this domain +# # renderCSP: false # optional: disable the injected CSP (team-settings) for this domain # tls: # # secretName: "" # optional TLS secret name override (defaults to a per-domain name) # issuer: # optional per-domain cert-manager issuer override (defaults to tls.issuer) diff --git a/charts/wire-server/templates/background-worker/configmap.yaml b/charts/wire-server/templates/background-worker/configmap.yaml index d4fe2a63202..299d0703d3a 100644 --- a/charts/wire-server/templates/background-worker/configmap.yaml +++ b/charts/wire-server/templates/background-worker/configmap.yaml @@ -84,6 +84,7 @@ data: migrateConversationCodes: {{ .migrateConversationCodes }} migrateTeamFeatures: {{ .migrateTeamFeatures }} migrateDomainRegistration: {{ .migrateDomainRegistration }} + migrateUsers: {{ .migrateUsers }} migrationOptions: {{ toYaml .migrationOptions | indent 6 }} diff --git a/charts/wire-server/templates/brig/configmap.yaml b/charts/wire-server/templates/brig/configmap.yaml index ad9ee08bf8f..7a43c8244ce 100644 --- a/charts/wire-server/templates/brig/configmap.yaml +++ b/charts/wire-server/templates/brig/configmap.yaml @@ -396,5 +396,16 @@ data: setNomadProfiles: {{ index . "setNomadProfiles" }} {{- end }} setConsumableNotifications: false + {{- /* Raw spar multi-ingress inputs (schema: spar.config in values.yaml). + Brig derives ssoIdpChangeDetectionEnabled from them at runtime + (see Brig.Options.deriveSsoIdpChangeDetectionEnabled). Keep the + rendered keys in sync with its FromJSON instance. */}} + {{- with $.Values.spar }} + {{- with .config }} + setSsoIdpChangeDetectionInputs: + multiIngressDomainConfigs: {{ .domainConfigs | default (dict) | toJson }} + idpCertFingerprintAllowlist: {{ .idpCertFingerprintAllowlist | default (list) | toJson }} + {{- end }} + {{- end }} {{- end }} {{- end }} diff --git a/charts/wire-server/templates/gundeck/configmap.yaml b/charts/wire-server/templates/gundeck/configmap.yaml index 10be21c34e1..7e844043675 100644 --- a/charts/wire-server/templates/gundeck/configmap.yaml +++ b/charts/wire-server/templates/gundeck/configmap.yaml @@ -63,6 +63,14 @@ data: {{- end }} {{- end }} + {{- if .postgresql }} + postgresql: {{ toYaml .postgresql | nindent 6 }} + postgresqlPool: {{ toYaml .postgresqlPool | nindent 6 }} + {{- if hasKey $.Values.gundeck.secrets "pgPassword" }} + postgresqlPassword: /etc/wire/gundeck/secrets/pgPassword + {{- end }} + {{- end }} + # Gundeck uses discovery for AWS access key / secrets # For more details, check amazonka's documentation at: # https://hackage.haskell.org/package/amazonka-1.4.5/docs/Network-AWS.html#t:Credentials diff --git a/charts/wire-server/templates/gundeck/secret.yaml b/charts/wire-server/templates/gundeck/secret.yaml index b1f744ff600..000255ba0a6 100644 --- a/charts/wire-server/templates/gundeck/secret.yaml +++ b/charts/wire-server/templates/gundeck/secret.yaml @@ -31,5 +31,8 @@ data: {{- if hasKey . "redisAdditionalWritePassword" }} redisAdditionalWritePassword: {{ .redisAdditionalWritePassword | b64enc | quote }} {{- end }} + {{- if hasKey . "pgPassword" }} + pgPassword: {{ .pgPassword | b64enc | quote }} + {{- end }} {{- end }} {{- end }} diff --git a/charts/wire-server/values.yaml b/charts/wire-server/values.yaml index 5bb0b276eb6..d2a7deafdc5 100644 --- a/charts/wire-server/values.yaml +++ b/charts/wire-server/values.yaml @@ -260,10 +260,9 @@ galley: allowed_to_open_channels: team-members lockStatus: locked preventAdminlessGroups: - # This feature has known errors. Thus, it must stay disabled for now. defaults: status: disabled - lockStatus: locked + lockStatus: unlocked config: promotionStrategy: alphabetical deletionTimeoutDuration: 7d @@ -314,7 +313,7 @@ galley: collabora: edition: COOL storage: - totalLimitBytes: "1000000000000" + totalLimitBytes: "-1" perUserQuotaBytes: "-1" allowedGlobalOperations: status: enabled @@ -1026,6 +1025,10 @@ background-worker: # It's important to set `settings.postgresMigration.domainRegistration` to `migration-to-postgresql` # before starting the migration. migrateDomainRegistration: false + # This will start the migration of users + # It's important to set `settings.postgresMigration.users` to `migration-to-postgresql` + # before starting the migration. + migrateUsers: false backendNotificationPusher: pushBackoffMinWait: 10000 # in microseconds, so 10ms diff --git a/deploy/dockerephemeral/docker-compose.yaml b/deploy/dockerephemeral/docker-compose.yaml index 2081edddc21..fb2a4801ebc 100644 --- a/deploy/dockerephemeral/docker-compose.yaml +++ b/deploy/dockerephemeral/docker-compose.yaml @@ -290,7 +290,7 @@ services: POSTGRES_PASSWORD: "posty-the-gres" POSTGRES_USER: "wire-server" POSTGRES_DB: "backendA" - command: postgres -c max_connections=150 + command: postgres -c max_connections=1000 cassandra: container_name: demo_wire_cassandra diff --git a/docs/src/developer/developer/api-versioning.md b/docs/src/developer/developer/api-versioning.md index c6f70a08e71..7904fcf87a7 100644 --- a/docs/src/developer/developer/api-versioning.md +++ b/docs/src/developer/developer/api-versioning.md @@ -282,7 +282,7 @@ When invoking an endpoint as a federation client, we need to make sure that all supported versions are covered. The `FederatorClient` monad has an `Alternative` instance which can be useful for this purpose: an action will fail (before even performing any request) if it refers to an endpoint whose version -range does not contain the version that was negotiatted. +range does not contain the version that was negotiated. For example, suppose that `get-user-clients` disappears in version 2, and clients are now supposed to use an endpoint called `get-clients-ng`, with diff --git a/docs/src/developer/developer/building.md b/docs/src/developer/developer/building.md index 6b754e073bb..bcbca56502c 100644 --- a/docs/src/developer/developer/building.md +++ b/docs/src/developer/developer/building.md @@ -45,16 +45,6 @@ and go and grab a coffee. ☕ Your system will likely not build much, but it will definitely spend some time fetching things from different caches. -### initializing the cabal mirrors - -There are a few dependencies that are not provided by the nix env, for these, please run - -```bash -cabal update -``` - -now that you’re in the devshell. - ### building wire-server #### with cabal @@ -154,7 +144,7 @@ make full-clean ### Cabal can’t read index (Did you call checkForUpdates?) -Sometimes abording cabal mid-update can corrupt its index. Deleting `~/.cabal/packages/hackage.haskell.org` will usually do the trick. +Sometimes aborting cabal mid-update can corrupt its index. Deleting `~/.cabal/packages/hackage.haskell.org` will usually do the trick. As a side-note: `make c` doesn’t run `cabal update`, but `make` does, so keep that in mind. @@ -182,7 +172,7 @@ Setting up these real, but in-memory internal and “fake” external dependenci deploy/dockerephemeral/run.sh ``` -Also make sure your system is able to resolve the fully qualified domain `localhost.` (note the trailing dot). This is surprisingly not trivial, because of limitations in how libc parses `/etc/hosts`. You can check that with, for example, `ping localhost.`. If you get a name resolution error, you need to add `localhost.` explictly to your `/etc/hosts` file. +Also make sure your system is able to resolve the fully qualified domain `localhost.` (note the trailing dot). This is surprisingly not trivial, because of limitations in how libc parses `/etc/hosts`. You can check that with, for example, `ping localhost.`. If you get a name resolution error, you need to add `localhost.` explicitly to your `/etc/hosts` file. After all containers are up you can use these Makefile targets to run the tests locally: @@ -220,7 +210,7 @@ After all containers are up you can use these Makefile targets to run the tests ## How to run the webapp locally against locally running backend 1. Clone the webapp from: https://github.com/wireapp/wire-webapp -2. Install these depedencies needed for the webapp: +2. Install these dependencies needed for the webapp: 1. nodejs 2. yarn 3. mkcert diff --git a/docs/src/developer/developer/coding-conventions.md b/docs/src/developer/developer/coding-conventions.md index 5df624aac44..22d6a4ce2ed 100644 --- a/docs/src/developer/developer/coding-conventions.md +++ b/docs/src/developer/developer/coding-conventions.md @@ -17,7 +17,7 @@ convert from and to `String` and `Text` which are nowadays typically `utf8` enco and a `String` or `Text` can be different; e.g. we could decode a `ByteString` as ASCII-Chars or as utf8, just to name a few. -There’s another inherent problem to `cs` in that context, namely **readability**; a `TL.fromStict` immediately tells +There’s another inherent problem to `cs` in that context, namely **readability**; a `TL.fromStrict` immediately tells you what the code does; `cs`, however, says nothing; you know there’s *some* conversion going on but not which. We have hence decided to not use the error-prone and hard-to-read `cs` in production code, i.e., in all libraries diff --git a/docs/src/developer/developer/how-to.md b/docs/src/developer/developer/how-to.md index 8e8f97fc128..440bba4bcc8 100644 --- a/docs/src/developer/developer/how-to.md +++ b/docs/src/developer/developer/how-to.md @@ -21,7 +21,7 @@ Terminal 2: * Build and start wire-server services: ` make c && ./dist/run-services` Open your browser at: -[http://localhost:8080/api/swagger-ui](http://localhost:8080/api/swagger-ui) for a list of API verions. +[http://localhost:8080/api/swagger-ui](http://localhost:8080/api/swagger-ui) for a list of API versions. Also check out the docs for swagger in our staging environment: [Swagger / OpenAPI documentation](../../understand/api-client-perspective/swagger.md#swagger-api-docs). Replace the staging domain by @@ -96,7 +96,7 @@ This will create two full installations of wire-server on the kubernetes cluster Check CI for the latest tag that has been created on your PR (expect this to take at least 30-60 minutes from the last time you pushed to your branch). Example: -Look at a successful job in the `wire-server-pr` pipeline from a job bruild matching your desired PR and commit hash. Then, find the actual docker tag used. +Look at a successful job in the `wire-server-pr` pipeline from a job build matching your desired PR and commit hash. Then, find the actual docker tag used. ![concourse-pr-version-circled](https://user-images.githubusercontent.com/2112744/114410146-69b34000-9bab-11eb-863c-106fb661ca82.png) diff --git a/docs/src/developer/developer/open-telemetry.md b/docs/src/developer/developer/open-telemetry.md index 240d5b4daaf..0d1750604ea 100644 --- a/docs/src/developer/developer/open-telemetry.md +++ b/docs/src/developer/developer/open-telemetry.md @@ -11,7 +11,7 @@ The following components have been instrumented: ## Known Issues and future work -- Proper HTTP/2 instrumentation is missing for federator & co - this is related to http/2 outobj in the http2 libraray throwing away all structured information +- Proper HTTP/2 instrumentation is missing for federator & co - this is related to http/2 outobj in the http2 library throwing away all structured information - Some parts of the service, such as background jobs, may need additional instrumentation. It’s currently unclear if these are appearing in the tracing data. - we need to ingest the data into grafana tempo diff --git a/docs/src/developer/developer/pr-guidelines.md b/docs/src/developer/developer/pr-guidelines.md index d8bc1cffd37..00210ff82a6 100644 --- a/docs/src/developer/developer/pr-guidelines.md +++ b/docs/src/developer/developer/pr-guidelines.md @@ -62,7 +62,7 @@ For customer support access to an internal endpoint, instead update code in [ste ### Demo nginz configuration -New entris should include `common_response_no_zauth.conf;` for public endpoints without authentication and `common_response_with_zauth.conf;` for regular (authenticated) endpoints. Browse the file to see examples. +New entries should include `common_response_no_zauth.conf;` for public endpoints without authentication and `common_response_with_zauth.conf;` for regular (authenticated) endpoints. Browse the file to see examples. ### Example @@ -109,7 +109,7 @@ Remove them with the PR from wire-server `./charts` folder, as charts are linked ### Renaming configuration flags -Avoid doing this, it’s usually viable to introduce an at-least-equally-good name and remove the old one, that admins can first add the new options, then uprade the software, then remove the old ones. +Avoid doing this, it’s usually viable to introduce an at-least-equally-good name and remove the old one, that admins can first add the new options, then upgrade the software, then remove the old ones. If you must, see Removing/adding sections above. But please note that all people who have an installation of wire also may have overridden any of the configuration option you may wish to change the name of. As this is not type checked, it’s very error prone and people may find themselves with default configuration values being used instead of their intended configuration settings. Guideline: only rename for good reasons, not for aesthetics; or be prepared to spend a significant amount on documenting and communication about this change. diff --git a/docs/src/developer/reference/config-options.md b/docs/src/developer/reference/config-options.md index cf86ee7681c..062f891f03c 100644 --- a/docs/src/developer/reference/config-options.md +++ b/docs/src/developer/reference/config-options.md @@ -811,7 +811,7 @@ config: collabora: edition: COOL storage: - totalLimitBytes: "1000000000000" # 1 TB + totalLimitBytes: "-1" perUserQuotaBytes: "-1" ``` @@ -1320,6 +1320,37 @@ brig: stored. The challenge (`StoredDomainVerificationChallenge`) will be deleted after this period. +### SSO Settings + +#### `setSsoIdpChangeDetectionInputs` + +When the reported `ssoIdpChangeDetectionEnabled` is `true`, the authenticated +`GET /system/settings` endpoint tells clients to compare the stored SSO IdP ID +with the IdP ID used for the current login and to keep existing locally +decrypted messages when they match. When false or absent, clients treat an IdP +change as before. Only the authenticated endpoint reports this field; the +public `/system/settings/unauthorized` endpoint does not. + +Brig derives `ssoIdpChangeDetectionEnabled` from these raw spar inputs: it +reports `true` iff `multiIngressDomainConfigs` and +`idpCertFingerprintAllowlist` are both non-empty. The wire-server Helm chart +renders them from `spar.config`; deployments outside the chart should mirror +their spar multi-ingress configuration, and the absence of this setting +disables the feature. + +```default +# [brig.yaml] +optSettings: + setSsoIdpChangeDetectionInputs: + multiIngressDomainConfigs: + nginz-https.example.com: + appUri: https://webapp.example.com + ssoUri: https://nginz-https.example.com/sso + idpCertFingerprintAllowlist: + - "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD" +``` + + ## Settings in cargohold AWS S3 (or an alternative provider / service) is used to upload and download @@ -2187,6 +2218,7 @@ The current settings and their background-worker flags are: - `conversationCodes` -> `migrateConversationCodes` - `teamFeatures` -> `migrateTeamFeatures` - `domainRegistration` -> `migrateDomainRegistration` +- `user` -> `migrateUsers` **Migration pattern per migration setting** @@ -2205,13 +2237,15 @@ The current settings and their background-worker flags are: conversation: migration-to-postgresql conversationCodes: migration-to-postgresql teamFeatures: migration-to-postgresql - domainRegistration: cassandra + domainRegistration: migration-to-postgresql + user: migration-to-postgresql background-worker: config: migrateConversations: false migrateConversationCodes: false migrateTeamFeatures: false migrateDomainRegistration: false + migrateUsers: false ``` This change should restart the affected pods, and new writes will follow the @@ -2226,6 +2260,7 @@ The current settings and their background-worker flags are: migrateConversationCodes: true migrateTeamFeatures: true migrateDomainRegistration: true + migrateUsers: true ``` During migration, Cassandra rows are not deleted. Writes and migration share @@ -2241,6 +2276,16 @@ The current settings and their background-worker flags are: - `conversationCodes`: `wire_conv_codes_migration_finished` - `teamFeatures`: `wire_team_features_migration_finished` - `domainRegistration`: `wire_domain_registration_migration_finished` + - `user`: `wire_user_migration_finished` + + > ⚠️ For user migrations please watch the logs for `Invalid user found, + > skipping`. This would be accompanied by an error which is either + > `UserHasNoName` or `UserHasNoActivated`. These users are invalid and all + > interactions with them were resulting in errors. If these warnings are + > ignored, these users will stop existing in the system. If these users are + > to be saved, the operator must insert some value as `name` and/or + > `activated` and then re-trigger the migration **after** the background + > worker finishes migrating the valid users. 3. Cut over reads and writes to PostgreSQL for the selected migration setting(s). This configuration must be used from now on for every new @@ -2253,13 +2298,15 @@ The current settings and their background-worker flags are: conversation: postgresql conversationCodes: postgresql teamFeatures: postgresql - domainRegistration: cassandra + domainRegistration: postgresql + user: postgresql background-worker: config: migrateConversations: false migrateConversationCodes: false migrateTeamFeatures: false migrateDomainRegistration: false + migrateUsers: false ``` **How to run migrations independently or in batches** diff --git a/flake.lock b/flake.lock index bd8e74f6d3a..67d13b227d8 100644 --- a/flake.lock +++ b/flake.lock @@ -350,16 +350,16 @@ "postgresql-connection-string": { "flake": false, "locked": { - "lastModified": 1778144330, - "narHash": "sha256-w/TFQX7PIsLQTG+Es2yla584Y3T7Q6H1iIlqFap8qUk=", + "lastModified": 1787930090, + "narHash": "sha256-ti+XZdhoCiDxgyUilva7EpV8SOfMlmwuKr28XkJ62N0=", "owner": "wireapp", "repo": "postgresql-connection-string", - "rev": "ff98790cb3058545ea978ea143cd57b04360c48c", + "rev": "bd5a2d72c15fa4ffe561e3b3f441e5809050f918", "type": "github" }, "original": { "owner": "wireapp", - "ref": "expose-from-key-value-params", + "ref": "wire-patches", "repo": "postgresql-connection-string", "type": "github" } diff --git a/flake.nix b/flake.nix index 09cc084bba4..46255be3e45 100644 --- a/flake.nix +++ b/flake.nix @@ -87,7 +87,8 @@ }; postgresql-connection-string = { - url = "github:wireapp/postgresql-connection-string?ref=expose-from-key-value-params"; + url = + "github:wireapp/postgresql-connection-string?ref=wire-patches"; flake = false; }; diff --git a/hack/bin/super-blame.sh b/hack/bin/super-blame.sh new file mode 100755 index 00000000000..fb9293afd9f --- /dev/null +++ b/hack/bin/super-blame.sh @@ -0,0 +1,101 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat <[@] [file ...] + +List commits that changed the given file(s) in chronological order, +annotated with the release in which each commit landed on master. + +A commit's release is the oldest chart/X.Y.0 tag on master whose +tagged commit is not older than the commit itself. + +Line ranges limit output to commits that changed those lines. +Syntax: file.hs@1,15-18 (single lines and ranges, comma-separated) +If no line ranges are given, all commits for the file are shown. + +Options: + -h Show this help +EOF + exit 0 +} + +if [ $# -eq 0 ]; then + echo "Usage: $0 [-h] [@] [file ...]" >&2 + exit 1 +fi + +if [ "$1" = "-h" ]; then + usage +fi + +git fetch --tags + +releases_tmp=$(mktemp) +trap 'rm -f "$releases_tmp"' EXIT + +while read -r tag; do + commit=$(git rev-list -1 "$tag") + ts=$(git log -1 --format="%ct" "$commit") + date=$(git log -1 --format="%ai" "$commit") + echo "${ts} ${tag} ${date}" +done < <(git tag --merged origin/master 'chart/*.0' | sort -V) > "$releases_tmp" + +annotate() { + while read -r commit_ts rest; do + commit=$(echo "$rest" | awk '{print $4}') + release="" + release_date="" + while read -r ts tag rdate; do + if [ "$ts" -ge "$commit_ts" ]; then + release="$tag" + release_date="$rdate" + break + fi + done < <(sort -n "$releases_tmp") + if [ -n "$release" ]; then + echo "$rest [$release, $release_date]" + else + echo "$rest [unreleased]" + fi + done +} + +for arg in "$@"; do + file="${arg%@*}" + lines="${arg##*@}" + if [ "$file" = "$arg" ]; then + lines="" + fi + + if [ ! -f "$file" ]; then + echo "Error: file not found: $file" >&2 + exit 1 + fi + + echo "=== $arg ===" + + if [ -z "$lines" ]; then + git log --follow --format="%ct %ai %H %s" -- "$file" | annotate + else + commits_tmp=$(mktemp) + IFS=',' read -ra ranges <<< "$lines" + for r in "${ranges[@]}"; do + if [[ "$r" == *"-"* ]]; then + start="${r%-*}" + end="${r#*-}" + else + start="$r" + end="$r" + fi + git log -L "${start},${end}:${file}" -s --format="%ct %ai %H %s" >> "$commits_tmp" + done + # Each line-range query may return the same commit. `sort -u` + # deduplicates and sorts by timestamp (field 1). + sort -u -k1,1n "$commits_tmp" | annotate + rm -f "$commits_tmp" + fi + + echo +done diff --git a/hack/helm_vars/nginx-ingress-services/values.yaml.gotmpl b/hack/helm_vars/nginx-ingress-services/values.yaml.gotmpl index 958ba24ac9b..e7d01c05688 100644 --- a/hack/helm_vars/nginx-ingress-services/values.yaml.gotmpl +++ b/hack/helm_vars/nginx-ingress-services/values.yaml.gotmpl @@ -15,7 +15,11 @@ tls: config: ingressClass: "nginx-{{ .Release.Namespace }}" + # Exercise the in-ingress CSP header path (off by default in the chart), so + # that changes to the 'configuration-snippet' annotation get test coverage. + renderCSPInIngress: true dns: + base: "{{ .Release.Namespace }}-integration.example.com" https: "nginz-https.{{ .Release.Namespace }}-integration.example.com" ssl: "nginz-ssl.{{ .Release.Namespace }}-integration.example.com" webapp: "webapp.{{ .Release.Namespace }}-integration.example.com" diff --git a/hack/helm_vars/wire-server/values.yaml.gotmpl b/hack/helm_vars/wire-server/values.yaml.gotmpl index b0309380b56..f05d42a98e4 100644 --- a/hack/helm_vars/wire-server/values.yaml.gotmpl +++ b/hack/helm_vars/wire-server/values.yaml.gotmpl @@ -400,7 +400,7 @@ galley: collabora: edition: COOL storage: - totalLimitBytes: "1000000000000" + totalLimitBytes: "-1" perUserQuotaBytes: "-1" allowedGlobalOperations: status: enabled @@ -420,17 +420,6 @@ galley: defaults: status: enabled lockStatus: unlocked - preventAdminlessGroups: - # FUTUREWORK: This feature should be unlocked in the main - # `values.yaml` file. It is just disabled & locked there due to open - # bugs. - defaults: - status: disabled - lockStatus: unlocked - config: - promotionStrategy: alphabetical - deletionTimeoutDuration: 7d - reminderTimeoutDurations: [2d, 4d, 6d] journal: endpoint: http://fake-aws-sqs:4568 queueName: integration-team-events.fifo diff --git a/integration/default.nix b/integration/default.nix index 8290943dee2..a1ec576d096 100644 --- a/integration/default.nix +++ b/integration/default.nix @@ -57,6 +57,7 @@ , optparse-applicative , process , proto-lens +, QuickCheck , ram , random , raw-strings-qq @@ -162,6 +163,7 @@ mkDerivation { optparse-applicative process proto-lens + QuickCheck ram random raw-strings-qq diff --git a/integration/integration.cabal b/integration/integration.cabal index d124256a118..8dd9466197c 100644 --- a/integration/integration.cabal +++ b/integration/integration.cabal @@ -181,6 +181,7 @@ library Test.Migration.ConversationCodes Test.Migration.DomainRegistration Test.Migration.TeamFeatures + Test.Migration.User Test.Migration.Util Test.MLS Test.MLS.Clients @@ -301,6 +302,7 @@ library , optparse-applicative , process , proto-lens + , QuickCheck ^>=2.15.0.1 , ram , random , raw-strings-qq diff --git a/integration/test/API/Brig.hs b/integration/test/API/Brig.hs index 7614567b84f..3b115345841 100644 --- a/integration/test/API/Brig.hs +++ b/integration/test/API/Brig.hs @@ -156,10 +156,13 @@ getSelfClients u = -- | https://staging-nginz-https.zinfra.io/v5/api/swagger-ui/#/default/delete_self deleteUser :: (HasCallStack, MakesValue user) => user -> App Response -deleteUser user = do +deleteUser user = deleteUserWithPassword user (Just defPassword) + +deleteUserWithPassword :: (HasCallStack, MakesValue user) => user -> Maybe String -> App Response +deleteUserWithPassword user mPassword = do req <- baseRequest user Brig Versioned "/self" submit "DELETE" $ - req & addJSONObject ["password" .= defPassword] + req & addJSONObject ["password" .= mPassword] -- | https://staging-nginz-https.zinfra.io/v5/api/swagger-ui/#/default/post_clients addClient :: @@ -824,6 +827,15 @@ addBot user providerId serviceId convId = do & zType "access" & addJSONObject ["provider" .= providerId, "service" .= serviceId] +rmBotSelf :: (HasCallStack, MakesValue domain) => domain -> String -> String -> App Response +rmBotSelf domain bid cid = do + req <- rawBaseRequest domain Brig Versioned $ joinHttpPath ["bot", "self"] + submit "DELETE" $ + req + & zType "bot" + & addHeader "Z-Bot" bid + & addHeader "Z-Conversation" cid + setProperty :: (MakesValue user, ToJSON val) => user -> String -> val -> App Response setProperty user propName val = do req <- baseRequest user Brig Versioned $ joinHttpPath ["properties", propName] @@ -978,6 +990,11 @@ getInvitationByCode user code = do req <- baseRequest user Brig Versioned $ joinHttpPath ["teams", "invitations", "info"] submit "GET" (req & addQueryParams [("code", code)]) +deleteTeamInvitation :: (HasCallStack, MakesValue user) => user -> String -> String -> App Response +deleteTeamInvitation user tid iid = do + req <- baseRequest user Brig Versioned (joinHttpPath ["teams", tid, "invitations", iid]) + submit "DELETE" req + passwordReset :: (HasCallStack, MakesValue domain) => domain -> String -> App Response passwordReset domain email = do req <- baseRequest domain Brig Versioned "password-reset" diff --git a/integration/test/API/Common.hs b/integration/test/API/Common.hs index cd4b4b348ab..9b720a3b9bd 100644 --- a/integration/test/API/Common.hs +++ b/integration/test/API/Common.hs @@ -25,6 +25,7 @@ import qualified Data.ByteString as BS import Data.Scientific (scientific) import qualified Data.Vector as Vector import System.Random (randomIO, randomRIO) +import Test.QuickCheck import Testlib.Prelude -- | please don't use special shell characters like '!' here. it makes writing shell lines @@ -33,8 +34,11 @@ defPassword :: String defPassword = "hunter2." randomEmail :: App String -randomEmail = do - u <- randomName +randomEmail = liftIO $ generate arbitraryEmail + +arbitraryEmail :: Gen String +arbitraryEmail = do + u <- arbitraryName pure $ u <> "@example.com" randomDomain :: App String @@ -52,23 +56,32 @@ randomExternalId = liftIO $ do pick = (chars !) <$> randomRIO (Array.bounds chars) randomName :: App String -randomName = liftIO $ do - n <- randomRIO (8, 15) +randomName = liftIO $ generate arbitraryName + +arbitraryName :: Gen String +arbitraryName = do + n <- chooseInt (8, 15) replicateM n pick where chars = mkArray $ ['A' .. 'Z'] <> ['a' .. 'z'] <> ['0' .. '9'] - pick = (chars !) <$> randomRIO (Array.bounds chars) + pick = (chars !) <$> chooseInt (Array.bounds chars) randomHandle :: App String -randomHandle = randomHandleWithRange 50 256 +randomHandle = liftIO $ generate arbitraryHandle randomHandleWithRange :: Int -> Int -> App String -randomHandleWithRange min' max' = liftIO $ do - n <- randomRIO (min', max') +randomHandleWithRange min' max' = liftIO $ generate (arbitraryHandleWithRange min' max') + +arbitraryHandle :: Gen String +arbitraryHandle = arbitraryHandleWithRange 50 60 + +arbitraryHandleWithRange :: Int -> Int -> Gen String +arbitraryHandleWithRange min' max' = do + n <- chooseInt (min', max') replicateM n pick where chars = mkArray $ ['a' .. 'z'] <> ['0' .. '9'] <> "_-." - pick = (chars !) <$> randomRIO (Array.bounds chars) + pick = (chars !) <$> chooseInt (Array.bounds chars) randomBytes :: Int -> App ByteString randomBytes n = liftIO $ BS.pack <$> replicateM n randomIO @@ -85,6 +98,14 @@ randomAlphaString n = liftIO $ replicateM n pick chars = mkArray $ ['A' .. 'Z'] <> ['a' .. 'z'] <> ['0' .. '9'] pick = (chars !) <$> randomRIO (Array.bounds chars) +randomPassword :: App String +randomPassword = liftIO $ generate arbitraryPassword + +arbitraryPassword :: Gen String +arbitraryPassword = do + n <- chooseInt (8, 1024) + replicateM n arbitraryPrintableChar + randomJSON :: App Value randomJSON = do let maxThings = 5 diff --git a/integration/test/Notifications.hs b/integration/test/Notifications.hs index 144b9902870..339922d117a 100644 --- a/integration/test/Notifications.hs +++ b/integration/test/Notifications.hs @@ -230,6 +230,9 @@ isConvDeleteNotif n = fieldEquals n "payload.0.type" "conversation.delete" ||~ fieldEquals n "payload.0.type" "conversation.system.delete" +isConvSystemDeleteNotif :: (HasCallStack, MakesValue a) => a -> App Bool +isConvSystemDeleteNotif n = fieldEquals n "payload.0.type" "conversation.system.delete" + isNotifTeamConvDelete :: (HasCallStack, MakesValue conv, MakesValue a) => conv -> a -> App Bool isNotifTeamConvDelete conv n = isNotifConv conv n diff --git a/integration/test/SetupHelpers.hs b/integration/test/SetupHelpers.hs index f4ed0509567..b5aed2c98a2 100644 --- a/integration/test/SetupHelpers.hs +++ b/integration/test/SetupHelpers.hs @@ -605,10 +605,14 @@ getCookieWithSamlLogin :: App (Maybe String, SAML.SignedAuthnResponse) getCookieWithSamlLogin mbZHost domain expectSuccess tid nameId mLabel (iid, (meta, privcreds)) = do let idpConfig = SAML.IdPConfig (SAML.IdPId (fromMaybe (error "invalid idp id") (UUID.fromString iid))) meta () - spmeta <- getSPMetadataWithZHost domain mbZHost tid - authnreq <- initiateSamlLoginWithZHostAndLabel domain mbZHost mLabel iid - let spMetaData = toSPMetaData spmeta.body - parsedAuthnReq = parseAuthnReqResp authnreq.body + spMetaData <- + getSPMetadataWithZHost domain mbZHost tid `bindResponse` \resp -> do + resp.status `shouldMatchInt` 200 + pure $ toSPMetaData resp.body + parsedAuthnReq <- + initiateSamlLoginWithZHostAndLabel domain mbZHost mLabel iid `bindResponse` \resp -> do + resp.status `shouldMatchInt` 200 + pure $ parseAuthnReqResp resp.body authnReqResp <- makeAuthnResponse nameId privcreds idpConfig spMetaData parsedAuthnReq mCookie <- finalizeSamlLoginWithZHost domain mbZHost tid authnReqResp `bindResponse` validateLoginResp pure (mCookie, authnReqResp) @@ -653,13 +657,14 @@ makeAuthnResponse nameId privcreds idpConfig spMetaData parsedAuthnReq = -- | extract an `AuthnRequest` from the html form in the http response from /sso/initiate-login parseAuthnReqResp :: + (HasCallStack) => ByteString -> SAML.AuthnRequest parseAuthnReqResp bs = reqBody where xml :: XML.Document xml = - fromRight (error "malformed html in response body") $ + fromRight (error $ "malformed html in response body: \n" <> show bs) $ XML.parseText XML.def (cs bs) reqBody :: SAML.AuthnRequest @@ -855,12 +860,12 @@ createNewIndex = do ExitFailure _ -> assertFailure $ prefix <> "failed to create index" ExitSuccess -> pure indexName -reindexUsers :: (HasCallStack) => BackendResource -> Int -> App () -reindexUsers ber pageSize = do +reindexUsers :: (HasCallStack) => BackendResource -> ServiceOverrides -> Int -> App () +reindexUsers ber serviceOverrides pageSize = do testName <- asks (fromMaybe "NoTest" . (.currentTestName)) let indexName = ber.berElasticsearchIndex let prefix = "[reindex-users:" <> indexName <> ":" <> testName <> "] " - getBrigConfig <- readAndUpdateConfig (defaultOverrides ber) ber Brig + getBrigConfig <- readAndUpdateConfig (defaultOverrides ber <> serviceOverrides) ber Brig brigConfig <- liftIO $ getBrigConfig esServer <- brigConfig %. "elasticsearch.url" & asString esCredentials <- brigConfig %. "elasticsearch.credentials" & asString diff --git a/integration/test/Test/AdminlessGroups.hs b/integration/test/Test/AdminlessGroups.hs index 139d5439357..094aa9ebbc3 100644 --- a/integration/test/Test/AdminlessGroups.hs +++ b/integration/test/Test/AdminlessGroups.hs @@ -19,6 +19,7 @@ module Test.AdminlessGroups where import API.Brig import API.Galley +import qualified API.Galley as Public import API.GalleyInternal hiding (getConversation) import qualified API.GalleyInternal as GalleyI import Control.Concurrent (threadDelay) @@ -26,6 +27,7 @@ import MLS.Util import Notifications import SetupHelpers hiding (deleteUser) import Testlib.Prelude +import Testlib.VersionedFed (FedDomain) testOnLastAdminLeaveReturnEligibleMembers :: (HasCallStack) => App () testOnLastAdminLeaveReturnEligibleMembers = do @@ -349,7 +351,7 @@ testAdminlessSetupDeletesWithOriginAndRemoteMembers = do conversationIds <- resp.json %. "qualified_conversations" & asList conversationIds `shouldContain` [convQid] - withWebSockets [remoteUser] $ \[wsRemoteUser] -> do + withWebSocket remoteUser $ \wsRemoteUser -> do setTeamFeatureConfigVersioned (ExplicitVersion 18) alice tid "preventAdminlessGroups" (mkAdminlessFeature "enabled" "1s" []) >>= assertSuccess deleteNotif <- awaitMatchFor 20 isConvDeleteNotif wsRemoteUser @@ -360,10 +362,9 @@ testAdminlessSetupDeletesWithOriginAndRemoteMembers = do conversationIds <- resp.json %. "qualified_conversations" & asList conversationIds `shouldNotContain` [convQid] -testAdminlessSetupSkipsDeletionForRemoteMembers :: (HasCallStack) => App () -testAdminlessSetupSkipsDeletionForRemoteMembers = do - -- Senderless deletion is skipped when remote members are present because - -- remote backends do not support the system delete event yet. +testAdminlessSetupDeletesWithSystemEventAndRemoteMembers :: (HasCallStack) => App () +testAdminlessSetupDeletesWithSystemEventAndRemoteMembers = do + -- The integration backends support the senderless system-delete event. (alice, tid, _) <- createTeam OwnDomain 1 remoteUser <- randomUser OtherDomain def connectTwoUsers alice remoteUser @@ -375,29 +376,66 @@ testAdminlessSetupSkipsDeletionForRemoteMembers = do traverse_ (uploadNewKeyPackage def) [alice1, remoteUser1] conv <- createTeamMLSConversation alice tid alice1 [remoteUser] + convQid <- objQidObject conv -- Create an adminless conversation while the feature is disabled. Enabling -- the feature later exercises the system-triggered setup path. removeMember alice conv alice >>= assertSuccess - configureAdminlessGroupsFeature OwnDomain tid "enabled" "1s" ["1s"] + withWebSocket remoteUser $ \wsRemoteUser -> do + configureAdminlessGroupsFeature OwnDomain tid "enabled" "1s" [] - -- The setup job must not schedule deletion or reminders for this - -- conversation because it contains a remote member. - liftIO $ threadDelay 2_000_000 - bindResponse (GalleyI.getConversation conv) $ \resp -> do - resp.status `shouldMatchInt` 200 + void $ awaitMatchFor 20 isConvSystemDeleteNotif wsRemoteUser + + eventually $ bindResponse (GalleyI.getConversation conv) $ \resp -> do + resp.status `shouldMatchInt` 404 + + eventually $ bindResponse (listConversationIds remoteUser def) $ \resp -> do + resp.status `shouldMatchInt` 200 + conversationIds <- resp.json %. "qualified_conversations" & asList + conversationIds `shouldNotContain` [convQid] + +testAdminlessSetupSkipsDeletionForUnsupportedRemote :: (HasCallStack) => FedDomain 2 -> App () +testAdminlessSetupSkipsDeletionForUnsupportedRemote fedDomain = do + (alice, tid, _) <- createTeam OwnDomain 1 + remoteUser <- randomUser fedDomain def + connectTwoUsers alice remoteUser + + configureAdminlessGroupsFeature OwnDomain tid "disabled" "1s" [] + + alice1 <- createMLSClient def alice + remoteUser1 <- createMLSClient def remoteUser + traverse_ (uploadNewKeyPackage def) [alice1, remoteUser1] + + conv <- createTeamMLSConversation alice tid alice1 [remoteUser] + + -- Create an adminless conversation while the feature is disabled. The + -- setup scan must skip it because the remote backend does not support the + -- senderless system-delete notification. + removeMember alice conv alice >>= assertSuccess + + withWebSocket remoteUser $ \wsRemoteUser -> do + configureAdminlessGroupsFeature OwnDomain tid "enabled" "1s" [] -testAdminlessSetupSkipsReminderForRemoteMembers :: (HasCallStack) => App () -testAdminlessSetupSkipsReminderForRemoteMembers = do - -- A remote member prevents senderless deletion. The remaining local app is - -- not eligible for promotion, but would receive a system reminder if one - -- were emitted. + -- Allow the setup scan and deletion worker to run, and assert that neither + -- senderless notification is emitted for the unsupported backend. + deleteResult <- awaitNMatchesResultFor 8 1 isConvSystemDeleteNotif wsRemoteUser + deleteResult.success `shouldMatch` False + reminderResult <- awaitNMatchesResultFor 8 1 isConvSystemAdminlessReminderNotif wsRemoteUser + reminderResult.success `shouldMatch` False + + bindResponse (GalleyI.getConversation conv) $ \resp -> do + resp.status `shouldMatchInt` 200 + +testAdminlessSetupSendsReminderWithRemoteMembers :: (HasCallStack) => App () +testAdminlessSetupSendsReminderWithRemoteMembers = do + -- The remaining local app is not eligible for promotion and receives the + -- senderless reminder even though the conversation has a remote member. (alice, tid, _) <- createTeam OwnDomain 1 remoteUser <- randomUser OtherDomain def connectTwoUsers alice remoteUser - configureAdminlessGroupsFeature OwnDomain tid "disabled" "5s" ["4s"] + configureAdminlessGroupsFeature OwnDomain tid "disabled" "10s" ["1s"] alice1 <- createMLSClient def alice remoteUser1 <- createMLSClient def remoteUser @@ -411,20 +449,63 @@ testAdminlessSetupSkipsReminderForRemoteMembers = do -- it through the internal path runs senderless setup cleanup. removeMember alice conv alice >>= assertSuccess - withWebSockets [app] $ \[wsApp] -> do - configureAdminlessGroupsFeature OwnDomain tid "enabled" "2s" ["1s"] + withWebSockets [app, remoteUser] $ \[wsApp, wsRemoteUser] -> do + configureAdminlessGroupsFeature OwnDomain tid "enabled" "10s" ["1s"] - reminderResult <- awaitNMatchesResultFor 5 1 isConvSystemAdminlessReminderNotif wsApp - reminderResult.success `shouldMatch` False + reminder <- awaitMatchFor 20 isConvSystemAdminlessReminderNotif wsApp + reminder %. "payload.0.qualified_conversation" `shouldMatch` objQidObject conv + + remoteReminder <- awaitMatchFor 20 isConvSystemAdminlessReminderNotif wsRemoteUser + remoteReminder %. "payload.0.qualified_conversation" `shouldMatch` objQidObject conv bindResponse (GalleyI.getConversation conv) $ \resp -> do resp.status `shouldMatchInt` 200 +testAdminlessSetupSendsReminderWithOriginUserAndRemoteMembers :: (HasCallStack) => App () +testAdminlessSetupSendsReminderWithOriginUserAndRemoteMembers = do + -- Enabling the feature through the public API preserves the origin user. + (alice, tid, _) <- createTeam OwnDomain 1 + remoteUser <- randomUser OtherDomain def + connectTwoUsers alice remoteUser + + configureAdminlessGroupsFeature OwnDomain tid "disabled" "10s" ["1s"] + + alice1 <- createMLSClient def alice + remoteUser1 <- createMLSClient def remoteUser + traverse_ (uploadNewKeyPackage def) [alice1, remoteUser1] + + conv <- createTeamMLSConversation alice tid alice1 [remoteUser] + let newApp = def {name = "adminless-federated-origin-reminder-app", description = "not eligible for promotion"} + (app, _) <- createAndAddAppMember alice tid alice1 conv newApp + + removeMember alice conv alice >>= assertSuccess + + withWebSockets [app, remoteUser] $ \[wsApp, wsRemoteUser] -> do + Public.setTeamFeatureConfig alice tid "preventAdminlessGroups" (mkAdminlessFeature "enabled" "10s" ["1s"]) + >>= assertSuccess + + reminder <- awaitMatchFor 20 isConvAdminlessReminderNotif wsApp + reminder %. "payload.0.qualified_conversation" `shouldMatch` objQidObject conv + reminder %. "payload.0.qualified_from" `shouldMatch` objQidObject alice + + remoteReminder <- awaitMatchFor 20 isConvAdminlessReminderNotif wsRemoteUser + remoteReminder %. "payload.0.qualified_conversation" `shouldMatch` objQidObject conv + remoteReminder %. "payload.0.qualified_from" `shouldMatch` objQidObject alice + + deleteNotif <- awaitMatchFor 20 isConvDeleteNotif wsApp + deleteNotif %. "payload.0.qualified_from" `shouldMatch` objQidObject alice + + remoteDeleteNotif <- awaitMatchFor 20 isConvDeleteNotif wsRemoteUser + remoteDeleteNotif %. "payload.0.qualified_from" `shouldMatch` objQidObject alice + + bindResponse (GalleyI.getConversation conv) $ \resp -> do + resp.status `shouldMatchInt` 404 + testAdminlessSetupAutopromotesWithRemoteMembers :: (HasCallStack) => App () testAdminlessSetupAutopromotesWithRemoteMembers = do -- Autopromotion is safe with remote members because the owning backend is - -- authoritative for roles, even though remote clients do not receive the - -- senderless system member-update event yet. + -- authoritative for roles. The remote member receives the senderless + -- system member-update event. (alice, tid, [bob]) <- createTeam OwnDomain 2 remoteUser <- randomUser OtherDomain def connectTwoUsers alice remoteUser @@ -442,12 +523,18 @@ testAdminlessSetupAutopromotesWithRemoteMembers = do -- the feature later promotes Bob through a system action. removeMember alice conv alice >>= assertSuccess - configureAdminlessGroupsFeature OwnDomain tid "enabled" "1s" [] + withWebSocket remoteUser $ \wsRemoteUser -> do + configureAdminlessGroupsFeature OwnDomain tid "enabled" "1s" [] - liftIO $ threadDelay 2_000_000 - bindResponse (getConversation bob conv) $ \resp -> do - resp.status `shouldMatchInt` 200 - resp.json %. "members.self.conversation_role" `shouldMatch` "wire_admin" + liftIO $ threadDelay 2_000_000 + bindResponse (getConversation bob conv) $ \resp -> do + resp.status `shouldMatchInt` 200 + resp.json %. "members.self.conversation_role" `shouldMatch` "wire_admin" + + memberUpdate <- awaitMatchFor 20 isConvSystemMemberUpdateNotif wsRemoteUser + memberUpdate %. "payload.0.qualified_conversation" `shouldMatch` objQidObject conv + memberUpdate %. "payload.0.data.qualified_target" `shouldMatch` objQidObject bob + memberUpdate %. "payload.0.data.conversation_role" `shouldMatch` "wire_admin" testAdminlessJobsCancelledOnFeatureDisable :: (HasCallStack) => App () testAdminlessJobsCancelledOnFeatureDisable = do diff --git a/integration/test/Test/Conversation.hs b/integration/test/Test/Conversation.hs index 681df7f59fa..e3a859df46f 100644 --- a/integration/test/Test/Conversation.hs +++ b/integration/test/Test/Conversation.hs @@ -582,6 +582,189 @@ testGetOneOnOneConvInStatusSentFromRemote domain = do resp <- getConversation d1User d2ConvId resp.status `shouldMatchInt` 200 +testReconcileStaleLocalMembershipsForDeletedRemoteConversation :: (HasCallStack) => App () +testReconcileStaleLocalMembershipsForDeletedRemoteConversation = do + owner <- randomUser OwnDomain def + alice <- randomUser OtherDomain def + charlie <- randomUser OtherDomain def + for_ [alice, charlie] $ connectTwoUsers owner + + conv <- registerMissingRemoteConversation owner [alice, charlie] + + eventually $ do + assertConversationMembership alice conv True + assertConversationMembership charlie conv True + + let isSystemDeleteFor conversation event = + fieldEquals event "payload.0.type" "conversation.system.delete" + &&~ isNotifConv conversation event + + -- A successful response from the owning backend that omits the conversation + -- proves that Alice's locally stored membership is stale. + withWebSockets [alice, charlie] $ \[wsAlice, wsCharlie] -> do + getConversation alice conv >>= assertLabel 404 "no-conversation" + void $ awaitMatch (isSystemDeleteFor conv) wsAlice + assertConversationMembership alice conv False + assertConversationMembership charlie conv True + + -- The bulk endpoint performs the same reconciliation for Charlie. + bindResponse (listConversations charlie [conv]) $ \resp -> do + resp.status `shouldMatchInt` 200 + resp.json %. "found" `shouldMatch` ([] :: [Value]) + resp.json %. "not_found" `shouldMatch` [conv] + resp.json %. "failed" `shouldMatch` ([] :: [Value]) + void $ awaitMatch (isSystemDeleteFor conv) wsCharlie + + assertConversationMembership alice conv False + assertConversationMembership charlie conv False + + -- Reconciliation is idempotent once the local membership has been removed. + getConversation alice conv >>= assertLabel 404 "no-conversation" + +-- | Fetching stale remote conversations from two different domains reconciles +-- both independently. A response for one domain must not remove memberships +-- belonging to another domain. +testReconcileStaleMembershipsMultipleDomains :: (HasCallStack) => App () +testReconcileStaleMembershipsMultipleDomains = do + resourcePool <- asks resourcePool + runCodensity (acquireResources 1 resourcePool) $ \[remoteBackend] -> + runCodensity (startDynamicBackend remoteBackend mempty) $ \_ -> do + alice <- randomUser OwnDomain def + ownerStatic <- randomUser OtherDomain def + ownerDynamic <- randomUser remoteBackend.berDomain def + connectTwoUsers ownerStatic alice + connectTwoUsers ownerDynamic alice + convStatic <- registerMissingRemoteConversation ownerStatic [alice] + convDynamic <- registerMissingRemoteConversation ownerDynamic [alice] + + eventually $ do + assertConversationMembership alice convStatic True + assertConversationMembership alice convDynamic True + + bindResponse (listConversations alice [convStatic, convDynamic]) $ \resp -> do + resp.status `shouldMatchInt` 200 + resp.json %. "found" `shouldMatch` ([] :: [Value]) + resp.json %. "failed" `shouldMatch` ([] :: [Value]) + notFound <- resp.json %. "not_found" & asList + for_ [convStatic, convDynamic] $ \conv -> + (notFound :: [Value]) `shouldContain` [conv] + + assertConversationMembership alice convStatic False + assertConversationMembership alice convDynamic False + +-- | Conversations the remote still returns are preserved; only omitted ones +-- are reconciled within the same request. +testReconcileOnlyMissingConversations :: (HasCallStack) => App () +testReconcileOnlyMissingConversations = do + alice <- randomUser OwnDomain def + owner <- randomUser OtherDomain def + connectTwoUsers owner alice + + alive <- + postConversation owner (defProteus {qualifiedUsers = [alice]}) + >>= getJSON 201 + aliveQid <- objQidObject alive + stale <- registerMissingRemoteConversation owner [alice] + + eventually $ do + assertConversationMembership alice aliveQid True + assertConversationMembership alice stale True + + bindResponse (listConversations alice [aliveQid, stale]) $ \resp -> do + resp.status `shouldMatchInt` 200 + resp.json %. "failed" `shouldMatch` ([] :: [Value]) + found <- resp.json %. "found" & asList + length (found :: [Value]) `shouldMatchInt` 1 + notFound <- resp.json %. "not_found" & asList + (notFound :: [Value]) `shouldContain` [stale] + + assertConversationMembership alice aliveQid True + assertConversationMembership alice stale False + +testPreserveRemoteMembershipOnFederationFailure :: (HasCallStack) => App () +testPreserveRemoteMembershipOnFederationFailure = do + resourcePool <- asks resourcePool + runCodensity (acquireResources 1 resourcePool) $ \[remoteBackend] -> do + (alice, convQid) <- runCodensity (startDynamicBackend remoteBackend mempty) $ \_ -> do + owner <- randomUser remoteBackend.berDomain def + alice <- randomUser OwnDomain def + connectTwoUsers owner alice + conv <- + postConversation owner (defProteus {qualifiedUsers = [alice]}) + >>= getJSON 201 + convQid <- objQidObject conv + eventually $ assertConversationMembership alice convQid True + pure (alice, convQid) + + bindResponse (listConversations alice [convQid]) $ \resp -> do + resp.status `shouldMatchInt` 200 + resp.json %. "failed" `shouldMatch` [convQid] + assertConversationMembership alice convQid True + +-- | This function only submits the on-conversation-created event +-- to the remote backend without actually having created a local conversation. +registerMissingRemoteConversation :: (HasCallStack) => Value -> [Value] -> App Value +registerMissingRemoteConversation owner members = do + originDomain <- objDomain owner + originUserId <- objId owner + convId <- randomId + targetDomain <- case members of + [] -> assertFailure "A remote conversation needs at least one local member" + firstMember : remainingMembers -> do + domain <- objDomain firstMember + for_ remainingMembers $ \remoteMember -> do + memberDomain <- objDomain remoteMember + memberDomain `shouldMatch` domain + pure domain + memberPayloads <- for members $ \remoteMember -> do + memberId <- objId remoteMember + memberQid <- objQidObject remoteMember + pure + $ object + [ "id" .= memberId, + "qualified_id" .= memberQid, + "status" .= (0 :: Int), + "conversation_role" .= ("wire_member" :: String) + ] + req <- + rawBaseRequest + originDomain + FederatorInternal + Unversioned + (joinHttpPath ["rpc", targetDomain, "galley", "on-conversation-created"]) + bindResponse + ( submit "POST" + $ req + & addHeader "Wire-Origin-Domain" originDomain + & addJSONObject + [ "time" .= ("2026-01-01T00:00:00.000Z" :: String), + "orig_user_id" .= originUserId, + "cnv_id" .= convId, + "cnv_type" .= (0 :: Int), + "cnv_access" .= ["invite" :: String, "code"], + "cnv_access_roles" .= ["team_member" :: String, "non_team_member"], + "cnv_name" .= Aeson.Null, + "non_creator_members" .= memberPayloads, + "message_timer" .= Aeson.Null, + "receipt_mode" .= Aeson.Null, + "protocol" .= object ["protocol" .= ("proteus" :: String)], + "group_conv_type" .= ("group_conversation" :: String), + "channel_add_permission" .= Aeson.Null, + "history" .= Aeson.Null + ] + ) + $ \resp -> resp.status `shouldMatchInt` 200 + pure $ object ["domain" .= originDomain, "id" .= convId] + +assertConversationMembership :: (HasCallStack) => Value -> Value -> Bool -> App () +assertConversationMembership user conv expected = + bindResponse (listConversationIds user def) $ \resp -> do + resp.status `shouldMatchInt` 200 + conversationIds <- resp.json %. "qualified_conversations" & asList + if expected + then conversationIds `shouldContain` [conv] + else conversationIds `shouldNotContain` [conv] + testAddingUserNonFullyConnectedFederation :: (HasCallStack) => StaticDomain -> App () testAddingUserNonFullyConnectedFederation domain = do let overrides = @@ -1029,8 +1212,13 @@ testOnUserDeletedConversations = do do -- Bob is not in the one-to-one conversation with Alice any more - conv <- getConversation alice ooConvId >>= getJSON 200 - shouldBeEmpty $ conv %. "members.others" + resp <- getConversation alice ooConvId + case resp.status of + 200 -> do + conv <- getJSON 200 resp + shouldBeEmpty $ conv %. "members.others" + 404 -> resp.json %. "label" `shouldMatch` ("no-conversation" :: String) + status -> assertFailure $ "Unexpected status while fetching one-to-one conversation: " <> show status do -- Bob is not in the main conversation any more mainConvAfter <- getConversation alice (mainConvBefore %. "qualified_id") >>= getJSON 200 diff --git a/integration/test/Test/FeatureFlags/CellsInternal.hs b/integration/test/Test/FeatureFlags/CellsInternal.hs index 573ba9c8809..0bc135c1c53 100644 --- a/integration/test/Test/FeatureFlags/CellsInternal.hs +++ b/integration/test/Test/FeatureFlags/CellsInternal.hs @@ -96,7 +96,7 @@ defConf = CellsInternalConfig { url = "https://cells-beta.wire.com", collabora = "COOL", - totalLimit = "1000000000000", + totalLimit = "-1", quota = "-1" } diff --git a/integration/test/Test/FeatureFlags/Util.hs b/integration/test/Test/FeatureFlags/Util.hs index 17a994de737..6b0ad2175aa 100644 --- a/integration/test/Test/FeatureFlags/Util.hs +++ b/integration/test/Test/FeatureFlags/Util.hs @@ -244,7 +244,7 @@ defAllFeatures = "collabora" .= object ["edition" .= "COOL"], "storage" .= object - [ "totalLimitBytes" .= "1000000000000", + [ "totalLimitBytes" .= "-1", "perUserQuotaBytes" .= "-1" ] ] diff --git a/integration/test/Test/MLS.hs b/integration/test/Test/MLS.hs index ca8dc088b64..d31754f561e 100644 --- a/integration/test/Test/MLS.hs +++ b/integration/test/Test/MLS.hs @@ -726,82 +726,19 @@ testStaleCommit = do resp.status `shouldMatchInt` 409 resp.json %. "label" `shouldMatch` "mls-stale-message" -testPropInvalidEpoch :: (HasCallStack) => App () -testPropInvalidEpoch = do - users@[_alice, bob, charlie, dee] <- createAndConnectUsers (replicate 4 OwnDomain) - [alice1, bob1, charlie1, dee1] <- traverse (createMLSClient def) users +testBareProposalRejected :: (HasCallStack) => App () +testBareProposalRejected = do + [alice, bob] <- createAndConnectUsers [OwnDomain, OwnDomain] + [alice1, bob1] <- traverse (createMLSClient def) [alice, bob] convId <- createNewGroup def alice1 - - -- Add bob -> epoch 1 - void $ uploadNewKeyPackage def bob1 - gsBackup <- getClientGroupState alice1 - void $ createAddCommit alice1 convId [bob] >>= sendAndConsumeCommitBundle - gsBackup2 <- getClientGroupState alice1 - - -- try to send a proposal from an old epoch (0) - do - setClientGroupState alice1 gsBackup - void $ uploadNewKeyPackage def dee1 - [prop] <- createAddProposals convId alice1 [dee] - bindResponse (postMLSMessage alice1 prop.message) $ \resp -> do - resp.status `shouldMatchInt` 409 - resp.json %. "label" `shouldMatch` "mls-stale-message" - - -- try to send a proposal from a newer epoch (2) - do - void $ uploadNewKeyPackage def dee1 - void $ uploadNewKeyPackage def charlie1 - setClientGroupState alice1 gsBackup2 - void $ createAddCommit alice1 convId [charlie] -- --> epoch 2 - [prop] <- createAddProposals convId alice1 [dee] - bindResponse (postMLSMessage alice1 prop.message) $ \resp -> do - resp.status `shouldMatchInt` 409 - resp.json %. "label" `shouldMatch` "mls-stale-message" - -- remove charlie from users expected to get a welcome message - modifyMLSState $ \mls -> mls {convs = Map.adjust (\conv -> conv {newMembers = mempty}) convId mls.convs} - - -- alice send a well-formed proposal and commits it - void $ uploadNewKeyPackage def dee1 - setClientGroupState alice1 gsBackup2 - createAddProposals convId alice1 [dee] >>= traverse_ sendAndConsumeMessage - void $ createPendingProposalCommit convId alice1 >>= sendAndConsumeCommitBundle - ---- | This test submits a ReInit proposal, which is currently ignored by the --- backend, in order to check that unsupported proposal types are accepted. -testPropUnsupported :: (HasCallStack) => App () -testPropUnsupported = do - users@[_alice, bob] <- createAndConnectUsers (replicate 2 OwnDomain) - [alice1, bob1] <- traverse (createMLSClient def) users void $ uploadNewKeyPackage def bob1 - convId <- createNewGroup def alice1 void $ createAddCommit alice1 convId [bob] >>= sendAndConsumeCommitBundle - mp <- createReInitProposal convId alice1 - - -- we cannot consume this message, because the membership tag is fake - void $ postMLSMessage mp.sender mp.message >>= getJSON 201 - -testAddUserBareProposalCommit :: (HasCallStack) => App () -testAddUserBareProposalCommit = do - [alice, bob] <- createAndConnectUsers (replicate 2 OwnDomain) - [alice1, bob1] <- traverse (createMLSClient def) [alice, bob] - convId <- createNewGroup def alice1 void $ uploadNewKeyPackage def bob1 - void $ createAddCommit alice1 convId [] >>= sendAndConsumeCommitBundle - - createAddProposals convId alice1 [bob] - >>= traverse_ sendAndConsumeMessage - commit <- createPendingProposalCommit convId alice1 - void $ assertJust "Expected welcome" commit.welcome - void $ sendAndConsumeCommitBundle commit - - -- check that bob can now see the conversation - convs <- getAllConvs bob - convIds <- traverse objConvId convs - void - $ assertBool - "Users added to an MLS group should find it when listing conversations" - (convId `elem` convIds) + [proposal] <- createAddProposals convId alice1 [bob] + postMLSMessage alice1 proposal.message >>= flip withResponse \resp -> do + resp.status `shouldMatchInt` 422 + resp.json %. "label" `shouldMatch` "mls-unsupported-message" testShadowConversation :: (HasCallStack) => App () testShadowConversation = do @@ -841,43 +778,76 @@ testShadowConversationDenied = do bindResponse (postConversation bob1 (defMLS {parent = Just convId.id_})) $ \resp -> do resp.status `shouldMatchInt` 403 -testPropExistingConv :: (HasCallStack) => App () -testPropExistingConv = do - [alice, bob] <- createAndConnectUsers (replicate 2 OwnDomain) - [alice1, bob1] <- traverse (createMLSClient def) [alice, bob] - void $ uploadNewKeyPackage def bob1 - convId <- createNewGroup def alice1 - void $ createAddCommit alice1 convId [] >>= sendAndConsumeCommitBundle - res <- createAddProposals convId alice1 [bob] >>= traverse sendAndConsumeMessage >>= assertOne - shouldBeEmpty (res %. "events") - -- @SF.Separation @TSFI.RESTfulAPI @S2 -- --- This test verifies that the server rejects any commit that does not --- reference all pending proposals in an MLS group. +-- This test verifies that rejected bare proposals do not create pending +-- backend proposals, and that the corresponding membership change succeeds +-- when submitted as a commit. testCommitNotReferencingAllProposals :: (HasCallStack) => App () testCommitNotReferencingAllProposals = do - users@[_alice, bob, charlie] <- createAndConnectUsers (replicate 3 OwnDomain) - - [alice1, bob1, charlie1] <- traverse (createMLSClient def) users + [alice, bob] <- createAndConnectUsers (replicate 2 OwnDomain) + [alice1, bob1] <- traverse (createMLSClient def) [alice, bob] convId <- createNewGroup def alice1 - traverse_ (uploadNewKeyPackage def) [bob1, charlie1] - void $ createAddCommit alice1 convId [] >>= sendAndConsumeCommitBundle + void $ uploadNewKeyPackage def bob1 + void $ createAddCommit alice1 convId [bob] >>= sendAndConsumeCommitBundle - gsBackup <- getClientGroupState alice1 + groupStateBeforeRemoval <- getClientGroupState alice1 + let isRemoveProposal e = do + isNewMLSMessageNotif e &&~ do + msgData <- e %. "payload.0.data" & asByteString + msg <- showMessage def alice1 msgData + fieldEquals msg "message.content.body.Proposal.Remove.removed" (1 :: Int) - -- create proposals for bob and charlie - createAddProposals convId alice1 [bob, charlie] - >>= traverse_ sendAndConsumeMessage + withWebSocket alice1 $ \ws -> do + deleteUser bob + void $ consumeMessageWithPredicate isRemoveProposal convId def alice1 Nothing ws - -- now create a commit referencing only the first proposal - setClientGroupState alice1 gsBackup - commit <- createPendingProposalCommit convId alice1 + groupStateWithRemovalProposal <- getClientGroupState alice1 + bobUser <- asString $ bob %. "id" + -- Keep the integration-test conversation model in sync with the backend + -- deletion. The backend has removed Bob from the Wire conversation and + -- created a backend remove proposal, but the harness's 'mls.convs' map is + -- not updated when Alice consumes that proposal. The client MLS group state + -- still contains Bob's leaf until the commit is applied, so this update is + -- separate from the 'setClientGroupState' calls below. + modifyMLSState $ \mls -> + mls + { convs = + Map.adjust + ( \conv -> + conv + { members = Set.filter (\m -> m.user /= bobUser) conv.members, + memberUsers = Set.filter (/= bob1.qualifiedUserId) conv.memberUsers + } + ) + convId + mls.convs + } - -- send commit and expect and error - bindResponse (postMLSCommitBundle alice1 (mkBundle commit)) $ \resp -> do + -- Restore the state before the backend proposal was consumed and submit a + -- commit that does not reference it. + setClientGroupState alice1 groupStateBeforeRemoval + alice2 <- createMLSClient def alice + void $ uploadNewKeyPackage def alice2 + commitWithoutRemoval <- createAddCommit alice1 convId [alice] + bindResponse (postMLSCommitBundle alice1 (mkBundle commitWithoutRemoval)) $ \resp -> do resp.status `shouldMatchInt` 400 resp.json %. "label" `shouldMatch` "mls-commit-missing-references" + -- 'createAddCommit' updates the harness optimistically with a pending + -- welcome recipient, even though the backend rejects this commit because it + -- omits the pending remove proposal. Clear that bookkeeping before consuming + -- the valid removal commit; otherwise the harness would wait for a welcome + -- for a client that was never added. + modifyMLSState $ \mls -> + mls + { convs = + Map.adjust (\conv -> conv {newMembers = mempty}) convId mls.convs + } + + -- Restore the state containing the backend proposal and submit the commit + -- generated from it. + setClientGroupState alice1 groupStateWithRemovalProposal + void $ createPendingProposalCommit convId alice1 >>= sendAndConsumeCommitBundle -- @END diff --git a/integration/test/Test/Migration/Conversation.hs b/integration/test/Test/Migration/Conversation.hs index 88f78e059ea..1e712ba9094 100644 --- a/integration/test/Test/Migration/Conversation.hs +++ b/integration/test/Test/Migration/Conversation.hs @@ -99,6 +99,7 @@ testMigrationToPostgresMLS = do runPhase 5 where n = 1 + createTestConvs :: (HasCallStack) => ClientIdentity -> String -> ClientIdentity -> ClientIdentity -> [ClientIdentity] -> App TestConvList createTestConvs creatorC tid melC markC othersC = do unmodifiedConvs <- replicateM n $ do diff --git a/integration/test/Test/Migration/User.hs b/integration/test/Test/Migration/User.hs new file mode 100644 index 00000000000..573b3f46e7c --- /dev/null +++ b/integration/test/Test/Migration/User.hs @@ -0,0 +1,956 @@ +{-# LANGUAGE ApplicativeDo #-} +{-# OPTIONS_GHC -Wno-ambiguous-fields #-} + +-- | The migration has these phases. +-- 1. Write to cassandra (before any migration activity) +-- 2. Galley is prepared for migrations (new things created in PG, old things are in Cassandra) +-- 3. Backgound worker starts migration +-- 4. Background worker finishes migration, galley is still configured to think migration is on going +-- 5. Background worker is configured to not do anything, galley is configured to only use PG +-- +-- The comments and variable names call these phases by number i.e. Phase1, Phase2, and so on. +-- +-- The tests are from the perspective of mel, a user on the dynamic backend, +-- called backendM (migrating backend). There are also users called mark and mia +-- on this backend. +module Test.Migration.User where + +import API.Brig +import qualified API.BrigInternal as I +import API.Common +import API.Galley +import qualified API.GalleyInternal as I +import API.Spar +import Control.Applicative +import Control.Monad.Codensity +import Control.Monad.Reader +import qualified Data.Aeson.KeyMap as KM +import qualified Data.Aeson.KeyMap as KeyMap +import Data.IntMap (IntMap) +import qualified Data.IntMap as IntMap +import qualified Data.IntSet as IntSet +import qualified Data.Map as Map +import Data.String.Conversions +import Data.Text (Text) +import qualified Data.Text as Text +import Data.Tuple.Extra +import Data.UUID (UUID) +import qualified Data.UUID as UUID +import qualified Data.Vector as Vector +import Database.CQL.IO +import GHC.Stack +import Notifications +import SetupHelpers hiding (deleteUser) +import Test.Bot (mkBotService) +import Test.Migration.Util +import Test.QuickCheck +import Test.Search +import Testlib.MockIntegrationService (MockServerSettings (..), withMockServer) +import Testlib.Prelude +import Testlib.ResourcePool +import UnliftIO + +testUserMigrationToPostgres :: App () +testUserMigrationToPostgres = withMockServer botServiceSettings mkBotService $ \(botHost, botPort) _botChan -> do + resourcePool <- asks (.resourcePool) + + runCodensity (acquireResources 1 resourcePool) $ \[migratingBackend] -> do + let domainM = migratingBackend.berDomain + (mel, pid, sid, seedUsers) <- runCodensity (startDynamicBackend migratingBackend phase1Overrides) $ \_ -> do + -- mel exists to connect with all the personal users, so we can wait for a + -- notification for their deletion + mel <- randomUser domainM def + + pid <- setupProvider domainM def {newProviderPassword = Just defPassword} %. "id" & asString + service <- + newService domainM pid + $ def + { newServiceUrl = "https://" <> botHost <> ":" <> show botPort, + newServiceKey = cs botServiceSettings.publicKey + } + sid <- service %. "id" & asString + updateServiceConn domainM pid sid (object ["password" .= defPassword, "enabled" .= True]) >>= assertSuccess + + seedUsers <- seedTestUsers domainM mel pid sid + pure (mel, pid, sid, seedUsers) + + newUsersRef <- newIORef mempty + updatedUsersRef <- newIORef mempty + updates <- fmap IntMap.fromList . for [1 .. 5] $ \phase -> do + (phase,) <$> liftIO (generate (arbitraryPhaseUpdates nUpdates)) + + addUsersToFailureContext [("mel", mel)] + $ addJSONToFailureContext "updates" updates + $ addJSONToFailureContext "seed users" seedUsers do + let runPhase :: (HasCallStack) => Int -> App () + runPhase phase = do + runCodensity (startDynamicBackend migratingBackend (phaseOverrides IntMap.! phase)) $ \_ -> do + let toBeUpdated = seedUsers.updates IntMap.! phase + phaseUpdates = updates IntMap.! phase + + updatedScimUsersWithRichInfo <- updateScimUsers domainM toBeUpdated.scimUsersWithRichInfo phaseUpdates.scimUsersWithRichInfo + updatedScimUsersWithoutRichInfo <- updateScimUsers domainM toBeUpdated.scimUsersWithoutRichInfo phaseUpdates.scimUsersWithoutRichInfo + updatedPendingScimUsers <- updatePendingScimUsers domainM toBeUpdated.pendingScimUsers phaseUpdates.pendingScimUsers + updatedSsoUsers <- checkUpdateUser toBeUpdated.ssoUsers.users phaseUpdates.ssoUsers + updatedPasswordTeamUsers <- checkUpdateUser toBeUpdated.passwordTeamUsers.users phaseUpdates.passwordTeamUsers + updatedPersonalUsersWithoutHandle <- checkUpdateUser toBeUpdated.personalUsersWithoutHandle phaseUpdates.personalUsersWithoutHandle + updatedPersonalUsersWithHandle <- checkUpdateUser toBeUpdated.personalUsersWithHandle phaseUpdates.personalUsersWithHandle + let updatedUsers = + TestUserList + { scimUsersWithRichInfo = updatedScimUsersWithRichInfo, + scimUsersWithoutRichInfo = updatedScimUsersWithoutRichInfo, + pendingScimUsers = updatedPendingScimUsers, + ssoUsers = toBeUpdated.ssoUsers {users = updatedSsoUsers} :: TestTeamUsers, + passwordTeamUsers = toBeUpdated.passwordTeamUsers {users = updatedPasswordTeamUsers} :: TestTeamUsers, + personalUsersWithoutHandle = updatedPersonalUsersWithoutHandle, + personalUsersWithHandle = updatedPersonalUsersWithHandle, + -- Bots don't have any updates + botsInTeamConvs = toBeUpdated.botsInTeamConvs, + botsInPersonalConvs = toBeUpdated.botsInPersonalConvs + } + + newUsers <- createTestUsers domainM mel pid sid nNew + modifyIORef newUsersRef (IntMap.insert phase newUsers) + modifyIORef updatedUsersRef (IntMap.insert phase updatedUsers) + + let toBeDeleted = seedUsers.deletes IntMap.! phase + + deleteScimUsers domainM False toBeDeleted.scimUsersWithRichInfo + deleteScimUsers domainM False toBeDeleted.scimUsersWithoutRichInfo + deleteScimUsers domainM True toBeDeleted.pendingScimUsers + deleteTeamUsers toBeDeleted.ssoUsers + deleteTeamUsers toBeDeleted.passwordTeamUsers + deletePersonalUsers mel toBeDeleted.personalUsersWithoutHandle + deletePersonalUsers mel toBeDeleted.personalUsersWithHandle + deleteBotsTeam toBeDeleted.botsInTeamConvs pid sid + deleteBotConvs mel toBeDeleted.botsInPersonalConvs + + checkAllDeletionsWorked domainM mel seedUsers.deletes phase + checkUnaffectedUsers domainM seedUsers.deletes seedUsers.updates phase + updatedSoFar <- readIORef updatedUsersRef + newSoFar <- readIORef newUsersRef + addJSONToFailureContext "newSoFar" newSoFar + $ checkNewAndUpdatedUsers domainM updatedSoFar newSoFar + + when (phase == 3) $ do + waitForMigration domainM userMigrationFinishedCounterName + runPhase 1 + runPhase 2 + runPhase 3 + runPhase 4 + runPhase 5 + where + parallelism = 64 + + -- Number of users of each type + nUpdates = 5 + nDeletes = 1 + nNew = 1 + + botServiceSettings = def + + seedTestUsers :: (HasCallStack, MakesValue mel) => String -> mel -> String -> String -> App TestUsersByOperations + seedTestUsers domain mel pid sid = + fmap mconcat . for [(1 :: Int) .. 5] $ \phase -> do + updates <- IntMap.singleton phase <$> createTestUsers domain mel pid sid nUpdates + deletes <- IntMap.singleton phase <$> createTestUsers domain mel pid sid nDeletes + pure TestUsersByOperations {..} + + tombstone :: String -> String -> Maybe String -> Value + tombstone domain uid mTid = + object + $ [ "accent_id" .= (0 :: Int), + "assets" .= (), + "deleted" .= True, + "id" .= uid, + "legalhold_status" .= "no_consent", + "name" .= "default", + "picture" .= (), + "qualified_id" .= object ["domain" .= domain, "id" .= uid], + "searchable" .= True, + "supported_protocols" .= ["proteus"], + "type" .= "regular" + ] + <> (maybe [] (\tid -> ["team" .= tid]) mTid) + + scimUserIdsWithGetter :: (HasCallStack) => IntMap TestUserList -> [(String, String)] + scimUserIdsWithGetter relevantSeedUsers = + foldMap IntMap.elems . for relevantSeedUsers $ \usersInPhase -> do + map (usersInPhase.scimUsersWithRichInfo.token,) (Map.keys usersInPhase.scimUsersWithRichInfo.users) + <> map (usersInPhase.scimUsersWithoutRichInfo.token,) (Map.keys usersInPhase.scimUsersWithoutRichInfo.users) + <> map (usersInPhase.pendingScimUsers.token,) (Map.keys usersInPhase.pendingScimUsers.users) + + nonScimUserIds :: (HasCallStack) => Value -> IntMap TestUserList -> [(Value, Value)] + nonScimUserIds mel relevantSeedUsers = foldMap IntMap.elems . for relevantSeedUsers $ \usersInPhase -> do + map (usersInPhase.scimUsersWithRichInfo.owner,) (thd3 <$> Map.elems usersInPhase.scimUsersWithRichInfo.users) + <> map (usersInPhase.scimUsersWithoutRichInfo.owner,) (thd3 <$> Map.elems usersInPhase.scimUsersWithoutRichInfo.users) + <> map (usersInPhase.passwordTeamUsers.owner,) (fst <$> Map.elems usersInPhase.passwordTeamUsers.users) + <> map (mel,) (fst <$> Map.elems usersInPhase.personalUsersWithHandle) + <> map (mel,) (fst <$> Map.elems usersInPhase.personalUsersWithoutHandle) + + checkAllDeletionsWorked :: (HasCallStack) => String -> Value -> IntMap TestUserList -> Int -> App () + checkAllDeletionsWorked domain mel seedUsers phase = do + let deletedSoFar = IntMap.restrictKeys seedUsers (IntSet.fromList $ [1 .. phase]) + pooledForConcurrentlyN_ parallelism (scimUserIdsWithGetter deletedSoFar) $ \(token, uid) -> + getScimUser domain token uid >>= assertStatus 404 + + pooledForConcurrentlyN_ parallelism (nonScimUserIds mel deletedSoFar) $ \(getter, user) -> do + uid <- user %. "qualified_id.id" & asString + mTid <- lookupField user "team" & asStringM + getUser getter (object ["domain" .= domain, "id" .= uid]) `bindResponse` \resp -> do + resp.status `shouldMatchInt` 200 + resp.json `shouldMatch` tombstone domain uid mTid + + let bots = + concatMap + ( \testUsers -> + map fst (Map.elems testUsers.botsInTeamConvs.users) + <> map fst (Map.elems testUsers.botsInPersonalConvs) + ) + (IntMap.elems deletedSoFar) + pooledForConcurrentlyN_ parallelism bots $ \botUser -> do + botTombstone <- setField "status" "deleted" =<< setField "deleted" True botUser + getSelf botUser `bindResponse` \resp -> do + resp.status `shouldMatchInt` 200 + resp.json `shouldMatch` botTombstone + + checkUnaffectedUsers :: (HasCallStack) => String -> IntMap TestUserList -> IntMap TestUserList -> Int -> App () + checkUnaffectedUsers domain seedUsersToBeUpdated seedUsersToBeDeleted phase = do + let upcomingPhases = IntSet.fromList [(phase + 1) .. 5] + usersNotYetDeleted = IntMap.restrictKeys seedUsersToBeDeleted upcomingPhases + usersNotYetUpdated = IntMap.restrictKeys seedUsersToBeUpdated upcomingPhases + existingUserLists = IntMap.elems usersNotYetDeleted <> IntMap.elems usersNotYetUpdated + existingScimUsers = concatMap extractScimUsers existingUserLists + existingUsers = concatMap extractTestUsers existingUserLists + + checkScimUsers domain existingScimUsers + checkUsers existingUsers + + checkNewAndUpdatedUsers :: (HasCallStack) => String -> IntMap TestUserList -> IntMap TestUserList -> App () + checkNewAndUpdatedUsers domain newUsers updatedUsers = do + let scimUsers = + concatMap extractScimUsers newUsers + <> concatMap extractScimUsers updatedUsers + users = + concatMap extractTestUsers newUsers + <> concatMap extractTestUsers updatedUsers + checkScimUsers domain scimUsers + checkUsers users + + checkScimUsers :: (HasCallStack) => String -> [(String, Value)] -> App () + checkScimUsers domain tokensAndUsers = do + pooledForConcurrentlyN_ parallelism tokensAndUsers $ \(token, scimUser) -> + addJSONToFailureContext "scimUser" scimUser $ do + uid <- scimUser %. "id" & asString + getScimUser domain token uid `bindResponse` \resp -> do + resp.status `shouldMatchInt` 200 + resp.json `shouldMatch` scimUser + + checkUsers :: (HasCallStack) => [Value] -> App () + checkUsers users = + pooledForConcurrentlyN_ parallelism users $ \user -> + addJSONToFailureContext "user" user $ do + getSelf user `bindResponse` \resp -> do + resp.status `shouldMatchInt` 200 + resp.json `shouldMatch` user + + extractScimUsers :: TestUserList -> [(String, Value)] + extractScimUsers testUserList = + map (testUserList.scimUsersWithRichInfo.token,) (fst3 <$> Map.elems testUserList.scimUsersWithRichInfo.users) + <> map (testUserList.scimUsersWithoutRichInfo.token,) (fst3 <$> Map.elems testUserList.scimUsersWithoutRichInfo.users) + <> map (testUserList.pendingScimUsers.token,) (fst3 <$> Map.elems testUserList.pendingScimUsers.users) + + extractTestUsers :: TestUserList -> [Value] + extractTestUsers testUserList = + map thd3 (Map.elems testUserList.scimUsersWithRichInfo.users) + <> map thd3 (Map.elems testUserList.scimUsersWithoutRichInfo.users) + <> map fst (Map.elems testUserList.ssoUsers.users) + <> map fst (Map.elems testUserList.passwordTeamUsers.users) + <> map fst (Map.elems testUserList.personalUsersWithHandle) + <> map fst (Map.elems testUserList.personalUsersWithoutHandle) + <> extractBots testUserList + + extractBots :: TestUserList -> [Value] + extractBots testUserList = + map fst (Map.elems testUserList.botsInTeamConvs.users) + <> map fst (Map.elems testUserList.botsInPersonalConvs) + + createTestUsers :: (HasCallStack, MakesValue mel) => String -> mel -> String -> String -> Int -> App TestUserList + createTestUsers domain mel pid sid n = runConcurrently $ do + scimUsersWithRichInfo <- Concurrently $ createScimUsers domain n True True + scimUsersWithoutRichInfo <- Concurrently $ createScimUsers domain n False True + pendingScimUsers <- Concurrently $ createScimUsers domain n False False + ssoUsers <- Concurrently $ createSsoUsers domain n + passwordTeamUsers <- Concurrently $ createPasswordTeamUsers domain n + personalUsersWithoutHandle <- Concurrently $ createPersonalUsers domain mel n False + personalUsersWithHandle <- Concurrently $ createPersonalUsers domain mel n True + botsInTeamConvs <- Concurrently $ createTeamBots domain pid sid n + botsInPersonalConvs <- Concurrently $ createConvsAndAddBot domain mel Nothing pid sid n + pure TestUserList {..} + + getUnqualifiedUser :: String -> String -> App (Map String Value) + getUnqualifiedUser domain uid = do + let quid = object ["domain" .= domain, "id" .= uid] + Map.singleton uid <$> (getSelf quid >>= getJSON 200) + + createScimUsers :: (HasCallStack) => String -> Int -> Bool -> Bool -> App TestScimUsers + createScimUsers domain n shouldCreateRichInfo shouldAcceptInvite = do + (owner, tid, _) <- createTeam domain 1 + tok <- createScimToken owner def >>= \resp -> resp.json %. "token" >>= asString + users <- fmap Map.unions . pooledReplicateConcurrentlyN 16 n $ do + newScimUser0 <- randomScimUser + newScimUser <- + if shouldCreateRichInfo + then do + richInfoKey <- randomAlphaString 10 + richInfoValue <- randomString 10 + modifyObject (KeyMap.insert (fromString "urn:ietf:params:scim:schemas:extension:wire:1.0:User") (object [richInfoKey .= richInfoValue])) + =<< setField "schemas" ["urn:ietf:params:scim:schemas:core:2.0:User", "urn:ietf:params:scim:schemas:extension:wire:1.0:User"] newScimUser0 + else pure newScimUser0 + email <- asString $ newScimUser %. "emails.0.value" + inactiveScimUser <- createScimUser domain tok newScimUser >>= getJSON 201 + uid <- inactiveScimUser %. "id" & asString + (scimUser, userOrInv) <- + if shouldAcceptInvite + then do + registerInvitedUser domain tid email + scimUser <- getScimUser owner tok uid >>= getJSON 200 + (scimUser,) <$> getUnqualifiedUser domain uid + else fmap (inactiveScimUser,) . fmap (Map.singleton uid) . getJSON 200 =<< I.getInvitationByEmail domain email + pure $ (scimUser,defPassword,) <$> userOrInv + pure $ TestScimUsers owner tok users + + deleteScimUsers :: (HasCallStack) => String -> Bool -> TestScimUsers -> App () + deleteScimUsers domain arePendingUsers testScimUsers = do + withWebSocket testScimUsers.owner $ \wsOwner -> do + pooledForConcurrentlyN_ parallelism testScimUsers.users $ \(scimUser, _, _) -> do + uid <- scimUser %. "id" & asString + deleteScimUser domain testScimUsers.token uid >>= assertSuccess + getScimUser domain testScimUsers.token uid >>= assertStatus 404 + + unless arePendingUsers $ do + void $ awaitNMatches (Map.size testScimUsers.users) isTeamMemberLeaveNotif wsOwner + + updatePendingScimUserAndCheck :: (HasCallStack) => String -> String -> (Value, String, Value) -> UserUpdate -> App (Value, String, Value) + updatePendingScimUserAndCheck domain token (scimUser, pw, inv) update = do + addJSONToFailureContext "update" update . addJSONToFailureContext "scimUser" scimUser $ do + uid <- scimUser %. "id" & asString + updatedScimUser <- case update of + UpdatePassword _ -> do + pure scimUser + _ -> do + let updateScimRecord = case update of + UpdateName newName -> setField "displayName" newName + UpdateEmail newEmail -> setField "emails" (Array (Vector.singleton (object ["value" .= newEmail]))) + UpdateHandle newHandle -> setField "userName" newHandle + updateScimReq <- setField "active" True =<< updateScimRecord scimUser + updateScimUser domain token uid updateScimReq `bindResponse` \resp -> do + resp.status `shouldMatchInt` 200 + case update of + UpdateName newName -> resp.json %. "displayName" `shouldMatch` newName + UpdateEmail newEmail -> resp.json %. "emails.0.value" `shouldMatch` newEmail + UpdateHandle newHandle -> resp.json %. "userName" `shouldMatch` newHandle + assertJust "expected a updated scim user" resp.json + (updatedUserOrInv, newPassword) <- do + case update of + UpdatePassword newPassword -> pure (inv, newPassword) + _ -> + -- Changing email of a pending user doesn't generate a new + -- invitation, perhaps this is a bug? + -- Changing other things ofc doesn't generate a new invitation. + pure (inv, pw) + pure (updatedScimUser, newPassword, updatedUserOrInv) + + updateScimUserAndCheck :: (HasCallStack) => String -> String -> (Value, String, Value) -> UserUpdate -> App (Value, String, Value) + updateScimUserAndCheck domain token (scimUser, pw, user) update = do + uid <- scimUser %. "id" & asString + updatedScimUser <- case update of + UpdatePassword newPassword -> do + putPassword user pw newPassword >>= assertSuccess + pure scimUser + _ -> do + updateScimReq <- case update of + UpdateName newName -> setField "displayName" newName scimUser + UpdateEmail newEmail -> setField "emails" (Array (Vector.singleton (object ["value" .= newEmail]))) scimUser + UpdateHandle newHandle -> setField "userName" newHandle scimUser + updateScimUser domain token uid updateScimReq `bindResponse` \resp -> do + resp.status `shouldMatchInt` 200 + case update of + UpdateName newName -> resp.json %. "displayName" `shouldMatch` newName + UpdateEmail newEmail -> resp.json %. "emails.0.value" `shouldMatch` newEmail + UpdateHandle newHandle -> resp.json %. "userName" `shouldMatch` newHandle + assertJust "expected a updated scim user" resp.json + (updatedUserOrInv, newPassword) <- case update of + UpdatePassword newPassword -> do + email <- scimUser %. "emails.0.value" & asString + login domain email newPassword >>= assertSuccess + pure (user, newPassword) + UpdateEmail newEmail -> do + activateEmail domain newEmail + getSelf user `bindResponse` \resp -> do + resp.status `shouldMatchInt` 200 + resp.json %. "email" `shouldMatch` newEmail + (,pw) <$> assertJust "expected user data" resp.json + _ -> do + getSelf user `bindResponse` \resp -> do + resp.status `shouldMatchInt` 200 + case update of + UpdateName newName -> resp.json %. "name" `shouldMatch` newName + UpdateHandle newHandle -> resp.json %. "handle" `shouldMatch` newHandle + (,pw) <$> assertJust "expected user data" resp.json + pure (updatedScimUser, newPassword, updatedUserOrInv) + + updateScimUsers :: (HasCallStack) => String -> TestScimUsers -> [UserUpdate] -> App TestScimUsers + updateScimUsers domain testScimUsers updates = do + let usersWithUpdates = (zip (Map.elems testScimUsers.users) updates) + updatedUsers <- fmap Map.unions . pooledForConcurrentlyN parallelism usersWithUpdates $ \((scimUser, pw, user), update) -> do + uid <- scimUser %. "id" & asString + Map.singleton uid <$> updateScimUserAndCheck domain testScimUsers.token (scimUser, pw, user) update + + pure $ (testScimUsers {users = updatedUsers} :: TestScimUsers) + + updatePendingScimUsers :: (HasCallStack) => String -> TestScimUsers -> [PendingScimUpdate] -> App TestScimUsers + updatePendingScimUsers domain testScimUsers updates = do + let usersWithUpdates = (zip (Map.elems testScimUsers.users) updates) + updatedUsers <- fmap Map.unions . pooledForConcurrentlyN parallelism usersWithUpdates $ \((scimUser, pw, inv), update) -> do + uid <- scimUser %. "id" & asString + email <- scimUser %. "externalId" & asString + tid <- testScimUsers.owner %. "team" & asString + Map.singleton uid <$> case update of + RegisterPendingScimUser -> do + registerInvitedUser domain tid email + updatedScimUser <- getScimUser domain testScimUsers.token uid >>= getJSON 200 + let quid = object ["domain" .= domain, "id" .= uid] + fmap (updatedScimUser,pw,) . getJSON 200 =<< getSelf quid + UpdatePendingScimUser updateUser -> do + updatePendingScimUserAndCheck domain testScimUsers.token (scimUser, pw, inv) updateUser + pure (testScimUsers {users = updatedUsers} :: TestScimUsers) + + createSsoUsers :: (HasCallStack) => String -> Int -> App TestTeamUsers + createSsoUsers domain n = do + (owner, tid, _) <- createTeam domain 1 + I.setTeamFeatureStatus owner tid "sso" "enabled" >>= assertSuccess + (createIdpResp, (idpMeta, privcreds)) <- registerTestIdPWithMetaWithPrivateCreds owner + assertSuccess createIdpResp + idpId <- asString =<< (createIdpResp.json %. "id") + + users <- fmap Map.unions . pooledReplicateConcurrentlyN 16 n $ do + subject <- nextSubject + (mUid, _) <- loginWithSamlWithZHost Nothing domain True tid subject (idpId, (idpMeta, privcreds)) + uid <- assertJust "user id not created by logging in with SAML" mUid + (,Nothing) <$$> getUnqualifiedUser domain uid + pure $ TestTeamUsers {..} + + createPasswordTeamUsers :: (HasCallStack) => String -> Int -> App TestTeamUsers + createPasswordTeamUsers domain n = do + (owner, _tid, usersWithoutPassword) <- createTeam domain n + + users <- fmap Map.unions . pooledForConcurrentlyN parallelism usersWithoutPassword $ \user -> do + p <- randomPassword + putPassword user defPassword p >>= assertSuccess + uid <- user %. "qualified_id.id" & asString + pure $ Map.singleton uid (user, Just p) + + pure $ TestTeamUsers {..} + + deleteTeamUsers :: (HasCallStack) => TestTeamUsers -> App () + deleteTeamUsers team = do + withWebSocket team.owner $ \wsOwner -> do + tid <- team.owner %. "team" & asString + pooledForConcurrentlyN_ parallelism team.users $ \(user, _) -> do + uid <- user %. "qualified_id.id" & asString + deleteTeamMember tid team.owner uid >>= assertSuccess + + void $ awaitNMatches (Map.size team.users) isTeamMemberLeaveNotif wsOwner + + getSelfWithAssertion :: (HasCallStack, MakesValue user) => user -> ((HasCallStack) => Response -> App ()) -> App (Map String Value) + getSelfWithAssertion user assertion = do + getSelf user `bindResponse` \resp -> do + resp.status `shouldMatchInt` 200 + assertion resp + Map.singleton <$> (resp.json %. "qualified_id.id" & asString) <*> (assertJust "expected GET /self to return a JSON" resp.json) + + checkUpdateUser :: (HasCallStack) => Map String (Value, Maybe String) -> [UserUpdate] -> App (Map String (Value, Maybe String)) + checkUpdateUser users updates = do + fmap Map.unions . pooledForConcurrentlyN parallelism (zip (Map.elems users) updates) $ \((user, mPassword), update) -> + addJSONToFailureContext "user" user . addJSONToFailureContext "update" update $ do + updatedUser <- case (update, mPassword) of + (UpdateName newName, _) -> do + putSelf user def {name = Just newName} >>= assertSuccess + getSelfWithAssertion user $ \resp -> resp.json %. "name" `shouldMatch` newName + (UpdateEmail newEmail, Just pw) -> do + oldEmail <- user %. "email" & asString + (cookie, token) <- bindResponse (login user oldEmail pw) $ \resp -> do + resp.status `shouldMatchInt` 200 + token <- resp.json %. "access_token" & asString + let cookie = fromJust $ getCookie "zuid" resp + pure ("zuid=" <> cookie, token) + updateEmail user newEmail cookie token >>= assertSuccess + activateEmail user newEmail + getSelfWithAssertion user $ \resp -> resp.json %. "email" `shouldMatch` newEmail + (UpdateEmail {}, Nothing) -> do + uid <- user %. "qualified_id.id" & asString + pure $ Map.singleton uid user + (UpdateHandle newHandle, _) -> do + putHandle user newHandle >>= assertSuccess + getSelfWithAssertion user $ \resp -> resp.json %. "handle" `shouldMatch` newHandle + (UpdatePassword newPassword, Just oldPassword) -> do + email <- user %. "email" & asString + putPassword user oldPassword newPassword >>= assertSuccess + login user email oldPassword `bindResponse` \resp -> + resp.status `shouldMatchInt` 403 + login user email newPassword >>= assertSuccess + uid <- user %. "qualified_id.id" & asString + pure $ Map.singleton uid user + (UpdatePassword {}, Nothing) -> do + uid <- user %. "qualified_id.id" & asString + pure $ Map.singleton uid user + pure $ (,mPassword) <$> updatedUser + + createPersonalUsers :: (HasCallStack, MakesValue mel) => String -> mel -> Int -> Bool -> App (Map String (Value, Maybe String)) + createPersonalUsers domain mel n claimHandle = + fmap Map.unions . pooledReplicateConcurrentlyN parallelism n $ do + user <- randomUser domain def + connectTwoUsers mel user + uid <- user %. "qualified_id.id" & asString + if claimHandle + then do + hdl <- randomHandle + putHandle user hdl >>= assertSuccess + fmap (,Just defPassword) . Map.singleton uid <$> (setField "handle" hdl user) + else pure $ Map.singleton uid (user, Just defPassword) + + deletePersonalUsers :: (HasCallStack, MakesValue mel, ToWSConnect mel) => mel -> Map String (Value, Maybe String) -> App () + deletePersonalUsers mel users = + withWebSocket mel $ \wsMel -> do + pooledForConcurrentlyN_ parallelism users $ uncurry deleteUserWithPassword + void $ awaitNMatches (Map.size users) isDeleteUserNotif wsMel + + createConvsAndAddBot :: (HasCallStack, MakesValue user) => String -> user -> Maybe String -> String -> String -> Int -> App (Map String (Value, Value)) + createConvsAndAddBot domain user tid pid sid n = do + fmap Map.unions . pooledReplicateConcurrentlyN parallelism n $ do + conv <- postConversation user (defProteus {team = tid}) >>= getJSON 201 + convId <- conv %. "qualified_id" & objId + addBotResp <- addBot user pid sid convId >>= getJSON 201 + botId <- addBotResp %. "id" & asString + (,conv) <$$> getUnqualifiedUser domain botId + + createTeamBots :: (HasCallStack) => String -> String -> String -> Int -> App TestTeamUsers + createTeamBots domain pid sid n = do + (owner, tid, _) <- createTeam domain 1 + postServiceWhitelist owner tid (object ["id" .= sid, "provider" .= pid, "whitelisted" .= True]) + >>= assertSuccess + TestTeamUsers owner . fmap (\(x, _) -> (x, Nothing)) <$> createConvsAndAddBot domain owner (Just tid) pid sid n + + deleteBotsTeam :: (HasCallStack) => TestTeamUsers -> String -> String -> App () + deleteBotsTeam testTeam pid sid = do + tid <- testTeam.owner %. "team" & asString + withWebSocket testTeam.owner $ \ws -> do + postServiceWhitelist testTeam.owner tid (object ["id" .= sid, "provider" .= pid, "whitelisted" .= False]) >>= assertSuccess + void $ awaitNMatches (Map.size testTeam.users) isConvLeaveNotif ws + + deleteBotConvs :: (HasCallStack) => Value -> Map String (Value, Value) -> App () + deleteBotConvs mel botConvs = do + pooledForConcurrentlyN_ parallelism (Map.elems botConvs) $ \(bot, conv) -> do + cid <- conv %. "qualified_id.id" & asString + bid <- bot %. "qualified_id.id" & asString + rmBotSelf mel bid cid >>= assertSuccess + +-- | This test creates users in PG and Cassandra separately to simulate a +-- situation where there are users in both DBs. Then tries to index them into ES +-- to make sure the pagination over these users works. +testReindexingUsersDuringMigration :: (HasCallStack) => App () +testReindexingUsersDuringMigration = do + resourcePool <- asks (.resourcePool) + + runCodensity (acquireResources 1 resourcePool) $ \[backend] -> do + let domain = backend.berDomain + -- Create users in cassandra using 'phase1Overrides' + (casSearcher, casExistingUsers, casDeletedUsers) <- + runCodensity (startDynamicBackend backend phase1Overrides) + $ \_ -> setupUsers domain + + -- Create users in postgres using 'phase5Overrides' + (pgSearcher, pgExistingUsers, pgDeletedUsers) <- + runCodensity (startDynamicBackend backend phase5Overrides) + $ \_ -> setupUsers domain + + -- Test that searching in the already existing index works with in + -- 'phase2Overrides', which should work with data in cassandra and postgres + runCodensity (startDynamicBackend backend phase2Overrides) $ \_ -> do + I.refreshIndex domain + checkSearchWorks domain casSearcher casExistingUsers casDeletedUsers + checkSearchWorks domain pgSearcher pgExistingUsers pgDeletedUsers + + newIndex <- createNewIndex + let backendWithNewIndex = backend {berElasticsearchIndex = newIndex} + runCodensity (startDynamicBackend backendWithNewIndex phase2Overrides) $ \_ -> do + reindexUsers backendWithNewIndex phase2Overrides 5 + I.refreshIndex domain + checkSearchWorks domain casSearcher casExistingUsers casDeletedUsers + checkSearchWorks domain pgSearcher pgExistingUsers pgDeletedUsers + where + n = 5 + parallelism = 16 + + setupUsers :: (HasCallStack) => String -> App (Value, [Value], [Value]) + setupUsers domain = do + searcher <- randomUser domain def + existingUsers <- pooledReplicateConcurrentlyN parallelism n $ randomUser domain def + deletedUsers <- pooledReplicateConcurrentlyN parallelism n $ do + u <- randomUser domain def + connectTwoUsers searcher u + pure u + withWebSocket searcher $ \ws -> do + pooledForConcurrentlyN_ parallelism deletedUsers deleteUser + void $ awaitNMatches n isDeleteUserNotif ws + pure (searcher, existingUsers, deletedUsers) + + checkSearchWorks :: (HasCallStack) => String -> Value -> [Value] -> [Value] -> App () + checkSearchWorks domain searcher existingUsers deletedUsers = do + pooledForConcurrentlyN_ parallelism existingUsers $ \u -> + assertCanFind searcher u (u %. "name") domain + + pooledForConcurrentlyN_ parallelism deletedUsers $ \u -> + assertCannotFind searcher u (u %. "name") domain + +-- handleA: Alice and Anna have the same handle, but the handle claims table +-- supports Alice's claim. After the migration Bob loses their handle. +-- +-- handleB: Bob and Bill also have the same handle, but the handle claims table +-- doesn't support any of their claims. After the migration both of them will +-- loose the claim. +-- +-- handleC: Carl and Creed also have the same handle, Cassandra supports Carl's +-- claim, while Postgresql supports Creed's claim. In this case Creed gets to +-- keep their handle. +testMigrationOfUsersWithHandleDisputes :: (HasCallStack) => App () +testMigrationOfUsersWithHandleDisputes = do + resourcePool <- asks (.resourcePool) + -- Between Alice and Anna + handleA <- randomHandle + + -- In user record for Bob and Bill + handleB <- randomHandle + + -- Between Carl and Creed + handleC <- randomHandle + + runCodensity (acquireResources 1 resourcePool) $ \[backend] -> do + let domain = backend.berDomain + brigKeyspace = backend.berBrigKeyspace + (alice, anna, bob, bill, carl) <- runCodensity (startDynamicBackend backend phase1Overrides) $ \_ -> do + alice <- randomUser domain def + anna <- randomUser domain def + bob <- randomUser domain def + bill <- randomUser domain def + carl <- randomUser domain def + + Just annaId <- UUID.fromString <$> (anna %. "qualified_id.id" & asString) + Just bobId <- UUID.fromString <$> (bob %. "qualified_id.id" & asString) + Just billId <- UUID.fromString <$> (bill %. "qualified_id.id" & asString) + + -- Claim handle correctly for alice + putHandle alice handleA >>= assertSuccess + putHandle carl handleC >>= assertSuccess + + -- Claim handle by hacking into the DB for others. There seems to be no + -- other way of testing this edge case + let assignHandleQuery :: PrepQuery W (Text, UUID) () = fromString $ "UPDATE " <> brigKeyspace <> ".user SET handle = ? WHERE id = ?" + write assignHandleQuery $ defQueryParams LocalQuorum (Text.pack handleA, annaId) + write assignHandleQuery $ defQueryParams LocalQuorum (Text.pack handleB, bobId) + write assignHandleQuery $ defQueryParams LocalQuorum (Text.pack handleB, billId) + + assertHandle alice (Just handleA) + assertHandle anna (Just handleA) + assertHandle bob (Just handleB) + assertHandle bill (Just handleB) + assertHandle carl (Just handleC) + + pure (alice, anna, bob, bill, carl) + + -- Start Phase 5 here so that we can claim the same handle for Dan as Doug + -- but in Postgresql. The production scenario can only happen due to a race + -- condition. This is just a more precise way of causing the DB + -- inconsistency. + creed <- runCodensity (startDynamicBackend backend phase5Overrides) $ \_ -> do + creed <- randomUser domain def + putHandle creed handleC >>= assertSuccess + assertHandle creed (Just handleC) + pure creed + + runCodensity (startDynamicBackend backend phase3Overrides) $ \_ -> do + waitForMigration domain userMigrationFinishedCounterName + assertMigrationSuccessful domain "^wire_users_migration_failed" + + runCodensity (startDynamicBackend backend phase5Overrides) $ \_ -> do + assertHandle alice (Just handleA) + assertHandle anna Nothing + + assertHandle bob Nothing + assertHandle bill Nothing + + assertHandle carl Nothing + assertHandle creed (Just handleC) + + -- handleA cannot be claimed + putHandle anna handleA >>= assertStatus 409 + + -- handleB can be claimed + putHandle bob handleB >>= assertSuccess + + -- handleC cannot be claimed + putHandle carl handleC >>= assertStatus 409 + where + assertHandle :: (HasCallStack) => Value -> Maybe String -> App () + assertHandle user expectedHandle = do + getSelf user `bindResponse` \resp -> do + resp.status `shouldMatchInt` 200 + case expectedHandle of + Just h -> + resp.json %. "handle" `shouldMatch` h + Nothing -> + case resp.json of + Just (Object o) -> KM.keys o `shouldNotContain` [fromString "handle"] + _ -> assertFailure "Unexpected body for getSelf" + +testMigrationOfInvalidUsers :: (HasCallStack) => App () +testMigrationOfInvalidUsers = do + resourcePool <- asks (.resourcePool) + + runCodensity (acquireResources 1 resourcePool) $ \[backend] -> do + let domain = backend.berDomain + brigKeyspace = backend.berBrigKeyspace + (validUser, noName, noNameId, noActivated, noActivatedId) <- runCodensity (startDynamicBackend backend phase1Overrides) $ \_ -> do + validUser <- randomUser domain def + + noName <- randomUser domain def + Just noNameId <- UUID.fromString <$> (noName %. "qualified_id.id" & asString) + + noActivated <- randomUser domain def + Just noActivatedId <- UUID.fromString <$> (noActivated %. "qualified_id.id" & asString) + + -- Cause users to be invalid by poking into Cassandra + let removeName :: PrepQuery W (Identity UUID) () = fromString $ "UPDATE " <> brigKeyspace <> ".user SET name = NULL WHERE id = ?" + removeActivated :: PrepQuery W (Identity UUID) () = fromString $ "UPDATE " <> brigKeyspace <> ".user SET activated = NULL WHERE id = ?" + write removeName $ defQueryParams LocalQuorum (Identity noNameId) + write removeActivated $ defQueryParams LocalQuorum (Identity noActivatedId) + + getSelf validUser >>= assertStatus 200 + getSelf noName >>= assertStatus 500 + getSelf noActivated >>= assertStatus 500 + + pure (validUser, noName, noNameId, noActivated, noActivatedId) + + runCodensity (startDynamicBackend backend phase3Overrides) $ \_ -> do + waitForMigration domain userMigrationFinishedCounterName + + runCodensity (startDynamicBackend backend phase5Overrides) $ \_ -> do + getSelf validUser >>= assertStatus 200 + getSelf noName >>= assertStatus 404 + getSelf noActivated >>= assertStatus 404 + + -- Delete invalid users from cassandra so they don't trip other tests. These + -- other tests are usually reindexing the users, the reindex code doesn't + -- deal with invalid users so well. + let deleteUserRow :: PrepQuery W (Identity UUID) () = fromString $ "DELETE FROM " <> brigKeyspace <> ".user WHERE id = ?" + write deleteUserRow $ defQueryParams LocalQuorum (Identity noNameId) + write deleteUserRow $ defQueryParams LocalQuorum (Identity noActivatedId) + +-- * Test Helpers + +data TestUsersByOperations = TestUsersByOperations + { updates :: IntMap TestUserList, + deletes :: IntMap TestUserList + } + deriving (Show, Eq, Generic) + +instance Semigroup TestUsersByOperations where + users1 <> users2 = + TestUsersByOperations + { updates = users1.updates <> users2.updates, + deletes = users1.deletes <> users2.deletes + } + +instance Monoid TestUsersByOperations where + mempty = TestUsersByOperations {updates = mempty, deletes = mempty} + +instance ToJSON TestUsersByOperations + +data TestUserList = TestUserList + { scimUsersWithRichInfo :: TestScimUsers, + scimUsersWithoutRichInfo :: TestScimUsers, + pendingScimUsers :: TestScimUsers, + ssoUsers :: TestTeamUsers, + passwordTeamUsers :: TestTeamUsers, + personalUsersWithoutHandle :: Map String (Value, Maybe String), + personalUsersWithHandle :: Map String (Value, Maybe String), + botsInTeamConvs :: TestTeamUsers, + -- UserId -> (User, Conv) + botsInPersonalConvs :: Map String (Value, Value) + } + deriving (Show, Eq) + +data TestScimUsers = TestScimUsers + { owner :: Value, + token :: String, + -- | ScimUser, Password, UserOrInv + users :: Map String (Value, String, Value) + } + deriving (Show, Eq) + +data TestTeamUsers = TestTeamUsers + { owner :: Value, + -- | (user, maybe password) + users :: Map String (Value, Maybe String) + } + deriving (Show, Eq) + +instance ToJSON TestUserList where + toJSON userList = do + object + [ fromString "scimUsersWithRichInfo" .= Map.keys userList.scimUsersWithRichInfo.users, + fromString "scimUsersWithoutRichInfo" .= Map.keys userList.scimUsersWithoutRichInfo.users, + fromString "pendingScimUsers" .= Map.keys userList.pendingScimUsers.users, + fromString "ssoUsers" .= Map.keys userList.ssoUsers.users, + fromString "passwordTeamUsers" .= Map.keys userList.passwordTeamUsers.users, + fromString "personalUsersWithoutHandle" .= Map.keys userList.personalUsersWithoutHandle, + fromString "personalUsersWithHandle" .= Map.keys userList.personalUsersWithHandle, + fromString "botsInTeamConvs" .= Map.keys userList.botsInTeamConvs.users, + fromString "botsInPersonalConvs" .= Map.keys userList.botsInPersonalConvs + ] + +data UserUpdate + = UpdateName String + | UpdateHandle String + | UpdateEmail String + | UpdatePassword String + deriving (Show, Eq, Generic) + +instance Arbitrary UserUpdate where + arbitrary = + oneof + [ UpdateName <$> arbitraryName, + UpdateHandle <$> arbitraryHandle, + UpdateEmail <$> arbitraryEmail, + UpdatePassword <$> arbitraryPassword + ] + +instance ToJSON UserUpdate + +arbitraryNonPasswordUpdate :: Gen UserUpdate +arbitraryNonPasswordUpdate = + oneof + [ UpdateName <$> arbitraryName, + UpdateHandle <$> arbitraryHandle, + UpdateEmail <$> arbitraryEmail + ] + +data PendingScimUpdate + = RegisterPendingScimUser + | UpdatePendingScimUser UserUpdate + deriving (Show, Eq, Generic) + +instance Arbitrary PendingScimUpdate where + arbitrary = + oneof + [ pure RegisterPendingScimUser, + UpdatePendingScimUser <$> arbitraryNonPasswordUpdate + ] + +instance ToJSON PendingScimUpdate + +data PhaseUpdates = PhaseUpdates + { scimUsersWithRichInfo :: [UserUpdate], + scimUsersWithoutRichInfo :: [UserUpdate], + pendingScimUsers :: [PendingScimUpdate], + ssoUsers :: [UserUpdate], + passwordTeamUsers :: [UserUpdate], + personalUsersWithoutHandle :: [UserUpdate], + personalUsersWithHandle :: [UserUpdate] + } + deriving (Show, Eq, Generic) + +instance ToJSON PhaseUpdates + +arbitraryPhaseUpdates :: Int -> Gen PhaseUpdates +arbitraryPhaseUpdates n = do + scimUsersWithRichInfo <- replicateM n arbitrary + scimUsersWithoutRichInfo <- replicateM n arbitrary + pendingScimUsers <- replicateM n arbitrary + ssoUsers <- replicateM n arbitraryNonPasswordUpdate + passwordTeamUsers <- replicateM n arbitrary + personalUsersWithoutHandle <- replicateM n arbitrary + personalUsersWithHandle <- replicateM n arbitrary + pure PhaseUpdates {..} + +userMigrationFinishedCounterName :: String +userMigrationFinishedCounterName = "^wire_users_migration_finished" + +commonOverrides, phase1Overrides, phase2Overrides, phase3Overrides, phase4Overrides, phase5Overrides :: ServiceOverrides +commonOverrides = + def + { brigCfg = + setField @_ @Int "optSettings.setUserMaxConnections" 500 + >=> setField @_ @Int "optSettings.setActivationTimeout" 3600 + >=> setField @_ @Int "optSettings.setVerificationTimeout" 3600 + >=> setField @_ @Int "optSettings.setTeamInvitationTimeout" 3600 + >=> setField @_ @Int "optSettings.setUserCookieRenewAge" 1209600 + >=> setField @_ @Int "postgresqlPool.size" 200 + >=> removeField "optSettings.setSuspendInactiveUsers" + } +phase1Overrides = + commonOverrides + <> def + { brigCfg = setField "postgresMigration.user" "cassandra", + galleyCfg = setField "postgresMigration.user" "cassandra", + backgroundWorkerCfg = + setField "postgresMigration.user" "cassandra" + >=> setField "migrateUsers" False + } +phase2Overrides = + commonOverrides + <> def + { brigCfg = setField "postgresMigration.user" "migration-to-postgresql", + galleyCfg = setField "postgresMigration.user" "migration-to-postgresql", + backgroundWorkerCfg = + setField "postgresMigration.user" "migration-to-postgresql" + >=> setField "migrateUsers" False + } +phase3Overrides = + commonOverrides + <> def + { brigCfg = setField "postgresMigration.user" "migration-to-postgresql", + galleyCfg = setField "postgresMigration.user" "migration-to-postgresql", + backgroundWorkerCfg = + setField "postgresMigration.user" "migration-to-postgresql" + >=> setField "migrateUsers" True + } +phase4Overrides = + commonOverrides + <> def + { brigCfg = setField "postgresMigration.user" "migration-to-postgresql", + galleyCfg = setField "postgresMigration.user" "migration-to-postgresql", + backgroundWorkerCfg = + setField "postgresMigration.user" "migration-to-postgresql" + >=> setField "migrateUsers" False + } +phase5Overrides = + commonOverrides + <> def + { brigCfg = setField "postgresMigration.user" "postgresql", + galleyCfg = setField "postgresMigration.user" "postgresql", + backgroundWorkerCfg = + setField "postgresMigration.user" "postgresql" + >=> setField "migrateUsers" False + } + +phaseOverrides :: IntMap ServiceOverrides +phaseOverrides = + IntMap.fromList + [ (1, phase1Overrides), + (2, phase2Overrides), + (3, phase3Overrides), + (4, phase4Overrides), + (5, phase5Overrides) + ] diff --git a/integration/test/Test/Migration/Util.hs b/integration/test/Test/Migration/Util.hs index ba3a116b453..28d1d4712ac 100644 --- a/integration/test/Test/Migration/Util.hs +++ b/integration/test/Test/Migration/Util.hs @@ -27,14 +27,30 @@ import GHC.Stack import SetupHelpers hiding (deleteUser) import Testlib.Prelude import Text.Regex.TDFA ((=~)) +import UnliftIO waitForMigration :: (HasCallStack) => String -> String -> App () -waitForMigration domain name = do - metrics <- - getMetrics domain BackgroundWorker `bindResponse` \resp -> do - resp.status `shouldMatchInt` 200 - pure $ Text.decodeUtf8 resp.body - let (_, _, _, finishedMatches) :: (Text, Text, Text, [Text]) = (metrics =~ Text.pack (name <> "\\ ([0-9]+\\.[0-9]+)$")) - when (finishedMatches /= [Text.pack "1.0"]) $ do - liftIO $ threadDelay 100_000 - waitForMigration domain name +waitForMigration domain metricName = + maybe failWithContext pure =<< timeout 30_000_000 go + where + failWithContext = do + getMetrics domain BackgroundWorker `bindResponse` \resp -> do + resp.status `shouldMatchInt` 200 + assertFailure "Timed out waiting for postgresql migration" + go = do + metrics <- + getMetrics domain BackgroundWorker `bindResponse` \resp -> do + resp.status `shouldMatchInt` 200 + pure $ Text.decodeUtf8 resp.body + let (_, _, _, finishedMatches) :: (Text, Text, Text, [Text]) = (metrics =~ Text.pack (metricName <> "\\ ([0-9]+\\.[0-9]+)$")) + when (finishedMatches /= [Text.pack "1.0"]) $ do + liftIO $ threadDelay 100_000 + go + +assertMigrationSuccessful :: (HasCallStack) => String -> String -> App () +assertMigrationSuccessful domain failedMetricName = do + getMetrics domain BackgroundWorker `bindResponse` \resp -> do + resp.status `shouldMatchInt` 200 + let metrics = Text.decodeUtf8 resp.body + (_, _, _, failedMatches) :: (Text, Text, Text, [Text]) = (metrics =~ Text.pack (failedMetricName <> "\\ ([0-9]+\\.[0-9]+)$")) + failedMatches `shouldMatch` [Text.pack "0.0"] diff --git a/integration/test/Test/Search.hs b/integration/test/Test/Search.hs index a0986828555..b4b3edb4b79 100644 --- a/integration/test/Test/Search.hs +++ b/integration/test/Test/Search.hs @@ -693,7 +693,7 @@ testReindexAllUsers = do assertCannotFind alice user (user %. "name") domain -- Reindex users using a small page size so pagination gets excersiced - reindexUsers testBackend 5 + reindexUsers testBackend def 5 BrigI.refreshIndex domain -- Now things should work as expected diff --git a/integration/test/Test/Spar.hs b/integration/test/Test/Spar.hs index 7d45322967a..d2a2f4770c5 100644 --- a/integration/test/Test/Spar.hs +++ b/integration/test/Test/Spar.hs @@ -131,6 +131,36 @@ testTeamInvitationWhenScimInvitationPending = do user %. "managed_by" `shouldMatch` "scim" user %. "status" `shouldMatch` "pending-invitation" +testScimReinviteAfterRevoke :: (HasCallStack) => App () +testScimReinviteAfterRevoke = do + let settings = + def + { brigCfg = + -- Controls when asynchronous cleanup removes expired SCIM pending accounts. + setField "optSettings.setExpiredUserCleanupTimeout" (3600 :: Int) + } + withModifiedBackend settings $ \domain -> do + (owner, tid, _) <- createTeam domain 1 + token <- createScimToken owner def >>= getJSON 200 >>= (%. "token") >>= asString + + email <- randomEmail + externalId <- randomExternalId + scimUser <- randomScimUserWithEmail externalId email + scid <- createScimUser domain token scimUser >>= getJSON 201 >>= (%. "id") >>= asString + handle <- scimUser %. "userName" >>= asString + + -- assert that the SCIM handle is claimed + putHandle owner handle >>= assertStatus 409 + + -- cancel the invitation + void $ Brig.listInvitations owner tid >>= getJSON 200 >>= (%. "invitations") >>= asList >>= assertOne + Brig.deleteTeamInvitation owner tid scid >>= assertSuccess + void $ Brig.listInvitations owner tid >>= getJSON 200 >>= (%. "invitations") >>= shouldBeEmpty + + -- retry the invite should work + createScimUser domain token scimUser `bindResponse` \resp -> do + resp.status `shouldMatchInt` 201 + testTeamInvitationWhenScimAccountExists :: (HasCallStack) => App () testTeamInvitationWhenScimAccountExists = do (owner, tid, _) <- createTeam OwnDomain 1 @@ -157,6 +187,37 @@ testTeamInvitationWhenScimAccountExists = do user %. "managed_by" `shouldMatch` "scim" user %. "status" `shouldMatch` "active" +-- | Ensure that unused team invitations are invalidated when the SCIM user +-- gets deleted. +testTeamInvitationUsedAfterScimUserDeleted :: (HasCallStack) => App () +testTeamInvitationUsedAfterScimUserDeleted = do + (owner, tid, _) <- createTeam OwnDomain 1 + token <- createScimToken owner def >>= getJSON 200 >>= (%. "token") >>= asString + + email <- randomEmail + externalId <- randomExternalId + scimUser <- randomScimUserWithEmail externalId email + scid <- createScimUser OwnDomain token scimUser >>= getJSON 201 >>= (%. "id") >>= asString + + code <- + getInvitationByEmail OwnDomain email + >>= getJSON 200 + >>= getInvitationCodeForTeam OwnDomain tid + >>= getJSON 200 + >>= (%. "code") + >>= asString + + deleteScimUser OwnDomain token scid >>= assertSuccess + + -- The invitation must no longer be usable: completing registration with + -- the previously-fetched code should fail, not resurrect the deleted + -- account. (This was bug WPB-28198) + registerUserWith OwnDomain email code "Eve" >>= assertStatus 400 + + getUsersByEmail OwnDomain [email] >>= getJSON 200 >>= asList >>= shouldBeEmpty + + getInvitationByEmail OwnDomain email >>= assertStatus 404 + testSparUserCreationInvitationTimeout :: (HasCallStack) => App () testSparUserCreationInvitationTimeout = do (owner, tid, _) <- createTeam OwnDomain 1 diff --git a/integration/test/Test/Swagger.hs b/integration/test/Test/Swagger.hs index c150b0d62f0..a326ff18abb 100644 --- a/integration/test/Test/Swagger.hs +++ b/integration/test/Test/Swagger.hs @@ -30,7 +30,7 @@ import Testlib.Prelude import UnliftIO.Temporary existingVersions :: Set Int -existingVersions = Set.fromList [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18] +existingVersions = Set.fromList [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] internalApis :: Set String internalApis = Set.fromList ["brig", "cannon", "cargohold", "cannon", "spar"] diff --git a/integration/test/Test/SystemSettings.hs b/integration/test/Test/SystemSettings.hs index 43071765b46..ff6c07fcdea 100644 --- a/integration/test/Test/SystemSettings.hs +++ b/integration/test/Test/SystemSettings.hs @@ -47,3 +47,41 @@ testGetSettingsInternal (MkTagged enableMls) = do getSystemSettingsInternal user `bindResponse` \resp -> do resp.status `shouldMatchInt` 200 resp.json %. "setEnableMls" `shouldMatch` fromMaybe False enableMls + +testGetSettingsInternalSsoIdpChangeDetection :: + (HasCallStack) => + Tagged "sso-idp-change-detection" (Maybe Bool) -> + App () +testGetSettingsInternalSsoIdpChangeDetection (MkTagged multiIngress) = do + let conf = + def + { brigCfg = + maybe + (removeField "optSettings.setSsoIdpChangeDetectionInputs") + (setField "optSettings.setSsoIdpChangeDetectionInputs" . sparInputs) + multiIngress + } + withModifiedBackend conf \domain -> do + user <- randomUser domain def + getSystemSettingsInternal user `bindResponse` \resp -> do + resp.status `shouldMatchInt` 200 + -- Brig derives the flag in Haskell from the raw inputs: true iff both the + -- multi-ingress domain configs and the IdP cert fingerprint allowlist are + -- non-empty (Brig.Options.deriveSsoIdpChangeDetectionEnabled); absent + -- inputs mean disabled. The tag enumerates Nothing/Just False/Just True + -- (GEnum), so `fromMaybe` — not `fromJust`. + resp.json %. "ssoIdpChangeDetectionEnabled" `shouldMatch` fromMaybe False multiIngress + getSystemSettingsPublic domain `bindResponse` \resp -> do + resp.status `shouldMatchInt` 200 + lookupField resp.json "ssoIdpChangeDetectionEnabled" `shouldMatch` (Nothing :: Maybe Value) + +-- | Minimal mirror of @spar.config@: 'True' is a multi-ingress spar (non-empty +-- @domainConfigs@ and allowlist); 'False' is single-ingress spar (both empty). +sparInputs :: Bool -> Value +sparInputs multiIngress = + object + [ "multiIngressDomainConfigs" + .= if multiIngress then object ["example.com" .= object []] else object [], + "idpCertFingerprintAllowlist" + .= if multiIngress then ["00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33" :: String] else ([] :: [String]) + ] diff --git a/integration/test/Testlib/Env.hs b/integration/test/Testlib/Env.hs index dd37e9c8f56..92675404337 100644 --- a/integration/test/Testlib/Env.hs +++ b/integration/test/Testlib/Env.hs @@ -96,14 +96,14 @@ mkGlobalEnv cfgFile = do & Cassandra.setContacts intConfig.cassandra.cassHost [] & Cassandra.setPortNumber (fromIntegral intConfig.cassandra.cassPort) cassSettings = maybe basicCassSettings (\sslCtx -> Cassandra.setSSLContext sslCtx basicCassSettings) mbSSLContext - cassClient <- Cassandra.init cassSettings + gCassClient <- Cassandra.init cassSettings let resources = backendResources (Map.elems intConfig.dynamicBackends) resourcePool <- liftIO $ createBackendResourcePool resources intConfig.rabbitmq - cassClient + gCassClient let sm = Map.fromList $ [ (intConfig.backendOne.originDomain, intConfig.backendOne.beServiceMap), @@ -133,7 +133,7 @@ mkGlobalEnv cfgFile = do gFederationV1Domain = intConfig.federationV1.originDomain, gFederationV2Domain = intConfig.federationV2.originDomain, gDynamicDomains = (.domain) <$> Map.elems intConfig.dynamicBackends, - gDefaultAPIVersion = 18, + gDefaultAPIVersion = 19, gManager = manager, gServicesCwdBase = devEnvProjectRoot <&> ( "services"), gBackendResourcePool = resourcePool, @@ -146,7 +146,8 @@ mkGlobalEnv cfgFile = do gDNSMockServerConfig = intConfig.dnsMockServer, gCellsEventQueue = intConfig.cellsEventQueue, gCellsEventWatchersLock, - gCellsEventWatchers + gCellsEventWatchers, + gCassClient } where createSSLContext :: Maybe FilePath -> IO (Maybe OpenSSL.SSLContext) @@ -202,6 +203,7 @@ mkEnv currentTestName ge = do cellsEventQueue = ge.gCellsEventQueue, cellsEventWatchersLock = ge.gCellsEventWatchersLock, cellsEventWatchers = ge.gCellsEventWatchers, + cassClient = ge.gCassClient, curlTrace } diff --git a/integration/test/Testlib/JSON.hs b/integration/test/Testlib/JSON.hs index 04ae74ef192..b02402cc27a 100644 --- a/integration/test/Testlib/JSON.hs +++ b/integration/test/Testlib/JSON.hs @@ -26,6 +26,7 @@ import Data.Aeson hiding ((.=)) import qualified Data.Aeson as Aeson import qualified Data.Aeson.Encode.Pretty as Aeson import qualified Data.Aeson.Key as KM +import Data.Aeson.KeyMap (KeyMap) import qualified Data.Aeson.KeyMap as KM import qualified Data.Aeson.Types as Aeson import Data.ByteString (ByteString) @@ -320,6 +321,11 @@ modifyField selector up x = do ob <- asObject v pure $ Object $ KM.insert (KM.fromString k) newValue ob +modifyObject :: (HasCallStack, MakesValue a) => (KeyMap Value -> KeyMap Value) -> a -> App Value +modifyObject f x = do + ob <- asObject x + pure . Object $ f ob + -- | `removeField "a.b" {"a": {"b": 3}, "c": true} == {"a": {}, "c": true}` removeField :: (HasCallStack, MakesValue a) => String -> a -> App Value removeField selector x = do diff --git a/integration/test/Testlib/Types.hs b/integration/test/Testlib/Types.hs index 638c6a65279..2919803d459 100644 --- a/integration/test/Testlib/Types.hs +++ b/integration/test/Testlib/Types.hs @@ -55,6 +55,7 @@ import qualified Data.Text as T import qualified Data.Text.Encoding as T import Data.Time import Data.Word +import qualified Database.CQL.IO as Cassandra import GHC.Generics (Generic) import GHC.Records import GHC.Stack @@ -147,7 +148,8 @@ data GlobalEnv = GlobalEnv gDNSMockServerConfig :: DNSMockServerConfig, gCellsEventQueue :: String, gCellsEventWatchersLock :: MVar (), - gCellsEventWatchers :: IORef (Map String QueueWatcher) + gCellsEventWatchers :: IORef (Map String QueueWatcher), + gCassClient :: Cassandra.ClientState } data IntegrationConfig = IntegrationConfig @@ -276,7 +278,8 @@ data Env = Env cellsEventQueue :: String, cellsEventWatchersLock :: MVar (), cellsEventWatchers :: IORef (Map String QueueWatcher), - curlTrace :: IORef [String] + curlTrace :: IORef [String], + cassClient :: Cassandra.ClientState } data Response = Response @@ -488,6 +491,18 @@ newtype App a = App {unApp :: ReaderT Env IO a} instance MonadRandom App where getRandomBytes n = liftIO (getRandomBytes n) +instance Cassandra.MonadClient App where + liftClient :: Cassandra.Client a -> App a + liftClient action = do + clientState <- asks (.cassClient) + liftIO $ Cassandra.runClient clientState action + + localState :: (Cassandra.ClientState -> Cassandra.ClientState) -> App a -> App a + localState f action = do + env <- ask + let newClientState = f env.cassClient + liftIO $ runAppWithEnv (env {cassClient = newClientState}) action + runAppWithEnv :: Env -> App a -> IO a runAppWithEnv e m = runReaderT (unApp m) e diff --git a/libs/extended/default.nix b/libs/extended/default.nix index 1813326fc12..8880b875bb5 100644 --- a/libs/extended/default.nix +++ b/libs/extended/default.nix @@ -27,6 +27,7 @@ , http-types , imports , lib +, megaparsec , metrics-wai , monad-control , postgresql-connection-string @@ -76,6 +77,7 @@ mkDerivation { http-client-tls http-types imports + megaparsec metrics-wai monad-control postgresql-connection-string @@ -101,12 +103,14 @@ mkDerivation { aeson base bytestring + containers crypton crypton-asn1-types crypton-pem crypton-x509 hspec imports + postgresql-connection-string QuickCheck string-conversions temporary diff --git a/libs/extended/extended.cabal b/libs/extended/extended.cabal index eee2d884228..6b64767dfd5 100644 --- a/libs/extended/extended.cabal +++ b/libs/extended/extended.cabal @@ -108,6 +108,7 @@ library , http-client-tls , http-types , imports + , megaparsec , metrics-wai , monad-control , postgresql-connection-string @@ -138,6 +139,7 @@ test-suite extended-tests Paths_extended Test.Data.Hourglass.ConstSpec Test.Data.X509.ExtendedSpec + Test.Hasql.Pool.ExtendedSpec Test.System.Logger.ExtendedSpec hs-source-dirs: test @@ -196,6 +198,7 @@ test-suite extended-tests aeson , base , bytestring + , containers , crypton , crypton-asn1-types , crypton-pem @@ -203,6 +206,7 @@ test-suite extended-tests , extended , hspec , imports + , postgresql-connection-string , QuickCheck , string-conversions , temporary diff --git a/libs/extended/src/Hasql/Pool/Extended.hs b/libs/extended/src/Hasql/Pool/Extended.hs index cebbdca0442..515c70ce09e 100644 --- a/libs/extended/src/Hasql/Pool/Extended.hs +++ b/libs/extended/src/Hasql/Pool/Extended.hs @@ -18,6 +18,7 @@ module Hasql.Pool.Extended where import Data.Aeson +import Data.List.NonEmpty qualified as NonEmpty import Data.Misc import Hasql.Connection qualified import Hasql.Connection.Settings qualified as HasqlConnSettings @@ -25,6 +26,7 @@ import Hasql.Pool qualified as HasqlPool import Imports import PostgresqlConnectionString qualified import Prometheus +import Text.Megaparsec qualified as Megaparsec import UnliftIO.IO (getMonotonicTime) import Util.Options @@ -108,6 +110,27 @@ startHasqlPoolStatsReporter pool = void $ forkIO $ forever $ do recordHasqlPoolStats pool threadDelay (5 * 1_000_000) -- 5s +-- | Run a postgresql-connection-string parser, turning a parse failure into +-- an IO exception whose message is the parser's failure text, so the +-- reason is visible wherever this call site's crash output is captured. +-- +-- 'Megaparsec.errorBundlePretty' is avoided because 'fromKeyValueParams' +-- never consumes the (always-empty) input stream, so its source-position +-- pointer would be meaningless noise around the actual message. +runConnStrParser :: Megaparsec.Parsec Void Text a -> IO a +runConnStrParser p = + either + ( fail + . dropWhileEnd isSpace + . Megaparsec.parseErrorTextPretty + . NonEmpty.head + . Megaparsec.bundleErrors + ) + pure + $ let file = "" + input = "" + in Megaparsec.parse p file input + -- | Creates a pool from postgres config params. -- -- 'acquisitionTimeout' is mapped to the pool acquisition timeout, @@ -115,8 +138,9 @@ startHasqlPoolStatsReporter pool = void $ forkIO $ forever $ do initPostgresPool :: PoolConfig -> Map Text Text -> Maybe FilePathSecrets -> IO Pool initPostgresPool config pgConfig mFpSecrets = do mPw <- for mFpSecrets initCredentials + connStr <- runConnStrParser $ PostgresqlConnectionString.fromKeyValueParams pgConfig let pgSettings = - HasqlConnSettings.connectionString (PostgresqlConnectionString.toUrl $ PostgresqlConnectionString.fromKeyValueParams pgConfig) + HasqlConnSettings.connectionString (PostgresqlConnectionString.toUrl connStr) <> foldMap HasqlConnSettings.password mPw metrics <- mkHasqlPoolMetrics rawPool <- diff --git a/libs/extended/test/Test/Hasql/Pool/ExtendedSpec.hs b/libs/extended/test/Test/Hasql/Pool/ExtendedSpec.hs new file mode 100644 index 00000000000..048ef8c323c --- /dev/null +++ b/libs/extended/test/Test/Hasql/Pool/ExtendedSpec.hs @@ -0,0 +1,70 @@ +-- This file is part of the Wire Server implementation. +-- +-- Copyright (C) 2026 Wire Swiss GmbH +-- +-- This program is free software: you can redistribute it and/or modify it under +-- the terms of the GNU Affero General Public License as published by the Free +-- Software Foundation, either version 3 of the License, or (at your option) any +-- later version. +-- +-- This program is distributed in the hope that it will be useful, but WITHOUT +-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +-- details. +-- +-- You should have received a copy of the GNU Affero General Public License along +-- with this program. If not, see . + +module Test.Hasql.Pool.ExtendedSpec where + +import Control.Exception (try) +import Data.Map qualified as Map +import Hasql.Pool.Extended (runConnStrParser) +import Imports +import PostgresqlConnectionString qualified +import System.IO.Error (ioeGetErrorString) +import Test.Hspec + +spec :: Spec +spec = + describe "runConnStrParser / fromKeyValueParams" $ do + it "parses a valid key/value connection string" $ do + let params = + Map.fromList + [ ("host", "localhost"), + ("port", "5432"), + ("dbname", "wire-server"), + ("user", "wire") + ] + connStr <- runConnStrParser $ PostgresqlConnectionString.fromKeyValueParams params + PostgresqlConnectionString.toUrl connStr `shouldBe` "postgresql://wire@localhost:5432/wire-server" + + it "applies a single port to every host" $ do + let params = + Map.fromList + [ ("host", "IP1,IP2,IP3"), + ("port", "5000") + ] + connStr <- runConnStrParser $ PostgresqlConnectionString.fromKeyValueParams params + PostgresqlConnectionString.toUrl connStr `shouldBe` "postgresql://IP1:5000,IP2:5000,IP3:5000" + + it "applies a single port to every host and keeps the dbname" $ do + let params = + Map.fromList + [ ("host", "IP1,IP2,IP3"), + ("port", "5000"), + ("dbname", "wire-server") + ] + connStr <- runConnStrParser $ PostgresqlConnectionString.fromKeyValueParams params + PostgresqlConnectionString.toUrl connStr `shouldBe` "postgresql://IP1:5000,IP2:5000,IP3:5000/wire-server" + + it "surfaces a mismatched host/port count as an exception with the parse error" $ do + let params = + Map.fromList + [ ("host", "host1,host2,host3"), + ("port", "5432,5433") + ] + result <- try @IOException $ runConnStrParser (PostgresqlConnectionString.fromKeyValueParams params) + case result of + Left e -> ioeGetErrorString e `shouldBe` "could not match 2 port numbers to 3 hosts" + Right _ -> expectationFailure "expected a parse failure" diff --git a/libs/galley-types/src/Galley/Types/Error.hs b/libs/galley-types/src/Galley/Types/Error.hs index 51a7223c868..2c63d7fa28a 100644 --- a/libs/galley-types/src/Galley/Types/Error.hs +++ b/libs/galley-types/src/Galley/Types/Error.hs @@ -42,7 +42,7 @@ data InternalError | NoPrekeyForUser | CannotCreateManagedConv | InternalErrorWithDescription LText - deriving (Eq) + deriving (Eq, Show) internalErrorDescription :: InternalError -> LText internalErrorDescription = message . internalErrorToWai diff --git a/libs/types-common/src/Data/Id.hs b/libs/types-common/src/Data/Id.hs index d9d7156640e..7157f8f334c 100644 --- a/libs/types-common/src/Data/Id.hs +++ b/libs/types-common/src/Data/Id.hs @@ -42,6 +42,7 @@ module Data.Id idToText, idToString, invitationIdToUserId, + userIdToInvitationId, idObjectSchema, IdObject (..), @@ -107,6 +108,10 @@ import Test.QuickCheck.Instances () invitationIdToUserId :: InvitationId -> UserId invitationIdToUserId = Id . toUUID +-- | Pending invitation users reuse the invitation UUID as the user UUID. +userIdToInvitationId :: UserId -> InvitationId +userIdToInvitationId = Id . toUUID + data IdTag = Asset | Conversation diff --git a/libs/wire-api-federation/src/Wire/API/Federation/API.hs b/libs/wire-api-federation/src/Wire/API/Federation/API.hs index 704d8a3a0a0..552783fb69a 100644 --- a/libs/wire-api-federation/src/Wire/API/Federation/API.hs +++ b/libs/wire-api-federation/src/Wire/API/Federation/API.hs @@ -34,6 +34,10 @@ module Wire.API.Federation.API -- * Re-exports Component (..), makeConversationUpdateBundle, + makeSystemMemberUpdateBundle, + makeSystemDeleteBundle, + makeSystemAdminlessReminderBundle, + makeAdminlessReminderBundle, ) where diff --git a/libs/wire-api-federation/src/Wire/API/Federation/API/Galley/Notifications.hs b/libs/wire-api-federation/src/Wire/API/Federation/API/Galley/Notifications.hs index 9fa5cd6b8f4..f02f1fdf7a6 100644 --- a/libs/wire-api-federation/src/Wire/API/Federation/API/Galley/Notifications.hs +++ b/libs/wire-api-federation/src/Wire/API/Federation/API/Galley/Notifications.hs @@ -32,6 +32,7 @@ import Imports import Servant.API import Wire.API.Conversation import Wire.API.Conversation.Action +import Wire.API.Event.Conversation (AdminlessReminder, MemberUpdateData) import Wire.API.Federation.Component import Wire.API.Federation.Endpoint import Wire.API.Federation.HasNotificationEndpoint @@ -49,6 +50,10 @@ data GalleyNotificationTag | OnConversationUpdatedTagV0 | OnConversationUpdatedTag | OnUserDeletedConversationsTag + | OnSystemMemberUpdateTag + | OnSystemDeleteTag + | OnAdminlessReminderTag + | OnSystemAdminlessReminderTag deriving (Show, Eq, Generic, Bounded, Enum) instance IsNotificationTag GalleyNotificationTag where @@ -85,6 +90,26 @@ instance HasNotificationEndpoint 'OnUserDeletedConversationsTag where type Payload 'OnUserDeletedConversationsTag = UserDeletedConversationsNotification type NotificationPath 'OnUserDeletedConversationsTag = "on-user-deleted-conversations" +instance HasNotificationEndpoint 'OnSystemMemberUpdateTag where + type Payload 'OnSystemMemberUpdateTag = SystemMemberUpdateNotification + type NotificationPath 'OnSystemMemberUpdateTag = "on-conversation-system-member-update" + type NotificationMods 'OnSystemMemberUpdateTag = '[From 'V4] + +instance HasNotificationEndpoint 'OnSystemDeleteTag where + type Payload 'OnSystemDeleteTag = SystemDeleteNotification + type NotificationPath 'OnSystemDeleteTag = "on-conversation-system-delete" + type NotificationMods 'OnSystemDeleteTag = '[From 'V4] + +instance HasNotificationEndpoint 'OnSystemAdminlessReminderTag where + type Payload 'OnSystemAdminlessReminderTag = SystemAdminlessReminderNotification + type NotificationPath 'OnSystemAdminlessReminderTag = "on-conversation-system-adminless-reminder" + type NotificationMods 'OnSystemAdminlessReminderTag = '[From 'V4] + +instance HasNotificationEndpoint 'OnAdminlessReminderTag where + type Payload 'OnAdminlessReminderTag = AdminlessReminderNotification + type NotificationPath 'OnAdminlessReminderTag = "on-conversation-adminless-reminder" + type NotificationMods 'OnAdminlessReminderTag = '[From 'V4] + -- | All the notification endpoints return an 'EmptyResponse'. type GalleyNotificationAPI = NotificationFedEndpoint 'OnClientRemovedTag @@ -93,6 +118,10 @@ type GalleyNotificationAPI = :<|> NotificationFedEndpoint 'OnConversationUpdatedTagV0 :<|> NotificationFedEndpoint 'OnConversationUpdatedTag :<|> NotificationFedEndpoint 'OnUserDeletedConversationsTag + :<|> NotificationFedEndpoint 'OnSystemMemberUpdateTag + :<|> NotificationFedEndpoint 'OnSystemDeleteTag + :<|> NotificationFedEndpoint 'OnAdminlessReminderTag + :<|> NotificationFedEndpoint 'OnSystemAdminlessReminderTag data ClientRemovedRequest = ClientRemovedRequest { user :: UserId, @@ -190,6 +219,54 @@ instance FromJSON ConversationUpdate instance ToSchema ConversationUpdate +data SystemMemberUpdateNotification = SystemMemberUpdateNotification + { time :: UTCTime, + conversation :: ConvId, + update :: MemberUpdateData, + alreadyPresentUsers :: [UserId] + } + deriving stock (Eq, Show, Generic) + deriving (Arbitrary) via (GenericUniform SystemMemberUpdateNotification) + deriving (ToJSON, FromJSON) via (CustomEncoded SystemMemberUpdateNotification) + +instance ToSchema SystemMemberUpdateNotification + +data SystemDeleteNotification = SystemDeleteNotification + { time :: UTCTime, + conversation :: ConvId, + alreadyPresentUsers :: [UserId] + } + deriving stock (Eq, Show, Generic) + deriving (Arbitrary) via (GenericUniform SystemDeleteNotification) + deriving (ToJSON, FromJSON) via (CustomEncoded SystemDeleteNotification) + +instance ToSchema SystemDeleteNotification + +data SystemAdminlessReminderNotification = SystemAdminlessReminderNotification + { time :: UTCTime, + conversation :: ConvId, + reminder :: AdminlessReminder, + alreadyPresentUsers :: [UserId] + } + deriving stock (Eq, Show, Generic) + deriving (Arbitrary) via (GenericUniform SystemAdminlessReminderNotification) + deriving (ToJSON, FromJSON) via (CustomEncoded SystemAdminlessReminderNotification) + +instance ToSchema SystemAdminlessReminderNotification + +data AdminlessReminderNotification = AdminlessReminderNotification + { time :: UTCTime, + conversation :: ConvId, + origUserId :: Qualified UserId, + reminder :: AdminlessReminder, + alreadyPresentUsers :: [UserId] + } + deriving stock (Eq, Show, Generic) + deriving (Arbitrary) via (GenericUniform AdminlessReminderNotification) + deriving (ToJSON, FromJSON) via (CustomEncoded AdminlessReminderNotification) + +instance ToSchema AdminlessReminderNotification + conversationUpdateToV0 :: ConversationUpdate -> ConversationUpdateV0 conversationUpdateToV0 cu = ConversationUpdateV0 diff --git a/libs/wire-api-federation/src/Wire/API/Federation/API/Util.hs b/libs/wire-api-federation/src/Wire/API/Federation/API/Util.hs index d855c2abb01..fbcf1facb14 100644 --- a/libs/wire-api-federation/src/Wire/API/Federation/API/Util.hs +++ b/libs/wire-api-federation/src/Wire/API/Federation/API/Util.hs @@ -27,3 +27,19 @@ makeConversationUpdateBundle :: FedQueueClient 'Galley (PayloadBundle 'Galley) makeConversationUpdateBundle update = (<>) <$> makeBundle update <*> makeBundle (conversationUpdateToV0 update) + +makeSystemMemberUpdateBundle :: SystemMemberUpdateNotification -> FedQueueClient 'Galley (PayloadBundle 'Galley) +makeSystemMemberUpdateBundle = + fmap (\bundle -> bundle {unsupportedVersionPolicy = DropIfUnsupported}) . makeBundle @'OnSystemMemberUpdateTag + +makeSystemDeleteBundle :: SystemDeleteNotification -> FedQueueClient 'Galley (PayloadBundle 'Galley) +makeSystemDeleteBundle = + fmap (\bundle -> bundle {unsupportedVersionPolicy = DropIfUnsupported}) . makeBundle @'OnSystemDeleteTag + +makeSystemAdminlessReminderBundle :: SystemAdminlessReminderNotification -> FedQueueClient 'Galley (PayloadBundle 'Galley) +makeSystemAdminlessReminderBundle = + fmap (\bundle -> bundle {unsupportedVersionPolicy = DropIfUnsupported}) . makeBundle @'OnSystemAdminlessReminderTag + +makeAdminlessReminderBundle :: AdminlessReminderNotification -> FedQueueClient 'Galley (PayloadBundle 'Galley) +makeAdminlessReminderBundle = + fmap (\bundle -> bundle {unsupportedVersionPolicy = DropIfUnsupported}) . makeBundle @'OnAdminlessReminderTag diff --git a/libs/wire-api-federation/src/Wire/API/Federation/BackendNotifications.hs b/libs/wire-api-federation/src/Wire/API/Federation/BackendNotifications.hs index ac1e0e03cd9..9e80eafe1ff 100644 --- a/libs/wire-api-federation/src/Wire/API/Federation/BackendNotifications.hs +++ b/libs/wire-api-federation/src/Wire/API/Federation/BackendNotifications.hs @@ -36,6 +36,7 @@ import Network.AMQP qualified as Q import Network.AMQP.Types qualified as Q import Servant import Servant.Client.Core +import Test.QuickCheck (Arbitrary (arbitrary), elements) import Wire.API.Federation.API.Common import Wire.API.Federation.Client import Wire.API.Federation.Component @@ -75,6 +76,29 @@ instance ToSchema BackendNotification where <*> bodyVersions .= maybe_ (optField "bodyVersions" schema) <*> (.requestId) .= maybe_ (optField "requestId" schema) +data UnsupportedVersionPolicy + = KeepQueued + | DropIfUnsupported + deriving stock (Eq, Show) + deriving (A.ToJSON, A.FromJSON) via (Schema UnsupportedVersionPolicy) + +instance Arbitrary UnsupportedVersionPolicy where + arbitrary = elements [KeepQueued, DropIfUnsupported] + +instance ToSchema UnsupportedVersionPolicy where + schema = + enum @Text $ + mconcat + [ element "keep_queued" KeepQueued, + element "drop_if_unsupported" DropIfUnsupported + ] + +-- Keeping the notification queued is the safe choice if representations +-- configured with different policies are accidentally combined. +instance Semigroup UnsupportedVersionPolicy where + DropIfUnsupported <> DropIfUnsupported = DropIfUnsupported + _ <> _ = KeepQueued + -- | Convert a federation endpoint to a backend notification to be enqueued to a -- RabbitMQ queue. fedNotifToBackendNotif :: @@ -104,17 +128,29 @@ fedNotifToBackendNotif rid ownDomain payload = requestId = Just rid } -newtype PayloadBundle (c :: Component) = PayloadBundle - { notifications :: NE.NonEmpty BackendNotification +data PayloadBundle (c :: Component) = PayloadBundle + { notifications :: NE.NonEmpty BackendNotification, + unsupportedVersionPolicy :: UnsupportedVersionPolicy } deriving (A.ToJSON, A.FromJSON) via (Schema (PayloadBundle c)) - deriving newtype (Semigroup) + deriving stock (Eq, Show) + +instance Semigroup (PayloadBundle c) where + bundle1 <> bundle2 = + PayloadBundle + { notifications = bundle1.notifications <> bundle2.notifications, + unsupportedVersionPolicy = bundle1.unsupportedVersionPolicy <> bundle2.unsupportedVersionPolicy + } instance (Typeable c) => ToSchema (PayloadBundle c) where schema = object $ PayloadBundle <$> notifications .= field "notifications" (nonEmptyArray schema) + <*> unsupportedVersionPolicy + .= fmap + (fromMaybe KeepQueued) + (optField "unsupportedVersionPolicy" schema) toBundle :: forall {k} (tag :: k). @@ -130,7 +166,10 @@ toBundle :: PayloadBundle (NotificationComponent k) toBundle reqId originDomain payload = let notif = fedNotifToBackendNotif @tag reqId originDomain payload - in PayloadBundle . pure $ notif + in PayloadBundle + { notifications = pure notif, + unsupportedVersionPolicy = KeepQueued + } makeBundle :: forall {k} (tag :: k) c. diff --git a/libs/wire-api-federation/src/Wire/API/Federation/HasNotificationEndpoint.hs b/libs/wire-api-federation/src/Wire/API/Federation/HasNotificationEndpoint.hs index cbc16a0d769..63410850c85 100644 --- a/libs/wire-api-federation/src/Wire/API/Federation/HasNotificationEndpoint.hs +++ b/libs/wire-api-federation/src/Wire/API/Federation/HasNotificationEndpoint.hs @@ -21,6 +21,7 @@ module Wire.API.Federation.HasNotificationEndpoint HasFedPath, HasVersionRange, fedPath, + supportsNotificationVersion, versionRange, ) where @@ -90,3 +91,6 @@ instance {-# OVERLAPPABLE #-} (MkVersionRange mods) => MkVersionRange (m ': mods -- | The federation API version range this endpoint is supported in. versionRange :: forall t. (HasVersionRange t) => VersionRange versionRange = mkVersionRange @(NotificationMods t) + +supportsNotificationVersion :: forall t. (HasVersionRange t) => VersionInfo -> Bool +supportsNotificationVersion = supportsVersionRange (versionRange @t) diff --git a/libs/wire-api-federation/src/Wire/API/Federation/Version.hs b/libs/wire-api-federation/src/Wire/API/Federation/Version.hs index 5e2f016901a..f9a6136f393 100644 --- a/libs/wire-api-federation/src/Wire/API/Federation/Version.hs +++ b/libs/wire-api-federation/src/Wire/API/Federation/Version.hs @@ -24,9 +24,11 @@ module Wire.API.Federation.Version V1Sym0, V2Sym0, V3Sym0, + V4Sym0, intToVersion, versionInt, versionText, + supportsVersionRange, supportedVersions, VersionInfo (..), versionInfo, @@ -54,7 +56,7 @@ import Imports import Servant.API (ToHttpApiData (..)) import Wire.API.MLS.Group.Serialisation -data Version = V0 | V1 | V2 | V3 +data Version = V0 | V1 | V2 | V3 | V4 deriving stock (Eq, Ord, Bounded, Enum, Show, Generic) deriving (FromJSON, ToJSON) via (Schema Version) @@ -67,15 +69,19 @@ versionInt V0 = 0 versionInt V1 = 1 versionInt V2 = 2 versionInt V3 = 3 +versionInt V4 = 4 versionText :: Version -> Text versionText = ("v" <>) . Text.pack . show . versionInt +supportsVersionRange :: VersionRange -> VersionInfo -> Bool +supportsVersionRange range = any (maybe False (inVersionRange range) . intToVersion) . (.vinfoSupported) + versionByteString :: Version -> ByteString versionByteString = ("v" <>) . BS.pack . show . versionInt intToVersion :: Int -> Maybe Version -intToVersion intV = find (\v -> versionInt v == intV) [minBound ..] +intToVersion intV = find (\v -> versionInt v == intV) [minBound .. maxBound] instance ToSchema Version where schema = @@ -83,7 +89,8 @@ instance ToSchema Version where [ element 0 V0, element 1 V1, element 2 V2, - element 3 V3 + element 3 V3, + element 4 V4 ] supportedVersions :: Set Version diff --git a/libs/wire-api-federation/test/Test/Wire/API/Federation/API/BackendNotificationsSpec.hs b/libs/wire-api-federation/test/Test/Wire/API/Federation/API/BackendNotificationsSpec.hs new file mode 100644 index 00000000000..2bb12c26503 --- /dev/null +++ b/libs/wire-api-federation/test/Test/Wire/API/Federation/API/BackendNotificationsSpec.hs @@ -0,0 +1,28 @@ +-- This file is part of the Wire Server implementation. +-- +-- Copyright (C) 2026 Wire Swiss GmbH +-- +-- This program is free software: you can redistribute it and/or modify it under +-- the terms of the GNU Affero General Public License as published by the Free +-- Software Foundation, either version 3 of the License, or (at your option) +-- any later version. +-- +-- This program is distributed in the hope that it will be useful, but WITHOUT +-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +-- details. +-- +-- You should have received a copy of the GNU Affero General Public License along +-- with this program. If not, see . + +module Test.Wire.API.Federation.API.BackendNotificationsSpec where + +import Imports +import Test.Hspec +import Test.Wire.API.Federation.API.Util (jsonRoundTrip) +import Wire.API.Federation.BackendNotifications (UnsupportedVersionPolicy (..)) + +spec :: Spec +spec = describe "UnsupportedVersionPolicy" $ do + describe "roundtrip" $ do + jsonRoundTrip @UnsupportedVersionPolicy diff --git a/libs/wire-api-federation/test/Test/Wire/API/Federation/Golden/GoldenSpec.hs b/libs/wire-api-federation/test/Test/Wire/API/Federation/Golden/GoldenSpec.hs index 038f98b0d1e..80be3edb0a1 100644 --- a/libs/wire-api-federation/test/Test/Wire/API/Federation/Golden/GoldenSpec.hs +++ b/libs/wire-api-federation/test/Test/Wire/API/Federation/Golden/GoldenSpec.hs @@ -29,6 +29,7 @@ import Test.Wire.API.Federation.Golden.MessageSendResponse qualified as MessageS import Test.Wire.API.Federation.Golden.NewConnectionRequest qualified as NewConnectionRequest import Test.Wire.API.Federation.Golden.NewConnectionResponse qualified as NewConnectionResponse import Test.Wire.API.Federation.Golden.Runner (testObjects) +import Test.Wire.API.Federation.Golden.UnsupportedVersionPolicy qualified as UnsupportedVersionPolicy spec :: Spec spec = @@ -85,3 +86,7 @@ spec = (GetOne2OneConversationResponse.testObject_GetOne2OneConversationResponseBackendMismatch, "testObject_GetOne2OneConversationResponseBackendMismatch.json"), (GetOne2OneConversationResponse.testObject_GetOne2OneConversationResponseNotConnected, "testObject_GetOne2OneConversationResponseNotConnected.json") ] + testObjects + [ (UnsupportedVersionPolicy.testObjectUnsupportedVersionPolicyKeepQueued, "testObject_UnsupportedVersionPolicy_KeepQueued.json"), + (UnsupportedVersionPolicy.testObjectUnsupportedVersionPolicyDropIfUnsupported, "testObject_UnsupportedVersionPolicy_DropIfUnsupported.json") + ] diff --git a/libs/wire-api-federation/test/Test/Wire/API/Federation/Golden/UnsupportedVersionPolicy.hs b/libs/wire-api-federation/test/Test/Wire/API/Federation/Golden/UnsupportedVersionPolicy.hs new file mode 100644 index 00000000000..bd868c808d7 --- /dev/null +++ b/libs/wire-api-federation/test/Test/Wire/API/Federation/Golden/UnsupportedVersionPolicy.hs @@ -0,0 +1,26 @@ +-- This file is part of the Wire Server implementation. +-- +-- Copyright (C) 2026 Wire Swiss GmbH +-- +-- This program is free software: you can redistribute it and/or modify it under +-- the terms of the GNU Affero General Public License as published by the Free +-- Software Foundation, either version 3 of the License, or (at your option) any +-- later version. +-- +-- This program is distributed in the hope that it will be useful, but WITHOUT +-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +-- details. +-- +-- You should have received a copy of the GNU Affero General Public License along +-- with this program. If not, see . + +module Test.Wire.API.Federation.Golden.UnsupportedVersionPolicy where + +import Wire.API.Federation.BackendNotifications (UnsupportedVersionPolicy (..)) + +testObjectUnsupportedVersionPolicyKeepQueued :: UnsupportedVersionPolicy +testObjectUnsupportedVersionPolicyKeepQueued = KeepQueued + +testObjectUnsupportedVersionPolicyDropIfUnsupported :: UnsupportedVersionPolicy +testObjectUnsupportedVersionPolicyDropIfUnsupported = DropIfUnsupported diff --git a/libs/wire-api-federation/test/golden/testObject_UnsupportedVersionPolicy_DropIfUnsupported.json b/libs/wire-api-federation/test/golden/testObject_UnsupportedVersionPolicy_DropIfUnsupported.json new file mode 100644 index 00000000000..ae02d02074a --- /dev/null +++ b/libs/wire-api-federation/test/golden/testObject_UnsupportedVersionPolicy_DropIfUnsupported.json @@ -0,0 +1 @@ +"drop_if_unsupported" diff --git a/libs/wire-api-federation/test/golden/testObject_UnsupportedVersionPolicy_KeepQueued.json b/libs/wire-api-federation/test/golden/testObject_UnsupportedVersionPolicy_KeepQueued.json new file mode 100644 index 00000000000..82b45e1fb25 --- /dev/null +++ b/libs/wire-api-federation/test/golden/testObject_UnsupportedVersionPolicy_KeepQueued.json @@ -0,0 +1 @@ +"keep_queued" diff --git a/libs/wire-api-federation/wire-api-federation.cabal b/libs/wire-api-federation/wire-api-federation.cabal index a451e2f01c0..5bb39296c38 100644 --- a/libs/wire-api-federation/wire-api-federation.cabal +++ b/libs/wire-api-federation/wire-api-federation.cabal @@ -135,6 +135,7 @@ test-suite spec -- cabal-fmt: expand test other-modules: Main + Test.Wire.API.Federation.API.BackendNotificationsSpec Test.Wire.API.Federation.API.BrigSpec Test.Wire.API.Federation.API.GalleySpec Test.Wire.API.Federation.API.Util @@ -149,6 +150,7 @@ test-suite spec Test.Wire.API.Federation.Golden.NewConnectionRequest Test.Wire.API.Federation.Golden.NewConnectionResponse Test.Wire.API.Federation.Golden.Runner + Test.Wire.API.Federation.Golden.UnsupportedVersionPolicy hs-source-dirs: test default-extensions: diff --git a/libs/wire-api/src/Wire/API/PostgresMarshall.hs b/libs/wire-api/src/Wire/API/PostgresMarshall.hs index e1a6f55f18d..24ff507ec27 100644 --- a/libs/wire-api/src/Wire/API/PostgresMarshall.hs +++ b/libs/wire-api/src/Wire/API/PostgresMarshall.hs @@ -521,6 +521,9 @@ instance (PostgresMarshall a1 b1, PostgresMarshall a2 b2, PostgresMarshall a3 b3 instance (PostgresMarshall a1 b1, PostgresMarshall a2 b2, PostgresMarshall a3 b3, PostgresMarshall a4 b4, PostgresMarshall a5 b5, PostgresMarshall a6 b6, PostgresMarshall a7 b7, PostgresMarshall a8 b8, PostgresMarshall a9 b9, PostgresMarshall a10 b10, PostgresMarshall a11 b11, PostgresMarshall a12 b12, PostgresMarshall a13 b13, PostgresMarshall a14 b14, PostgresMarshall a15 b15, PostgresMarshall a16 b16, PostgresMarshall a17 b17, PostgresMarshall a18 b18, PostgresMarshall a19 b19, PostgresMarshall a20 b20, PostgresMarshall a21 b21, PostgresMarshall a22 b22, PostgresMarshall a23 b23, PostgresMarshall a24 b24) => PostgresMarshall (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24) (b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19, b20, b21, b22, b23, b24) where postgresMarshall (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24) = (postgresMarshall a1, postgresMarshall a2, postgresMarshall a3, postgresMarshall a4, postgresMarshall a5, postgresMarshall a6, postgresMarshall a7, postgresMarshall a8, postgresMarshall a9, postgresMarshall a10, postgresMarshall a11, postgresMarshall a12, postgresMarshall a13, postgresMarshall a14, postgresMarshall a15, postgresMarshall a16, postgresMarshall a17, postgresMarshall a18, postgresMarshall a19, postgresMarshall a20, postgresMarshall a21, postgresMarshall a22, postgresMarshall a23, postgresMarshall a24) +instance (PostgresMarshall a1 b1, PostgresMarshall a2 b2, PostgresMarshall a3 b3, PostgresMarshall a4 b4, PostgresMarshall a5 b5, PostgresMarshall a6 b6, PostgresMarshall a7 b7, PostgresMarshall a8 b8, PostgresMarshall a9 b9, PostgresMarshall a10 b10, PostgresMarshall a11 b11, PostgresMarshall a12 b12, PostgresMarshall a13 b13, PostgresMarshall a14 b14, PostgresMarshall a15 b15, PostgresMarshall a16 b16, PostgresMarshall a17 b17, PostgresMarshall a18 b18, PostgresMarshall a19 b19, PostgresMarshall a20 b20, PostgresMarshall a21 b21, PostgresMarshall a22 b22, PostgresMarshall a23 b23, PostgresMarshall a24 b24, PostgresMarshall a25 b25) => PostgresMarshall (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25) (b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19, b20, b21, b22, b23, b24, b25) where + postgresMarshall (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25) = (postgresMarshall a1, postgresMarshall a2, postgresMarshall a3, postgresMarshall a4, postgresMarshall a5, postgresMarshall a6, postgresMarshall a7, postgresMarshall a8, postgresMarshall a9, postgresMarshall a10, postgresMarshall a11, postgresMarshall a12, postgresMarshall a13, postgresMarshall a14, postgresMarshall a15, postgresMarshall a16, postgresMarshall a17, postgresMarshall a18, postgresMarshall a19, postgresMarshall a20, postgresMarshall a21, postgresMarshall a22, postgresMarshall a23, postgresMarshall a24, postgresMarshall a25) + instance PostgresMarshall UUID (Id a) where postgresMarshall = toUUID @@ -989,6 +992,35 @@ instance (PostgresUnmarshall a1 b1, PostgresUnmarshall a2 b2, PostgresUnmarshall <*> postgresUnmarshall a23 <*> postgresUnmarshall a24 +instance (PostgresUnmarshall a1 b1, PostgresUnmarshall a2 b2, PostgresUnmarshall a3 b3, PostgresUnmarshall a4 b4, PostgresUnmarshall a5 b5, PostgresUnmarshall a6 b6, PostgresUnmarshall a7 b7, PostgresUnmarshall a8 b8, PostgresUnmarshall a9 b9, PostgresUnmarshall a10 b10, PostgresUnmarshall a11 b11, PostgresUnmarshall a12 b12, PostgresUnmarshall a13 b13, PostgresUnmarshall a14 b14, PostgresUnmarshall a15 b15, PostgresUnmarshall a16 b16, PostgresUnmarshall a17 b17, PostgresUnmarshall a18 b18, PostgresUnmarshall a19 b19, PostgresUnmarshall a20 b20, PostgresUnmarshall a21 b21, PostgresUnmarshall a22 b22, PostgresUnmarshall a23 b23, PostgresUnmarshall a24 b24, PostgresUnmarshall a25 b25) => PostgresUnmarshall (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25) (b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19, b20, b21, b22, b23, b24, b25) where + postgresUnmarshall (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25) = + (,,,,,,,,,,,,,,,,,,,,,,,,) + <$> postgresUnmarshall a1 + <*> postgresUnmarshall a2 + <*> postgresUnmarshall a3 + <*> postgresUnmarshall a4 + <*> postgresUnmarshall a5 + <*> postgresUnmarshall a6 + <*> postgresUnmarshall a7 + <*> postgresUnmarshall a8 + <*> postgresUnmarshall a9 + <*> postgresUnmarshall a10 + <*> postgresUnmarshall a11 + <*> postgresUnmarshall a12 + <*> postgresUnmarshall a13 + <*> postgresUnmarshall a14 + <*> postgresUnmarshall a15 + <*> postgresUnmarshall a16 + <*> postgresUnmarshall a17 + <*> postgresUnmarshall a18 + <*> postgresUnmarshall a19 + <*> postgresUnmarshall a20 + <*> postgresUnmarshall a21 + <*> postgresUnmarshall a22 + <*> postgresUnmarshall a23 + <*> postgresUnmarshall a24 + <*> postgresUnmarshall a25 + instance PostgresUnmarshall UUID (Id a) where postgresUnmarshall = Right . Id diff --git a/libs/wire-api/src/Wire/API/Routes/Internal/Spar.hs b/libs/wire-api/src/Wire/API/Routes/Internal/Spar.hs index e2a23c2d1c1..31233e07bda 100644 --- a/libs/wire-api/src/Wire/API/Routes/Internal/Spar.hs +++ b/libs/wire-api/src/Wire/API/Routes/Internal/Spar.hs @@ -32,6 +32,7 @@ type InternalAPI = "i" :> ( Named "i_status" ("status" :> Get '[JSON] NoContent) :<|> Named "i_delete_team" ("teams" :> Capture "team" TeamId :> DeleteNoContent) + :<|> Named "i_delete_scim_user" ("scim" :> "users" :> Capture "team" TeamId :> Capture "user" UserId :> DeleteNoContent) :<|> Named "i_put_sso_settings" ("sso" :> "settings" :> ReqBody '[JSON] SsoSettings :> Put '[JSON] NoContent) :<|> Named "i_post_scim_user_info" ("scim" :> "userinfo" :> Capture "user" UserId :> Post '[JSON] ScimUserInfo) :<|> Named "i_get_identity_providers" ("identity-providers" :> Capture "team" TeamId :> Get '[JSON] IdPList) diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Swagger.hs b/libs/wire-api/src/Wire/API/Routes/Public/Swagger.hs index 63791ced758..9a822b51711 100644 --- a/libs/wire-api/src/Wire/API/Routes/Public/Swagger.hs +++ b/libs/wire-api/src/Wire/API/Routes/Public/Swagger.hs @@ -48,7 +48,7 @@ import Wire.API.SwaggerHelper (cleanupSwagger) -- 'S.OpenApi' has to be assembled at a statically known version. devVersion :: Version devVersion = - if maxBound == V18 + if maxBound == V19 then maxBound else -- if you get this error, you also need to update the version literals below. @@ -60,15 +60,15 @@ devVersion = -- @info.description@, so setting it afterwards is equivalent. devVersionSwagger :: S.OpenApi devVersionSwagger = - ( serviceSwagger @VersionAPITag @'V18 - <> serviceSwagger @BrigAPITag @'V18 - <> serviceSwagger @GalleyAPITag @'V18 - <> serviceSwagger @SparAPITag @'V18 - <> serviceSwagger @CargoholdAPITag @'V18 - <> serviceSwagger @CannonAPITag @'V18 - <> serviceSwagger @GundeckAPITag @'V18 - <> serviceSwagger @ProxyAPITag @'V18 - <> serviceSwagger @OAuthAPITag @'V18 + ( serviceSwagger @VersionAPITag @'V19 + <> serviceSwagger @BrigAPITag @'V19 + <> serviceSwagger @GalleyAPITag @'V19 + <> serviceSwagger @SparAPITag @'V19 + <> serviceSwagger @CargoholdAPITag @'V19 + <> serviceSwagger @CannonAPITag @'V19 + <> serviceSwagger @GundeckAPITag @'V19 + <> serviceSwagger @ProxyAPITag @'V19 + <> serviceSwagger @OAuthAPITag @'V19 ) & S.info . S.title .~ "Wire-Server API" & S.servers .~ [S.Server ("/" <> toUrlPiece devVersion) Nothing mempty] diff --git a/libs/wire-api/src/Wire/API/Routes/Version.hs b/libs/wire-api/src/Wire/API/Routes/Version.hs index 119c62b3dfa..f360467b700 100644 --- a/libs/wire-api/src/Wire/API/Routes/Version.hs +++ b/libs/wire-api/src/Wire/API/Routes/Version.hs @@ -103,7 +103,7 @@ import Wire.Arbitrary (Arbitrary, GenericUniform (GenericUniform)) -- and 'developmentVersions' stay in sync; everything else here should keep working without -- change. See also documentation in the *docs* directory. -- https://docs.wire.com/developer/developer/api-versioning.html#version-bump-checklist -data Version = V0 | V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 | V11 | V12 | V13 | V14 | V15 | V16 | V17 | V18 +data Version = V0 | V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 | V11 | V12 | V13 | V14 | V15 | V16 | V17 | V18 | V19 deriving stock (Eq, Ord, Bounded, Enum, Show, Generic) deriving (FromJSON, ToJSON) via (Schema Version) deriving (Arbitrary) via (GenericUniform Version) @@ -144,6 +144,8 @@ instance RenderableSymbol V17 where renderSymbol = "V17" instance RenderableSymbol V18 where renderSymbol = "V18" +instance RenderableSymbol V19 where renderSymbol = "V19" + -- | Manual enumeration of version integrals (the `` in the constructor `V`). -- -- This is not the same as 'fromEnum': we will remove unsupported versions in the future, @@ -170,6 +172,7 @@ versionInt V15 = 15 versionInt V16 = 16 versionInt V17 = 17 versionInt V18 = 18 +versionInt V19 = 19 supportedVersions :: [Version] supportedVersions = [minBound .. maxBound] @@ -295,7 +298,8 @@ isDevelopmentVersion V14 = False isDevelopmentVersion V15 = False isDevelopmentVersion V16 = False isDevelopmentVersion V17 = False -isDevelopmentVersion V18 = True +isDevelopmentVersion V18 = False +isDevelopmentVersion V19 = True developmentVersions :: [Version] developmentVersions = filter isDevelopmentVersion supportedVersions diff --git a/libs/wire-api/src/Wire/API/SystemSettings.hs b/libs/wire-api/src/Wire/API/SystemSettings.hs index b41a17acc59..a0ce3c67a76 100644 --- a/libs/wire-api/src/Wire/API/SystemSettings.hs +++ b/libs/wire-api/src/Wire/API/SystemSettings.hs @@ -56,7 +56,8 @@ settingsPublicObjectSchema = ) data SystemSettingsInternal = SystemSettingsInternal - { ssiSetEnableMls :: !Bool + { ssiSetEnableMls :: !Bool, + ssiSetSsoIdpChangeDetectionEnabled :: !Bool } deriving (Eq, Show, Generic) deriving (A.ToJSON, A.FromJSON, S.ToSchema) via Schema SystemSettingsInternal @@ -70,6 +71,14 @@ settingsInternalObjectSchema :: ObjectSchema SwaggerDoc SystemSettingsInternal settingsInternalObjectSchema = SystemSettingsInternal <$> ssiSetEnableMls .= fieldWithDocModifier "setEnableMls" (description ?~ "Whether MLS is enabled or not") schema + <*> ssiSetSsoIdpChangeDetectionEnabled + .= fieldWithDocModifier + "ssoIdpChangeDetectionEnabled" + ( description + ?~ "Whether clients should compare the stored SSO IdP ID with the IdP ID of the current \ + \login and keep existing locally decrypted messages when they match." + ) + schema data SystemSettings = SystemSettings { ssPublic :: !SystemSettingsPublic, diff --git a/libs/wire-api/src/Wire/API/Team/Feature.hs b/libs/wire-api/src/Wire/API/Team/Feature.hs index 28563253014..eeef0a88b8d 100644 --- a/libs/wire-api/src/Wire/API/Team/Feature.hs +++ b/libs/wire-api/src/Wire/API/Team/Feature.hs @@ -2180,7 +2180,7 @@ instance Default CellsInternalConfig where collabora = CellsCollabora Cool, storage = CellsStorage - { totalLimitBytes = Just $ QuotaBytesFinite $ NumBytes $ BigIntString 1000000000000, -- 1 TB + { totalLimitBytes = Just QuotaBytesUnlimited, perUserQuotaBytes = QuotaBytesUnlimited } } diff --git a/libs/wire-subsystems/postgres-migrations/20260625104559-add-user-migration-pending-deletes.sql b/libs/wire-subsystems/postgres-migrations/20260625104559-add-user-migration-pending-deletes.sql new file mode 100644 index 00000000000..21143117419 --- /dev/null +++ b/libs/wire-subsystems/postgres-migrations/20260625104559-add-user-migration-pending-deletes.sql @@ -0,0 +1,3 @@ +CREATE TABLE user_migration_pending_deletes ( + id uuid PRIMARY KEY + ); diff --git a/libs/wire-subsystems/src/Wire/CodeStore/Migration.hs b/libs/wire-subsystems/src/Wire/CodeStore/Migration.hs index e652c5619a3..49062ebe50f 100644 --- a/libs/wire-subsystems/src/Wire/CodeStore/Migration.hs +++ b/libs/wire-subsystems/src/Wire/CodeStore/Migration.hs @@ -32,12 +32,12 @@ import Hasql.Pool.Extended qualified as Hasql import Imports import Polysemy import Polysemy.Async +import Polysemy.AtomicState import Polysemy.Conc (interpretRace) import Polysemy.Conc qualified as Conc import Polysemy.Conc.Effect.Race hiding (Timeout) import Polysemy.Input import Polysemy.Resource (Resource, bracket, resourceToIOFinal) -import Polysemy.State import Polysemy.TinyLog import Prometheus qualified import System.Logger qualified as Log @@ -53,7 +53,7 @@ import Wire.Sem.Logger (mapLogger) import Wire.Sem.Logger.TinyLog (loggerToTinyLog) type EffectStack = - [ State Int, + [ AtomicState Int, Input ClientState, Input Hasql.Pool, Input (Either HttpsUrl (Map Domain HttpsUrl)), @@ -97,7 +97,7 @@ interpreter cassClient pgPool logger name = . runInputConst (Right mempty) . runInputConst pgPool . runInputConst cassClient - . runState 0 + . atomicStateToIO 0 migrateAllCodes :: ( Member (Input Hasql.Pool) r, @@ -105,7 +105,7 @@ migrateAllCodes :: Member (Embed IO) r, Member (Input ClientState) r, Member TinyLog r, - Member (State Int) r, + Member (AtomicState Int) r, Member Resource r, Member Race r ) => diff --git a/libs/wire-subsystems/src/Wire/ConversationStore/Migration.hs b/libs/wire-subsystems/src/Wire/ConversationStore/Migration.hs index 8c5ddc11bd7..60ab456464e 100644 --- a/libs/wire-subsystems/src/Wire/ConversationStore/Migration.hs +++ b/libs/wire-subsystems/src/Wire/ConversationStore/Migration.hs @@ -43,11 +43,11 @@ import Hasql.Transaction.Sessions import Imports import Polysemy import Polysemy.Async +import Polysemy.AtomicState import Polysemy.Conc hiding (timeout_) import Polysemy.Error import Polysemy.Input import Polysemy.Resource (Resource, resourceToIOFinal) -import Polysemy.State import Polysemy.TinyLog import Prometheus qualified import System.Logger qualified as Log @@ -81,7 +81,7 @@ import Wire.StoredConversation -- * Top level logic type EffectStack = - [ State Int, + [ AtomicState Int, Input ClientState, Input Hasql.Pool, Resource, @@ -144,7 +144,7 @@ interpreter cassClient pgPool logger name = . resourceToIOFinal . runInputConst pgPool . runInputConst cassClient - . runState 0 + . atomicStateToIO 0 migrateAllConversations :: ( Member (Input Hasql.Pool) r, @@ -154,7 +154,7 @@ migrateAllConversations :: Member Async r, Member Race r, Member Resource r, - Member (State Int) r, + Member (AtomicState Int) r, Member (Concurrency Unsafe) r ) => MigrationOptions -> @@ -181,7 +181,7 @@ migrateAllUsers :: Member Async r, Member Race r, Member Resource r, - Member (State Int) r, + Member (AtomicState Int) r, Member (Concurrency 'Unsafe) r ) => MigrationOptions -> @@ -197,11 +197,11 @@ migrateAllUsers migOpts migCounter migDuration = do select :: PrepQuery R () (Identity UserId) select = "select distinct user from user_remote_conv" -handleErrors :: (Member (State Int) r, Member TinyLog r) => (Id a -> Sem (Error MigrationLockError : Error UsageError : r) b) -> ByteString -> Id a -> Sem r (Maybe b) +handleErrors :: (Member (AtomicState Int) r, Member TinyLog r) => (Id a -> Sem (Error MigrationLockError : Error UsageError : r) b) -> ByteString -> Id a -> Sem r (Maybe b) handleErrors action lockType id_ = join <$> handleError (handleError action lockType) lockType id_ -handleError :: (Member (State Int) r, Member TinyLog r, Show e) => (Id a -> Sem (Error e : r) b) -> ByteString -> Id a -> Sem r (Maybe b) +handleError :: (Member (AtomicState Int) r, Member TinyLog r, Show e) => (Id a -> Sem (Error e : r) b) -> ByteString -> Id a -> Sem r (Maybe b) handleError action lockType id_ = do eithErr <- runError (action id_) case eithErr of @@ -211,7 +211,7 @@ handleError action lockType id_ = do Log.msg (Log.val "error occurred during migration") . Log.field lockType (idToText id_) . Log.field "error" (show e) - modify (+ 1) + atomicModify (+ 1) pure Nothing -- * Conversations diff --git a/libs/wire-subsystems/src/Wire/ConversationSubsystem.hs b/libs/wire-subsystems/src/Wire/ConversationSubsystem.hs index 56b01784b8f..89d9267388a 100644 --- a/libs/wire-subsystems/src/Wire/ConversationSubsystem.hs +++ b/libs/wire-subsystems/src/Wire/ConversationSubsystem.hs @@ -304,6 +304,22 @@ data ConversationSubsystem m a where Domain -> ConversationUpdate -> ConversationSubsystem m EmptyResponse + FederationOnSystemMemberUpdate :: + Domain -> + SystemMemberUpdateNotification -> + ConversationSubsystem m EmptyResponse + FederationOnSystemDelete :: + Domain -> + SystemDeleteNotification -> + ConversationSubsystem m EmptyResponse + FederationOnSystemAdminlessReminder :: + Domain -> + SystemAdminlessReminderNotification -> + ConversationSubsystem m EmptyResponse + FederationOnAdminlessReminder :: + Domain -> + AdminlessReminderNotification -> + ConversationSubsystem m EmptyResponse FederationOnUserDeleted :: Domain -> UserDeletedConversationsNotification -> diff --git a/libs/wire-subsystems/src/Wire/ConversationSubsystem/Federation.hs b/libs/wire-subsystems/src/Wire/ConversationSubsystem/Federation.hs index df14feaa080..5cf578c7341 100644 --- a/libs/wire-subsystems/src/Wire/ConversationSubsystem/Federation.hs +++ b/libs/wire-subsystems/src/Wire/ConversationSubsystem/Federation.hs @@ -41,6 +41,7 @@ import Galley.Types.Error import Imports import Network.Wai.Utilities.Exception import Polysemy +import Polysemy.Async (Async) import Polysemy.Error import Polysemy.Input import Polysemy.Internal.Kind (Append) @@ -87,6 +88,7 @@ import Wire.ConversationSubsystem.MLS.SubConversation hiding (leaveSubConversati import Wire.ConversationSubsystem.MLS.Util import Wire.ConversationSubsystem.MLS.Welcome import Wire.ConversationSubsystem.Message +import Wire.ConversationSubsystem.Notify (pushSystemEvent) import Wire.ConversationSubsystem.Util import Wire.ExternalAccess (ExternalAccess) import Wire.FeaturesConfigSubsystem @@ -215,6 +217,130 @@ onConversationUpdated requestingDomain cu = do void $ updateLocalStateOfRemoteConv rcu Nothing pure EmptyResponse +onSystemMemberUpdate :: + ( Member E.ConversationStore r, + Member NotificationSubsystem r, + Member P.TinyLog r + ) => + Domain -> + SystemMemberUpdateNotification -> + Sem r EmptyResponse +onSystemMemberUpdate requestingDomain e = do + localMembers <- filterSystemNotificationRecipients requestingDomain e.conversation e.alreadyPresentUsers + pushSystemEvent + Nothing + ( SystemEvent + (Qualified e.conversation requestingDomain) + Nothing + e.time + Nothing + (EdSystemMemberUpdate e.update) + ) + (Set.fromList localMembers) + pure EmptyResponse + +onSystemDelete :: + ( Member E.ConversationStore r, + Member NotificationSubsystem r, + Member P.TinyLog r + ) => + Domain -> + SystemDeleteNotification -> + Sem r EmptyResponse +onSystemDelete requestingDomain e = do + let rconvId = toRemoteUnsafe requestingDomain e.conversation + localMembers <- filterSystemNotificationRecipients requestingDomain e.conversation e.alreadyPresentUsers + E.deleteMembersInRemoteConversation rconvId localMembers + pushSystemEvent + Nothing + ( SystemEvent + (Qualified e.conversation requestingDomain) + Nothing + e.time + Nothing + EdSystemConvDelete + ) + (Set.fromList localMembers) + pure EmptyResponse + +onSystemAdminlessReminder :: + ( Member E.ConversationStore r, + Member NotificationSubsystem r, + Member P.TinyLog r + ) => + Domain -> + SystemAdminlessReminderNotification -> + Sem r EmptyResponse +onSystemAdminlessReminder requestingDomain notification = do + localMembers <- + filterSystemNotificationRecipients + requestingDomain + notification.conversation + notification.alreadyPresentUsers + pushSystemEvent + Nothing + ( SystemEvent + (Qualified notification.conversation requestingDomain) + Nothing + notification.time + Nothing + (EdSystemAdminlessReminder notification.reminder) + ) + (Set.fromList localMembers) + pure EmptyResponse + +onAdminlessReminder :: + ( Member E.ConversationStore r, + Member NotificationSubsystem r, + Member ExternalAccess r, + Member (Input (Local ())) r, + Member P.TinyLog r + ) => + Domain -> + AdminlessReminderNotification -> + Sem r EmptyResponse +onAdminlessReminder requestingDomain notification = do + loc <- qualifyLocal () + localMembers <- + filterSystemNotificationRecipients + requestingDomain + notification.conversation + notification.alreadyPresentUsers + pushConversationEvent + Nothing + () + ( Event + (Qualified notification.conversation requestingDomain) + Nothing + (EventFromUser notification.origUserId) + notification.time + Nothing + (EdAdminlessReminder notification.reminder) + ) + (qualifyAs loc localMembers) + [] + pure EmptyResponse + +filterSystemNotificationRecipients :: + ( Member E.ConversationStore r, + Member P.TinyLog r + ) => + Domain -> + ConvId -> + [UserId] -> + Sem r [UserId] +filterSystemNotificationRecipients requestingDomain conversation users = do + let rconvId = toRemoteUnsafe requestingDomain conversation + (members, allMembers) <- E.selectRemoteMembers users rconvId + unless allMembers $ + P.warn $ + Log.field "conversation" (toByteString' conversation) + Log.~~ Log.field "domain" (toByteString' requestingDomain) + Log.~~ Log.field "users" (show users) + Log.~~ Log.msg + ("Federated system notification contained users that are not members of the conversation" :: ByteString) + pure members + -- as of now this will not generate the necessary events on the leaver's domain leaveConversation :: ( Member BackendNotificationQueueAccess r, @@ -603,7 +729,8 @@ sendMLSCommitBundle :: Member TeamCollaboratorsSubsystem r, Member E.MLSCommitLockStore r, Member FeaturesConfigSubsystem r, - Member (Input ConversationSubsystemConfig) r + Member (Input ConversationSubsystemConfig) r, + Member Async r ) => Domain -> MLSMessageSendRequest -> @@ -891,8 +1018,6 @@ onMLSMessageSent domain rmm = mlsSendWelcome :: ( Member (Error InternalError) r, Member NotificationSubsystem r, - Member ExternalAccess r, - Member P.TinyLog r, Member (Input (Maybe (MLSKeysByPurpose MLSPrivateKeys))) r, Member (Input (Local ())) r, Member Now r diff --git a/libs/wire-subsystems/src/Wire/ConversationSubsystem/Interpreter.hs b/libs/wire-subsystems/src/Wire/ConversationSubsystem/Interpreter.hs index 651d6c775e8..70428536c30 100644 --- a/libs/wire-subsystems/src/Wire/ConversationSubsystem/Interpreter.hs +++ b/libs/wire-subsystems/src/Wire/ConversationSubsystem/Interpreter.hs @@ -25,14 +25,18 @@ module Wire.ConversationSubsystem.Interpreter ) where +import Data.Aeson qualified as A +import Data.Aeson.Types qualified as AT import Data.Qualified +import Data.Text qualified as Text import Imports -import Network.Wai.Utilities.JSONResponse (JSONResponse) +import Network.Wai.Utilities.JSONResponse (JSONResponse (..)) import Polysemy +import Polysemy.Async (Async) import Polysemy.Error import Polysemy.Input import Polysemy.Resource (Resource) -import Polysemy.TinyLog (TinyLog) +import Polysemy.TinyLog (TinyLog, logErrors) import Wire.API.Conversation.Config import Wire.API.Error import Wire.API.Federation.Client (FederatorClient) @@ -86,6 +90,14 @@ import Wire.TeamSubsystem (TeamSubsystem) import Wire.UserClientIndexStore (UserClientIndexStore) import Wire.UserGroupStore (UserGroupStore) +renderConversationSubsystemError :: ConversationSubsystemError -> Text +renderConversationSubsystemError errorValue = + let response = toResponse errorValue + label = case response.value of + A.Object object -> fromMaybe "unknown" (AT.parseMaybe (A..: "label") object) + _ -> "unknown" + in "status=" <> Text.pack (show response.status) <> " label=" <> label + interpretConversationSubsystem :: ( Member MeetingNotifier r, Member (Error ConversationSubsystemError) r, @@ -123,7 +135,8 @@ interpretConversationSubsystem :: Member (Input (Maybe (MLSKeysByPurpose MLSPrivateKeys))) r, Member UserClientIndexStore r, Member (Input FanoutLimit) r, - Member TinyLog r + Member TinyLog r, + Member Async r ) => InterpreterFor ConversationSubsystem r interpretConversationSubsystem = interpret $ \case @@ -150,9 +163,15 @@ interpretConversationSubsystem = interpret $ \case InternalGetLocalMember cid uid -> mapErrors $ ConvStore.getLocalMember cid uid PostMLSCommitBundle loc qusr c ctype qConvOrSub conn oosCheck bundle -> - mapErrors $ MLSMessage.postMLSCommitBundle loc qusr c ctype qConvOrSub conn oosCheck bundle + logErrors @_ @ConversationSubsystemError + renderConversationSubsystemError + "MLS commit bundle failed" + (mapErrors $ MLSMessage.postMLSCommitBundle loc qusr c ctype qConvOrSub conn oosCheck bundle) PostMLSCommitBundleFromLocalUser v lusr c conn bundle -> - mapErrors $ MLSMessage.postMLSCommitBundleFromLocalUser v lusr c conn bundle + logErrors @_ @ConversationSubsystemError + renderConversationSubsystemError + "MLS commit bundle failed" + (mapErrors $ MLSMessage.postMLSCommitBundleFromLocalUser v lusr c conn bundle) PostMLSMessage loc qusr c ctype qconvOrSub con oosCheck msg -> mapErrors $ MLSMessage.postMLSMessage loc qusr c ctype qconvOrSub con oosCheck msg PostMLSMessageFromLocalUser v lusr c conn smsg -> @@ -201,6 +220,14 @@ interpretConversationSubsystem = interpret $ \case mapErrors $ Federation.onMLSMessageSent domain rmm FederationOnConversationUpdated domain cu -> mapErrors $ Federation.onConversationUpdated domain cu + FederationOnSystemMemberUpdate domain notification -> + mapErrors $ Federation.onSystemMemberUpdate domain notification + FederationOnSystemDelete domain notification -> + mapErrors $ Federation.onSystemDelete domain notification + FederationOnSystemAdminlessReminder domain notification -> + mapErrors $ Federation.onSystemAdminlessReminder domain notification + FederationOnAdminlessReminder domain notification -> + mapErrors $ Federation.onAdminlessReminder domain notification FederationOnUserDeleted domain udcn -> mapErrors $ Federation.onUserDeleted domain udcn PostOtrMessageUnqualified lusr con cnv ignore report msg -> diff --git a/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/CheckClients.hs b/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/CheckClients.hs index 388d6a16422..0581fec3bb9 100644 --- a/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/CheckClients.hs +++ b/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/CheckClients.hs @@ -29,8 +29,11 @@ import Data.Map qualified as Map import Data.Qualified import Data.Set qualified as Set import Data.Tuple.Extra +import Galley.Types.Error (InternalError (..)) import Imports import Polysemy +import Polysemy.Async (Async) +import Polysemy.Async qualified as P import Polysemy.Error import Wire.API.Error import Wire.API.Error.Galley @@ -50,7 +53,9 @@ checkClients :: Member (FederationAPIAccess FederatorClient) r, Member (ErrorS MLSClientMismatch) r, Member (ErrorS MLSIdentityMismatch) r, - Member (Error MLSProtocolError) r + Member (Error MLSProtocolError) r, + Member (Error InternalError) r, + Member Async r ) => Local ConvOrSubConv -> CipherSuiteTag -> @@ -59,9 +64,35 @@ checkClients :: checkClients lConvOrSub ciphersuite newCM = do let convOrSub = tUnqualified lConvOrSub cm = convOrSub.members - fmap catMaybes . forM (Map.assocs (unClientMap newCM)) $ - \(qtarget, newclients) -> do - mClientData <- getClientData lConvOrSub ciphersuite qtarget + assocs = Map.assocs (unClientMap newCM) + -- Fetch client data from brig concurrently. getClientData is total with + -- respect to 'FederationError' (hushed inside getClientData): an inner + -- 'Nothing' is a legitimate "user unreachable" result. + -- + -- sequenceConcurrently attaches an outer 'Maybe' to every child result. + -- Under galley's production stack (asyncToIOFinal below pure + -- runError/mapError interpreters, cf. Galley.App), an 'Error'-effect + -- thrown inside a spawned child (e.g. RpcException/ParseException from + -- interpretBrigAccess) is forwarded by the in-thread mapError handlers + -- to the residual error, whose interpreter sits outside the async + -- boundary; Polysemy collapses the child result to 'Nothing'. That is a + -- crashed child, not "no client data", and must abort the commit with + -- an internal error instead of being conflated with the unreachable + -- case. + -- + -- Validation below runs serially so that Error-effect throws abort the + -- whole commit exactly as in the fully serial implementation. + mClientDatas <- + P.sequenceConcurrently $ + flip fmap assocs $ \(qtarget, _) -> + getClientData lConvOrSub ciphersuite qtarget + clientDatas <- + forM mClientDatas $ + maybe + (throw (InternalErrorWithDescription "Concurrent brig client-data fetch failed while processing commit")) + pure + fmap catMaybes . forM (zip assocs clientDatas) $ + \((qtarget, newclients), mClientData) -> do unreachable <- case (mClientData, cmLookup qtarget cm) of -- user is already present, skip check in this case (_, Just existingClients) -> do @@ -103,9 +134,9 @@ checkClients lConvOrSub ciphersuite newCM = do pure False -- Check that new leaf nodes are using the registered signature keys. - for_ mClientData $ \clientData -> + for_ mClientData $ \cd -> for_ (Map.assocs newclients) $ \(cid, (_, mKp)) -> - checkSignatureKey (fmap (.leafNode) mKp) (Map.lookup cid clientData.infoMap) + checkSignatureKey (fmap (.leafNode) mKp) (Map.lookup cid cd.infoMap) pure $ guard unreachable $> qtarget diff --git a/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Commit/Core.hs b/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Commit/Core.hs index c54c5474cf8..64d13f432bd 100644 --- a/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Commit/Core.hs +++ b/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Commit/Core.hs @@ -18,6 +18,7 @@ module Wire.ConversationSubsystem.MLS.Commit.Core ( getCommitData, incrementEpoch, + incrementEpochNoRead, getClientInfo, getSingleClientInfo, checkSignatureKey, @@ -70,7 +71,7 @@ import Wire.ExternalAccess import Wire.FederationAPIAccess import Wire.LegalHoldStore (LegalHoldStore) import Wire.NotificationSubsystem -import Wire.ProposalStore (ProposalStore) +import Wire.ProposalStore (ProposalStore, StoredProposal, getAllPendingProposals) import Wire.Sem.Now (Now) import Wire.Sem.Random (Random) import Wire.TeamCollaboratorsSubsystem @@ -114,22 +115,27 @@ getCommitData :: Epoch -> CipherSuiteTag -> IncomingBundle -> - Sem r (IndexMap, ProposalAction) + Sem r (IndexMap, ProposalAction, [StoredProposal]) getCommitData senderIdentity lConvOrSub epoch ciphersuite bundle = do let convOrSub = tUnqualified lConvOrSub groupId = cnvmlsGroupId convOrSub.mlsMeta - runState convOrSub.indexMap $ do - creatorAction <- - if epoch == Epoch 0 - then addProposedClient (Left . RegularClient $ senderIdentity.client) - else mempty - proposals <- - traverse - (derefOrCheckProposal epoch ciphersuite groupId) - bundle.commit.value.proposals - action <- applyProposals ciphersuite proposals - pure (creatorAction <> action) + -- Fetch all pending proposals once: used both for dereferencing commit + -- proposal refs and by checkReferences downstream. + storedProposals <- getAllPendingProposals groupId epoch + (newIndexMap, combinedAction) <- + runState convOrSub.indexMap $ do + creatorAction <- + if epoch == Epoch 0 + then addProposedClient (Left . RegularClient $ senderIdentity.client) + else mempty + proposals <- + traverse + (derefOrCheckProposalFrom storedProposals ciphersuite) + bundle.commit.value.proposals + action <- applyProposals ciphersuite proposals + pure (creatorAction <> action) + pure (newIndexMap, combinedAction, storedProposals) incrementEpoch :: ( Member ConversationStore r, @@ -149,6 +155,19 @@ incrementEpoch (SubConv c s) = do getSubConversation (mcId c) (scSubConvId s) >>= noteS @'ConvNotFound pure (SubConv c subconv) +-- | Bump the MLS epoch without re-reading the conversation afterwards. +-- Use when the caller discards the result; avoids 2-3 CQL round trips. +incrementEpochNoRead :: + (Member ConversationStore r) => + ConvOrSubConv -> + Sem r () +incrementEpochNoRead = + \case + Conv c -> + setConversationEpoch (mcId c) (succ (cnvmlsEpoch (mcMLSData c))) + SubConv _c s -> + setSubConversationEpoch (scParentConvId s) (scSubConvId s) (succ (cnvmlsEpoch (scMLSData s))) + getClientInfo :: ( Member BrigAPIAccess r, Member (FederationAPIAccess FederatorClient) r, diff --git a/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Commit/InternalCommit.hs b/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Commit/InternalCommit.hs index d904f7396d5..68bb12c1ec0 100644 --- a/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Commit/InternalCommit.hs +++ b/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Commit/InternalCommit.hs @@ -32,6 +32,8 @@ import Data.Tuple.Extra import Galley.Types.Error import Imports import Polysemy +import Polysemy.Async (Async) +import Polysemy.Async qualified as P import Polysemy.Error import Polysemy.Input (Input) import Polysemy.Resource (Resource) @@ -78,6 +80,7 @@ processInternalCommit :: Member (ErrorS 'MissingLegalholdConsent) r, Member (ErrorS 'GroupIdVersionNotSupported) r, Member Resource r, + Member Async r, Member Random r, Member (ErrorS MLSInvalidLeafNodeSignature) r, Member MLSCommitLockStore r, @@ -93,14 +96,14 @@ processInternalCommit :: Epoch -> ProposalAction -> Commit -> + [StoredProposal] -> Codensity (Sem r) [LocalConversationUpdate] -processInternalCommit senderIdentity con lConvOrSub ciphersuite ciphersuiteUpdate epoch action commit = do +processInternalCommit senderIdentity con lConvOrSub ciphersuite ciphersuiteUpdate epoch action commit storedProposals = do let convOrSub = tUnqualified lConvOrSub qusr = cidQualifiedUser senderIdentity.client cm = convOrSub.members newUserClients = Map.assocs (unClientMap (paAdd action)) - - lift $ checkReferences convOrSub epoch commit + lift $ checkReferences storedProposals commit -- check update path lift $ traverse_ (checkUpdatePath lConvOrSub senderIdentity ciphersuite) commit.path @@ -244,9 +247,25 @@ processInternalCommit senderIdentity con lConvOrSub ciphersuite ciphersuiteUpdat removeMLSClients gid qtarget (Map.keysSet clients) -- add clients to the conversation state - for_ newUserClients $ \(qtarget, newClients) -> do - addMLSClients gid qtarget $ - Set.fromList [(cid, idx) | (cid, (idx, _)) <- Map.assocs newClients] + -- Note: safe to run concurrently because the children only perform store + -- writes on disjoint rows. The store children fail via IO exceptions + -- (addMLSClients runs through embedClient, a pure IO embed), which the + -- Async interpretation rethrows. An 'Error'-effect throw in a child is + -- forwarded by the in-thread mapError interpreters (cf. Galley.App) to + -- the residual error, whose interpreter sits outside asyncToIOFinal; + -- Polysemy collapses the child result to 'Nothing'. The 'Nothing' guard + -- below turns that into a hard commit failure instead of a silently + -- dropped write. + results <- + P.sequenceConcurrently $ + flip fmap newUserClients $ \(qtarget, newClients) -> + addMLSClients gid qtarget $ + Set.fromList [(cid, idx) | (cid, (idx, _)) <- Map.assocs newClients] + when (Nothing `elem` results) $ + throw + ( InternalErrorWithDescription + "A concurrent client-store write failed while processing commit" + ) for_ action.paHistoryClientAdd $ uncurry (addHistoryClient gid) @@ -256,9 +275,8 @@ processInternalCommit senderIdentity con lConvOrSub ciphersuite ciphersuiteUpdat when ciphersuiteUpdate $ case convOrSub.id of Conv cid -> setConversationCipherSuite cid ciphersuite SubConv cid sub -> setSubConversationCipherSuite cid sub ciphersuite - -- increment epoch number - for_ lConvOrSub incrementEpoch + for_ lConvOrSub incrementEpochNoRead pure events @@ -330,12 +348,9 @@ existingMembers :: Local StoredConversation -> Set (Qualified UserId) existingMembers lconv = existingLocalMembers lconv <> existingRemoteMembers lconv checkReferences :: - ( Member ProposalStore r, - Member (ErrorS MLSCommitMissingReferences) r - ) => - ConvOrSubConv -> Epoch -> Commit -> Sem r () -checkReferences convOrSub epoch commit = do - allPendingProposals <- getAllPendingProposals (cnvmlsGroupId convOrSub.mlsMeta) epoch + (Member (ErrorS MLSCommitMissingReferences) r) => + [StoredProposal] -> Commit -> Sem r () +checkReferences allPendingProposals commit = do let referencedProposals = Set.fromList $ mapMaybe (\x -> preview _Ref x) commit.proposals let (includedProposals, missingProposals) = partition diff --git a/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Message.hs b/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Message.hs index b5cc036c2c6..760bcd63e22 100644 --- a/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Message.hs +++ b/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Message.hs @@ -43,6 +43,7 @@ import Data.Tuple.Extra import Galley.Types.Error import Imports import Polysemy +import Polysemy.Async (Async) import Polysemy.Error import Polysemy.Input import Polysemy.Output @@ -183,7 +184,8 @@ postMLSCommitBundle :: Member FederationSubsystem r, Member TeamSubsystem r, Member (Input ConversationSubsystemConfig) r, - Member FeaturesConfigSubsystem r + Member FeaturesConfigSubsystem r, + Member Async r ) => Local x -> Qualified UserId -> @@ -220,7 +222,8 @@ postMLSCommitBundleFromLocalUser :: Member FederationSubsystem r, Member TeamSubsystem r, Member (Input ConversationSubsystemConfig) r, - Member FeaturesConfigSubsystem r + Member FeaturesConfigSubsystem r, + Member Async r ) => Version -> Local UserId -> @@ -257,7 +260,8 @@ postMLSCommitBundleToLocalConv :: Member FederationSubsystem r, Member TeamSubsystem r, Member (Input ConversationSubsystemConfig) r, - Member FeaturesConfigSubsystem r + Member FeaturesConfigSubsystem r, + Member Async r ) => Qualified UserId -> ClientId -> @@ -325,7 +329,7 @@ postMLSCommitBundleToLocalConv qusr c conn bundle ctype lConvOrSubId = do (events, newClients) <- case senderIdentity.index of Just _ -> do -- extract added/removed clients from bundle - (newIndexMap, action) <- + (newIndexMap, action, storedProposals) <- lift $ getCommitData senderIdentity lConvOrSub bundle.epoch ciphersuite bundle @@ -358,6 +362,7 @@ postMLSCommitBundleToLocalConv qusr c conn bundle ctype lConvOrSubId = do bundle.epoch action bundle.commit.value + storedProposals -- the sender client is included in the Add action on the first commit, -- but it doesn't need to get a welcome message, so we filter it out here let newClients = cmRemoveClient senderIdentity.client (paAdd action) diff --git a/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Proposal.hs b/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Proposal.hs index 083b1b77d20..c4d9497c148 100644 --- a/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Proposal.hs +++ b/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Proposal.hs @@ -17,7 +17,7 @@ module Wire.ConversationSubsystem.MLS.Proposal ( -- * Proposal processing - derefOrCheckProposal, + derefOrCheckProposalFrom, checkProposal, processProposal, proposalProcessingStage, @@ -145,24 +145,24 @@ type HasProposalEffects r = Member TeamCollaboratorsSubsystem r ) -derefOrCheckProposal :: +-- | Dereference a commit proposal, looking up refs in a prefetched list of +-- pending proposals instead of issuing one point-read per ref. +derefOrCheckProposalFrom :: ( Member (Error MLSProtocolError) r, Member (ErrorS 'MLSInvalidLeafNodeIndex) r, Member (ErrorS 'MLSUnsupportedProposal) r, - Member ProposalStore r, Member (State IndexMap) r, Member (ErrorS 'MLSProposalNotFound) r, Member (ErrorS 'MLSInvalidLeafNodeSignature) r ) => - Epoch -> + [StoredProposal] -> CipherSuiteTag -> - GroupId -> ProposalOrRef -> Sem r Proposal -derefOrCheckProposal epoch _ciphersuite groupId (Ref ref) = do - p <- getProposal groupId epoch ref >>= noteS @'MLSProposalNotFound - pure p.value -derefOrCheckProposal _epoch ciphersuite _ (Inline p) = do +derefOrCheckProposalFrom stored _ciphersuite (Ref ref) = + noteS @'MLSProposalNotFound $ + (.proposal.value) <$> find ((== ref) . (.ref)) stored +derefOrCheckProposalFrom _stored ciphersuite (Inline p) = do im <- get checkProposal ciphersuite im p pure p @@ -242,8 +242,9 @@ applyProposal _ciphersuite (RemoveProposal idx) = do applyProposal _activeData _ = pure mempty processProposal :: - (HasProposalEffects r) => - ( Member (ErrorS 'ConvNotFound) r, + ( HasProposalEffects r, + Member (ErrorS 'MLSUnsupportedMessage) r, + Member (ErrorS 'ConvNotFound) r, Member (ErrorS 'MLSStaleMessage) r, Member (ErrorS 'MLSInvalidLeafNodeSignature) r ) => @@ -259,6 +260,13 @@ processProposal qusr lConvOrSub groupId epoch pub prop = do -- Check if the group ID matches that of a conversation unless (groupId == cnvmlsGroupId mlsMeta) $ throwS @'ConvNotFound + -- Proposals from existing members are not authorized independently of the + -- commit that applies them. They must therefore only be submitted as part + -- of a commit bundle, where the committer's conversation role can be + -- checked. External proposals are retained for the join flow and are + -- restricted by 'checkExternalProposalUser' below. + unless (isExternal pub.sender) $ throwS @'MLSUnsupportedMessage + case cnvmlsActiveData mlsMeta of Nothing -> throw $ mlsProtocolError "Bare proposals at epoch 0 are not supported" Just activeData -> do diff --git a/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Util.hs b/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Util.hs index b862e488b09..e5ff6133bc9 100644 --- a/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Util.hs +++ b/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Util.hs @@ -28,7 +28,7 @@ import Data.Text qualified as T import Imports import Polysemy import Polysemy.Error -import Polysemy.Resource (Resource, bracket) +import Polysemy.Resource (Resource, bracket, onException) import Polysemy.TinyLog (TinyLog) import Polysemy.TinyLog qualified as TinyLog import System.Logger qualified as Log @@ -123,25 +123,46 @@ withCommitLock lConvOrSubId gid epoch = Nothing throwS @'MLSStaleMessage ) - (const $ releaseCommitLock gid epoch) ( const $ do - actualEpoch <- - fromMaybe (Epoch 0) <$> case tUnqualified lConvOrSubId of - Conv cnv -> getConversationEpoch cnv - SubConv cnv sub -> getSubConversationEpoch cnv sub - unless (actualEpoch == epoch) $ do - logStaleCommitLock - "commit-lock-epoch-mismatch" - lConvOrSubId - gid - epoch - (Just actualEpoch) - throwS @'MLSStaleMessage - k () + releaseCommitLock gid epoch + `onException` (logCommitLockFailure "release" lConvOrSubId gid epoch) + ) + ( const $ + ( do + actualEpoch <- + fromMaybe (Epoch 0) <$> case tUnqualified lConvOrSubId of + Conv cnv -> getConversationEpoch cnv + SubConv cnv sub -> getSubConversationEpoch cnv sub + unless (actualEpoch == epoch) $ do + logStaleCommitLock + "commit-lock-epoch-mismatch" + lConvOrSubId + gid + epoch + (Just actualEpoch) + throwS @'MLSStaleMessage + k () + ) + `onException` logCommitLockFailure "operation" lConvOrSubId gid epoch ) where ttl = fromIntegral (600 :: Int) -- 10 minutes +logCommitLockFailure :: + (Member TinyLog r) => + ByteString -> + Local ConvOrSubConvId -> + GroupId -> + Epoch -> + Sem r () +logCommitLockFailure phase lConvOrSubId gid epoch = + TinyLog.warn $ + Log.msg ("MLS commit lock operation failed" :: ByteString) + . Log.field "phase" phase + . Log.field "groupId" ("0x" <> hex (unGroupId gid)) + . Log.field "epoch" (epochNumber epoch) + . Log.field "convOrSubConvId" (toByteString' (show (tUnqualified lConvOrSubId))) + logStaleCommitLock :: (Member TinyLog r) => ByteString -> diff --git a/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Welcome.hs b/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Welcome.hs index b16bb87e1af..9ebe0ff0e85 100644 --- a/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Welcome.hs +++ b/libs/wire-subsystems/src/Wire/ConversationSubsystem/MLS/Welcome.hs @@ -48,7 +48,6 @@ import Wire.API.MLS.SubConversation import Wire.API.MLS.Welcome import Wire.API.Message import Wire.API.Push.V2 (RecipientClients (..)) -import Wire.ExternalAccess import Wire.FederationAPIAccess import Wire.NotificationSubsystem import Wire.Sem.Now (Now) @@ -56,7 +55,6 @@ import Wire.Sem.Now qualified as Now sendWelcomes :: ( Member (FederationAPIAccess FederatorClient) r, - Member ExternalAccess r, Member P.TinyLog r, Member Now r, Member NotificationSubsystem r @@ -79,10 +77,7 @@ sendWelcomes loc qusr con cids welcome = do convFrom (SubConv c _) = c sendLocalWelcomes :: - ( Member P.TinyLog r, - Member ExternalAccess r, - Member NotificationSubsystem r - ) => + (Member NotificationSubsystem r) => Qualified ConvId -> Qualified UserId -> Maybe ConnId -> @@ -100,8 +95,11 @@ sendLocalWelcomes qcnv qusr con now welcome lclients = do mempty $ tUnqualified lclients let e = Event qcnv Nothing (EventFromUser qusr) now Nothing $ EdMLSWelcome welcome.raw - runMessagePush lclients (Just qcnv) $ - newMessagePush mempty con defMessageMetadata rcpts e + -- Fire-and-forget: delivery is asynchronous downstream of gundeck anyway; + -- blocking the commit-bundle response on the fan-out is wasted latency. + void $ + pushNotificationAsync + (toPush (newMessagePush mempty con defMessageMetadata rcpts e)) sendRemoteWelcomes :: ( Member (FederationAPIAccess FederatorClient) r, diff --git a/libs/wire-subsystems/src/Wire/ConversationSubsystem/Notify.hs b/libs/wire-subsystems/src/Wire/ConversationSubsystem/Notify.hs index e40ea62e46f..d76ea3ff58e 100644 --- a/libs/wire-subsystems/src/Wire/ConversationSubsystem/Notify.hs +++ b/libs/wire-subsystems/src/Wire/ConversationSubsystem/Notify.hs @@ -18,6 +18,10 @@ module Wire.ConversationSubsystem.Notify ( notifyConversationActionImpl, pushSystemEvent, + sendSystemMemberUpdate, + sendSystemDelete, + sendSystemAdminlessReminder, + sendAdminlessReminder, ) where @@ -34,8 +38,8 @@ import Wire.API.Conversation hiding (Member) import Wire.API.Conversation qualified as Public import Wire.API.Conversation.Action import Wire.API.Event.Conversation -import Wire.API.Federation.API (makeConversationUpdateBundle, sendBundle) -import Wire.API.Federation.API.Galley.Notifications (ConversationUpdate (..)) +import Wire.API.Federation.API +import Wire.API.Federation.API.Galley.Notifications import Wire.API.Federation.Error import Wire.BackendNotificationQueueAccess (BackendNotificationQueueAccess, enqueueNotificationsConcurrently) import Wire.ConversationSubsystem.Util @@ -120,3 +124,55 @@ pushSystemEvent con event targets = do isCellsEvent = True } ] + +sendSystemMemberUpdate :: + ( Member BackendNotificationQueueAccess r, + Member (Error FederationError) r + ) => + Set (Remote UserId) -> + SystemMemberUpdateNotification -> + Sem r () +sendSystemMemberUpdate targets n = void $ + enqueueNotificationsConcurrently Q.Persistent (toList targets) $ \ruids -> + makeSystemMemberUpdateBundle + (SystemMemberUpdateNotification n.time n.conversation n.update (tUnqualified ruids)) + >>= sendBundle + +sendSystemDelete :: + ( Member BackendNotificationQueueAccess r, + Member (Error FederationError) r + ) => + Set (Remote UserId) -> + SystemDeleteNotification -> + Sem r () +sendSystemDelete targets n = void $ + enqueueNotificationsConcurrently Q.Persistent (toList targets) $ \ruids -> + makeSystemDeleteBundle + (SystemDeleteNotification n.time n.conversation (tUnqualified ruids)) + >>= sendBundle + +sendSystemAdminlessReminder :: + ( Member BackendNotificationQueueAccess r, + Member (Error FederationError) r + ) => + Set (Remote UserId) -> + SystemAdminlessReminderNotification -> + Sem r () +sendSystemAdminlessReminder targets n = void $ + enqueueNotificationsConcurrently Q.Persistent (toList targets) $ \ruids -> + makeSystemAdminlessReminderBundle + (SystemAdminlessReminderNotification n.time n.conversation n.reminder (tUnqualified ruids)) + >>= sendBundle + +sendAdminlessReminder :: + ( Member BackendNotificationQueueAccess r, + Member (Error FederationError) r + ) => + Set (Remote UserId) -> + AdminlessReminderNotification -> + Sem r () +sendAdminlessReminder targets n = void $ + enqueueNotificationsConcurrently Q.Persistent (toList targets) $ \ruids -> + makeAdminlessReminderBundle + (AdminlessReminderNotification n.time n.conversation n.origUserId n.reminder (tUnqualified ruids)) + >>= sendBundle diff --git a/libs/wire-subsystems/src/Wire/ConversationSubsystem/Query.hs b/libs/wire-subsystems/src/Wire/ConversationSubsystem/Query.hs index c181a9c0866..3f020ae6f39 100644 --- a/libs/wire-subsystems/src/Wire/ConversationSubsystem/Query.hs +++ b/libs/wire-subsystems/src/Wire/ConversationSubsystem/Query.hs @@ -84,6 +84,7 @@ import Wire.API.Conversation.Role import Wire.API.Conversation.Role qualified as Public import Wire.API.Error import Wire.API.Error.Galley +import Wire.API.Event.Conversation (SystemEvent (..), SystemEventData (EdSystemConvDelete)) import Wire.API.Federation.API import Wire.API.Federation.API.Galley import Wire.API.Federation.Client (FederatorClient, getNegotiatedVersion) @@ -106,12 +107,16 @@ import Wire.ConversationSubsystem.Fetch (getConversationIdsImpl) import Wire.ConversationSubsystem.MLS import Wire.ConversationSubsystem.MLS.Enabled (assertMLSEnabled, getMLSPrivateKeys, isMLSEnabled) import Wire.ConversationSubsystem.MLS.One2One (localMLSOne2OneConversation, remoteMLSOne2OneConversation) +import Wire.ConversationSubsystem.Notify qualified as Notify import Wire.ConversationSubsystem.One2One import Wire.ConversationSubsystem.Util import Wire.FeaturesConfigSubsystem import Wire.FederationAPIAccess qualified as E import Wire.HashPassword (HashPassword) +import Wire.NotificationSubsystem import Wire.RateLimit +import Wire.Sem.Now (Now) +import Wire.Sem.Now qualified as Now import Wire.Sem.Paging.Cassandra import Wire.StoredConversation import Wire.StoredConversation qualified as Data @@ -184,6 +189,8 @@ getConversation :: Member (Error FederationError) r, Member (E.FederationAPIAccess FederatorClient) r, Member P.TinyLog r, + Member Now r, + Member NotificationSubsystem r, Member TeamSubsystem r ) => Local UserId -> @@ -205,6 +212,8 @@ getOwnConversation :: Member (Error InternalError) r, Member (E.FederationAPIAccess FederatorClient) r, Member P.TinyLog r, + Member Now r, + Member NotificationSubsystem r, Member TeamSubsystem r ) => Local UserId -> @@ -222,7 +231,9 @@ getRemoteConversation :: Member (ErrorS ConvNotFound) r, Member (Error FederationError) r, Member TinyLog r, - Member (E.FederationAPIAccess FederatorClient) r + Member (E.FederationAPIAccess FederatorClient) r, + Member Now r, + Member NotificationSubsystem r ) => Local UserId -> Remote ConvId -> @@ -239,7 +250,9 @@ getRemoteConversations :: Member (Error FederationError) r, Member (ErrorS 'ConvNotFound) r, Member (E.FederationAPIAccess FederatorClient) r, - Member P.TinyLog r + Member P.TinyLog r, + Member Now r, + Member NotificationSubsystem r ) => Local UserId -> [Remote ConvId] -> @@ -308,7 +321,9 @@ partitionGetConversationFailures = bimap concat concat . partitionEithers . map getRemoteConversationsWithFailures :: ( Member ConversationStore.ConversationStore r, Member (E.FederationAPIAccess FederatorClient) r, - Member P.TinyLog r + Member P.TinyLog r, + Member Now r, + Member NotificationSubsystem r ) => Local UserId -> [Remote ConvId] -> @@ -346,18 +361,38 @@ getRemoteConversationsWithFailures lusr convs = do rpc $ GetConversationsRequest (tUnqualified lusr) (tUnqualified someConvs) bimap (localFailures <>) (map remoteView . concat) . partitionEithers - <$> traverse handleFailure resp + <$> traverse (handleRequest locallyFound) resp where - handleFailure :: - (Member P.TinyLog r) => + handleRequest :: + ( Member ConversationStore.ConversationStore r, + Member P.TinyLog r, + Member Now r, + Member NotificationSubsystem r + ) => + [Remote ConvId] -> Either (Remote [ConvId], FederationError) (Remote GetRemoteConversationViewsResponse) -> Sem r (Either FailedGetConversation [Remote RemoteConversationView]) - handleFailure (Left (rcids, e)) = do + handleRequest _ (Left (rcids, e)) = do P.warn $ Logger.msg ("Error occurred while fetching remote conversations" :: ByteString) . Logger.field "error" (displayException e) pure . Left $ failedGetConversationRemotely (sequenceA rcids) e - handleFailure (Right c) = pure . Right . traverse (.convs) $ c + handleRequest locallyFound (Right response) = do + let locallyFoundForDomain = Set.fromList $ filter ((== tDomain response) . tDomain) locallyFound + returnedIds = Set.fromList $ map (qualifyAs response . (.id)) (tUnqualified response).convs + missingConversations = Set.toList $ locallyFoundForDomain `Set.difference` returnedIds + unless (null missingConversations) $ do + now <- Now.get + for_ missingConversations $ \conv -> do + ConversationStore.deleteMembersInRemoteConversation conv [tUnqualified lusr] + Notify.pushSystemEvent + Nothing + (SystemEvent (tUntagged conv) Nothing now Nothing EdSystemConvDelete) + (Set.singleton $ tUnqualified lusr) + P.info $ + Logger.msg ("Removed stale local memberships for remote conversations" :: ByteString) + . Logger.field "convIds" (show $ map tUntagged missingConversations) + pure . Right . traverse (.convs) $ response getConversationRoles :: ( Member ConversationStore.ConversationStore r, @@ -505,7 +540,9 @@ listConversations :: ( Member ConversationStore.ConversationStore r, Member (Error InternalError) r, Member (E.FederationAPIAccess FederatorClient) r, - Member P.TinyLog r + Member P.TinyLog r, + Member Now r, + Member NotificationSubsystem r ) => Local UserId -> Public.ListConversations -> @@ -529,9 +566,6 @@ listConversations luser (Public.ListConversations ids) = do fetchedOrFailedRemoteIds = Set.fromList $ map Public.cnvQualifiedId remoteConversations <> failedConvs remoteNotFoundRemoteIds = filter (`Set.notMember` fetchedOrFailedRemoteIds) $ map tUntagged remoteIds unless (null remoteNotFoundRemoteIds) $ - -- FUTUREWORK: This implies that the backends are out of sync. Maybe the - -- current user should be considered removed from this conversation at this - -- point. P.warn $ Logger.msg ("Some locally found conversation ids were not returned by remotes" :: ByteString) . Logger.field "convIds" (show remoteNotFoundRemoteIds) @@ -591,7 +625,9 @@ getSelfMember :: Member (ErrorS ConvNotFound) r, Member (Error FederationError) r, Member TinyLog r, - Member (E.FederationAPIAccess FederatorClient) r + Member (E.FederationAPIAccess FederatorClient) r, + Member Now r, + Member NotificationSubsystem r ) => Local UserId -> Qualified ConvId -> diff --git a/libs/wire-subsystems/src/Wire/ConversationSubsystem/Update.hs b/libs/wire-subsystems/src/Wire/ConversationSubsystem/Update.hs index 78474964d8f..caa7f328b3e 100644 --- a/libs/wire-subsystems/src/Wire/ConversationSubsystem/Update.hs +++ b/libs/wire-subsystems/src/Wire/ConversationSubsystem/Update.hs @@ -83,6 +83,7 @@ import Data.Code import Data.Default import Data.Id import Data.Json.Util +import Data.List.Extra (nubOrd) import Data.List.NonEmpty (NonEmpty (..), appendList, nonEmpty) import Data.Map.Strict qualified as Map import Data.Misc @@ -96,6 +97,7 @@ import Imports hiding (forkIO) import Polysemy import Polysemy.Error import Polysemy.Input +import Polysemy.State (evalState, get, modify) import Polysemy.TinyLog import System.Logger qualified as Log import Wire.API.Bot hiding (addBot) @@ -1196,17 +1198,32 @@ isAdminlessCheckCandidate conv = conv.metadata.cnvmType == RegularConv && maybe True (== GroupConversation) conv.metadata.cnvmGroupConvType -shouldSkipSystemAdminlessDeletion :: Maybe (Local UserId) -> StoredConversation -> Bool -shouldSkipSystemAdminlessDeletion mlusr conv = - isNothing mlusr - && not (null conv.remoteMembers) +systemAdminlessDeletionSupported :: + (Member (E.FederationAPIAccess FederatorClient) r) => + StoredConversation -> + Sem r Bool +systemAdminlessDeletionSupported conv = + E.allRemoteBackendsSupportNotification @'OnSystemDeleteTag + (remoteBackendsForConversation conv) + +remoteBackendsForConversation :: StoredConversation -> [Remote ()] +remoteBackendsForConversation conv = + nubOrd $ + [ toRemoteUnsafe (tDomain member.id_) () + | member <- conv.remoteMembers + ] -logSkippedSystemAdminlessDeletion :: (Member TinyLog r) => Text -> StoredConversation -> Sem r () +logSkippedSystemAdminlessDeletion :: + (Member TinyLog r) => + Text -> + StoredConversation -> + Sem r () logSkippedSystemAdminlessDeletion action conv = info $ - Log.msg (Log.val "Skipping senderless adminless deletion for conversation with remote members") + Log.msg (Log.val "Skipping system-triggered adminless deletion") . Log.field "conversation_id" (idToText conv.id_) . Log.field "action" action + . Log.field "reason" (Log.val "remote backend does not support system delete") setupAdminlessGroupsCleanup :: ( Member ConversationStore r, @@ -1221,19 +1238,40 @@ setupAdminlessGroupsCleanup :: Member FeaturesConfigSubsystem r, Member (Input (Local ())) r, Member JobSubsystem r, - Member TinyLog r + Member TinyLog r, + Member (E.FederationAPIAccess FederatorClient) r ) => Maybe (Local UserId) -> TeamId -> Sem r () setupAdminlessGroupsCleanup mUsr tid = do - teamConvIds <- E.getTeamConversations tid - for_ teamConvIds $ \cnv -> do - lcnv <- qualifyLocal cnv - adminlessTryAutopromote mUsr lcnv $ \conv feature _ -> - if shouldSkipSystemAdminlessDeletion mUsr conv - then logSkippedSystemAdminlessDeletion "schedule_for_deletion" conv - else scheduleDeletion lcnv mUsr tid feature + evalState mempty $ do + teamConvIds <- E.getTeamConversations tid + for_ teamConvIds $ \cnv -> do + lcnv <- qualifyLocal cnv + adminlessTryAutopromote mUsr lcnv $ \conv feature -> do + supported <- + if isNothing mUsr + then systemAdminlessDeletionSupportedCached conv + else pure True + if supported + then scheduleDeletion lcnv mUsr tid feature + else logSkippedSystemAdminlessDeletion "scan" conv + where + systemAdminlessDeletionSupportedCached conv = + and + <$> for + (remoteBackendsForConversation conv) + ( \remoteBackend -> do + cached <- get + case Map.lookup (tDomain remoteBackend) cached of + Just supported -> pure supported + Nothing -> do + supported <- + E.allRemoteBackendsSupportNotification @'OnSystemDeleteTag [remoteBackend] + modify (Map.insert (tDomain remoteBackend) supported) + pure supported + ) guardPreventAdminlessGroups :: ( Member ConversationStore r, @@ -1370,7 +1408,7 @@ adminlessTryAutopromote :: ) => Maybe (Local UserId) -> Local ConvId -> - (StoredConversation -> LockableFeature PreventAdminlessGroupsConfig -> [(Qualified UserId, User.Name)] -> Sem r ()) -> + (StoredConversation -> LockableFeature PreventAdminlessGroupsConfig -> Sem r ()) -> Sem r () adminlessTryAutopromote mlusr lcnv altAction = do conv <- getConversationWithError lcnv @@ -1400,6 +1438,15 @@ adminlessTryAutopromote mlusr lcnv altAction = do def Nothing -> do now <- Now.get + Notify.sendSystemMemberUpdate + (Set.fromList (map (.id_) conv.remoteMembers)) + SystemMemberUpdateNotification + { time = now, + conversation = tUnqualified lcnv, + update = memberUpdateData candidate update, + -- Filled per remote backend by Notify.sendSystemMemberUpdate. + alreadyPresentUsers = [] + } Notify.pushSystemEvent Nothing ( SystemEvent @@ -1410,7 +1457,7 @@ adminlessTryAutopromote mlusr lcnv altAction = do (EdSystemMemberUpdate (memberUpdateData candidate update)) ) (Set.fromList (map (.id_) conv.localMembers)) - [] -> altAction conv feature eligibleMembers + [] -> altAction conv feature where memberUpdateData candidate memberUpdate' = MemberUpdateData @@ -1437,6 +1484,7 @@ adminlessAutopromoteOrDelete :: Member FeaturesConfigSubsystem r, Member ProposalStore r, Member CodeStore r, + Member (E.FederationAPIAccess FederatorClient) r, Member TinyLog r ) => Maybe (Local UserId) -> @@ -1444,10 +1492,13 @@ adminlessAutopromoteOrDelete :: Sem r () adminlessAutopromoteOrDelete mlusr lcnv = adminlessTryAutopromote mlusr lcnv orAlternativelyDeleteConv where - orAlternativelyDeleteConv conv _ _ = - if shouldSkipSystemAdminlessDeletion mlusr conv - then logSkippedSystemAdminlessDeletion "deletion" conv - else do + orAlternativelyDeleteConv conv _ = do + canDelete <- + if isNothing mlusr && not (null conv.remoteMembers) + then systemAdminlessDeletionSupported conv + else pure True + if canDelete + then do removeConversation (qualifyAs lcnv conv) case mlusr of Just lusr -> @@ -1463,10 +1514,19 @@ adminlessAutopromoteOrDelete mlusr lcnv = adminlessTryAutopromote mlusr lcnv orA def Nothing -> do now <- Now.get + Notify.sendSystemDelete + (Set.fromList (map (.id_) conv.remoteMembers)) + SystemDeleteNotification + { time = now, + conversation = tUnqualified lcnv, + -- Filled per remote backend by Notify.sendSystemDelete. + alreadyPresentUsers = [] + } Notify.pushSystemEvent Nothing (SystemEvent (tUntagged lcnv) Nothing now conv.metadata.cnvmTeam EdSystemConvDelete) (Set.fromList (map (.id_) conv.localMembers)) + else logSkippedSystemAdminlessDeletion "deletion" conv adminlessAutopromoteOrSendReminder :: ( Member ConversationStore r, @@ -1478,8 +1538,7 @@ adminlessAutopromoteOrSendReminder :: Member Now r, Member E.ExternalAccess r, Member BackendNotificationQueueAccess r, - Member FeaturesConfigSubsystem r, - Member TinyLog r + Member FeaturesConfigSubsystem r ) => Maybe (Local UserId) -> Local ConvId -> @@ -1487,33 +1546,49 @@ adminlessAutopromoteOrSendReminder :: Sem r () adminlessAutopromoteOrSendReminder mlusr lcnv deletionScheduledFor = adminlessTryAutopromote mlusr lcnv orAlternativelySendReminder where - orAlternativelySendReminder conv _ _ = - if shouldSkipSystemAdminlessDeletion mlusr conv - then logSkippedSystemAdminlessDeletion "reminder" conv - else do - now <- Now.get - case mlusr of - Just lusr -> do - let event = - Event - (tUntagged lcnv) - Nothing - (EventFromUser (tUntagged lusr)) - now - (conv.metadata.cnvmTeam) - (EdAdminlessReminder (AdminlessReminder deletionScheduledFor)) - pushConversationEvent Nothing conv event (qualifyAs lcnv (map (.id_) conv.localMembers)) [] - Nothing -> - Notify.pushSystemEvent + orAlternativelySendReminder conv _ = do + now <- Now.get + case mlusr of + Just lusr -> do + let event = + Event + (tUntagged lcnv) + Nothing + (EventFromUser (tUntagged lusr)) + now + (conv.metadata.cnvmTeam) + (EdAdminlessReminder (AdminlessReminder deletionScheduledFor)) + Notify.sendAdminlessReminder + (Set.fromList (map (.id_) conv.remoteMembers)) + AdminlessReminderNotification + { time = now, + conversation = tUnqualified lcnv, + reminder = AdminlessReminder deletionScheduledFor, + origUserId = tUntagged lusr, + -- Filled per remote backend by Notify.sendAdminlessReminder. + alreadyPresentUsers = [] + } + pushConversationEvent Nothing conv event (qualifyAs lcnv (map (.id_) conv.localMembers)) [] + Nothing -> do + Notify.sendSystemAdminlessReminder + (Set.fromList (map (.id_) conv.remoteMembers)) + SystemAdminlessReminderNotification + { time = now, + conversation = tUnqualified lcnv, + reminder = AdminlessReminder deletionScheduledFor, + -- Filled per remote backend by Notify.sendSystemAdminlessReminder. + alreadyPresentUsers = [] + } + Notify.pushSystemEvent + Nothing + ( SystemEvent + (tUntagged lcnv) Nothing - ( SystemEvent - (tUntagged lcnv) - Nothing - now - conv.metadata.cnvmTeam - (EdSystemAdminlessReminder (AdminlessReminder deletionScheduledFor)) - ) - (Set.fromList (map (.id_) conv.localMembers)) + now + conv.metadata.cnvmTeam + (EdSystemAdminlessReminder (AdminlessReminder deletionScheduledFor)) + ) + (Set.fromList (map (.id_) conv.localMembers)) -- Use eight random bytes and fold them into a big-endian Word64. This keeps -- the helper small, deterministic under tests, and free of extra Random API. diff --git a/libs/wire-subsystems/src/Wire/DomainRegistrationStore/Migration.hs b/libs/wire-subsystems/src/Wire/DomainRegistrationStore/Migration.hs index 5047d4b61e2..bd29da928f4 100644 --- a/libs/wire-subsystems/src/Wire/DomainRegistrationStore/Migration.hs +++ b/libs/wire-subsystems/src/Wire/DomainRegistrationStore/Migration.hs @@ -27,17 +27,16 @@ import Data.Conduit.List qualified as C import Data.Domain import Data.Id import Database.CQL.Protocol (Record (asRecord), TupleType) -import Hasql.Pool (UsageError) import Hasql.Pool.Extended qualified as Hasql import Imports hiding (lookup) import Polysemy import Polysemy.Async +import Polysemy.AtomicState import Polysemy.Conc (interpretRace) import Polysemy.Conc.Effect.Race hiding (Timeout) import Polysemy.Error import Polysemy.Input import Polysemy.Resource (Resource, resourceToIOFinal) -import Polysemy.State import Polysemy.TinyLog import Prometheus qualified import System.Logger qualified as Log @@ -55,7 +54,7 @@ import Wire.Sem.Logger (mapLogger) import Wire.Sem.Logger.TinyLog (loggerToTinyLog) type EffectStack = - [ State Int, + [ AtomicState Int, Input ClientState, Input Hasql.Pool, Resource, @@ -97,14 +96,14 @@ interpreter cassClient pgPool logger name = . resourceToIOFinal . runInputConst pgPool . runInputConst cassClient - . runState 0 + . atomicStateToIO 0 migrateAllDomainRegistrations :: ( Member (Input Hasql.Pool) r, Member (Embed IO) r, Member (Input ClientState) r, Member TinyLog r, - Member (State Int) r, + Member (AtomicState Int) r, Member Async r, Member Race r, Member Resource r @@ -122,7 +121,7 @@ migrateAllDomainRegistrations migOpts migCounter migDuration = do lift $ info $ Log.msg (Log.val "migrateAllDomainRegistrations") withCount (paginateSem selectAllRegistrations (paramsP LocalQuorum () migOpts.pageSize) x5) .| logRetrievedPage migOpts.pageSize asRecord - .| C.mapM_ (traverse_ (\row -> handleRegistrationErrors (toByteString' (show row.domain)) (migrateDomainRegistrationRow migOpts migCounter migDuration row))) + .| C.mapM_ (traverse_ (\row -> handleLockAndDBErrors (toByteString' (show row.domain)) (migrateDomainRegistrationRow migOpts migCounter migDuration row))) migrateDomainRegistrationRow :: ( PGConstraints r, @@ -175,24 +174,3 @@ selectAllRegistrations = selectAllChallenges :: PrepQuery R () (ChallengeId, Domain, Token, DnsVerificationToken, Int32) selectAllChallenges = "SELECT id, domain, challenge_token_hash, dns_verification_token, ttl(challenge_token_hash) FROM domain_registration_challenge" - -handleRegistrationErrors :: - ( Member (State Int) r, - Member TinyLog r - ) => - ByteString -> - (Sem (Error MigrationLockError : Error UsageError : r) ()) -> - Sem r () -handleRegistrationErrors key action = do - eithErr <- runError (runError action) - case eithErr of - Right (Right _) -> pure () - Right (Left e) -> logError (show e) - Left e -> logError (show e) - where - logError e = do - warn $ - Log.msg (Log.val "error occurred during migration") - . Log.field "key" (show key) - . Log.field "error" e - modify (+ 1) diff --git a/libs/wire-subsystems/src/Wire/FederationAPIAccess.hs b/libs/wire-subsystems/src/Wire/FederationAPIAccess.hs index 6476cc08de5..2fc3d3d60f8 100644 --- a/libs/wire-subsystems/src/Wire/FederationAPIAccess.hs +++ b/libs/wire-subsystems/src/Wire/FederationAPIAccess.hs @@ -35,6 +35,7 @@ import Servant.Client.Core.RunClient (RunClient) import Wire.API.Federation.API import Wire.API.Federation.Component import Wire.API.Federation.Error +import Wire.API.Federation.HasNotificationEndpoint type HasBrigFederationAccess m r = ( Member (FederationAPIAccess m) r, @@ -88,3 +89,24 @@ runFederatedConcurrently :: runFederatedConcurrently rx c = do results <- runFederatedConcurrentlyEither rx c fromEither $ mapLeft snd $ sequence results + +allRemoteBackendsSupportNotification :: + forall tag fedM f x r. + ( Member (FederationAPIAccess fedM) r, + HasVersionRange tag, + RunClient (fedM 'Brig), + FederationMonad fedM, + Typeable fedM, + Foldable f, + Functor f + ) => + f (Remote x) -> + Sem r Bool +allRemoteBackendsSupportNotification remoteBackends = do + results <- + runFederatedConcurrentlyEither remoteBackends $ \_ -> + fedClient @'Brig @"api-version" () + pure $ all supports results + where + supports (Right versionInfo) = supportsNotificationVersion @tag (tUnqualified versionInfo) + supports (Left _) = False diff --git a/libs/wire-subsystems/src/Wire/JobSubsystem/Migrations.hs b/libs/wire-subsystems/src/Wire/JobSubsystem/Migrations.hs index c39ac05fc71..920782cc856 100644 --- a/libs/wire-subsystems/src/Wire/JobSubsystem/Migrations.hs +++ b/libs/wire-subsystems/src/Wire/JobSubsystem/Migrations.hs @@ -36,6 +36,7 @@ import Hasql.Connection qualified as HasqlConnection import Hasql.Connection.Settings qualified as HasqlConnectionSettings import Hasql.Decoders qualified as HasqlDecoders import Hasql.Encoders qualified as HasqlEncoders +import Hasql.Pool.Extended (runConnStrParser) import Hasql.Session qualified as HasqlSession import Hasql.Statement qualified as HasqlStatement import Hasql.TH @@ -52,8 +53,8 @@ mkArbiterConnectionString :: Map Text Text -> Maybe FilePathSecrets -> IO Secret mkArbiterConnectionString pgConfig mFpSecrets = do mPw <- for mFpSecrets initCredentials let pgConfig' = maybe pgConfig (\pw -> Map.insert "password" pw pgConfig) mPw - pure . secretText . PostgresqlConnectionString.toKeyValueString $ - PostgresqlConnectionString.fromKeyValueParams pgConfig' + connStr <- runConnStrParser $ PostgresqlConnectionString.fromKeyValueParams pgConfig' + pure . secretText $ PostgresqlConnectionString.toKeyValueString connStr -- | Apply all migrations for the job registry before constructing any worker -- pools or accepting jobs. @@ -171,4 +172,4 @@ withArbiterMigrationLock connStr schemaName action = do releaseArbiterMigrationLock :: HasqlStatement.Statement Int64 () releaseArbiterMigrationLock = - [resultlessStatement|SELECT (1 :: integer) FROM (SELECT pg_advisory_unlock($1 :: bigint))|] + [resultlessStatement|SELECT (1 :: integer) FROM (SELECT pg_advisory_unlock($1 :: bigint)) AS t|] diff --git a/libs/wire-subsystems/src/Wire/MeetingNotifier/Interpreter.hs b/libs/wire-subsystems/src/Wire/MeetingNotifier/Interpreter.hs index 53ee3bbed38..8659a0b5b36 100644 --- a/libs/wire-subsystems/src/Wire/MeetingNotifier/Interpreter.hs +++ b/libs/wire-subsystems/src/Wire/MeetingNotifier/Interpreter.hs @@ -70,10 +70,10 @@ notifyMeetingMembersAddedImpl qUser qConvId mTeamId users = do TinyLog.warn $ Log.msg ("alive meeting not found for meeting member-add event" :: ByteString) . Log.field "conversationId" (toByteString' (qUnqualified qConvId)) - -- `users` are the members added by the commit; the commit creator is already - -- a member and never in `users`, so mkMeetingEventPush (which no longer - -- filters the originator by UserId) does not echo member-add back to them. - -- conn is Nothing: every client connection of each added user should be notified. + -- Recipients are exactly the added users: the commit creator is already a + -- member, so it is structurally absent from `users` and member-add is never + -- echoed back to them. conn is Nothing: every client connection of each + -- added user should be notified. for_ meetings $ \meeting -> pushNotificationAsync $ mkMeetingEventPush diff --git a/libs/wire-subsystems/src/Wire/MeetingsSubsystem/Notification.hs b/libs/wire-subsystems/src/Wire/MeetingsSubsystem/Notification.hs index 7eb3ad27faa..2fa1e7de2a8 100644 --- a/libs/wire-subsystems/src/Wire/MeetingsSubsystem/Notification.hs +++ b/libs/wire-subsystems/src/Wire/MeetingsSubsystem/Notification.hs @@ -31,6 +31,8 @@ import Wire.API.Push.V2 qualified as PushV2 import Wire.NotificationSubsystem -- | Build the common push event structure used by all meeting lifecycle events. +-- Delivered to all channels including native push (APNs/FCM), matching the +-- regular-conversation event convention (RouteAny). mkMeetingEventPush :: UTCTime -> Qualified UserId -> @@ -55,6 +57,6 @@ mkMeetingEventPush now qUser conn recipients qConvId mTeamId meetingType qMeetin evtTeam = mTeamId }, recipients = recipients, - route = PushV2.RouteDirect, + route = PushV2.RouteAny, conn } diff --git a/libs/wire-subsystems/src/Wire/Migration.hs b/libs/wire-subsystems/src/Wire/Migration.hs index 325910448ba..b15edbfeb47 100644 --- a/libs/wire-subsystems/src/Wire/Migration.hs +++ b/libs/wire-subsystems/src/Wire/Migration.hs @@ -32,12 +32,12 @@ import Hasql.Pool qualified as Hasql import Imports import Polysemy import Polysemy.Async +import Polysemy.AtomicState import Polysemy.Conc hiding (timeout_) import Polysemy.Conc qualified as Conc import Polysemy.Error import Polysemy.Input import Polysemy.Resource -import Polysemy.State import Polysemy.Time import Polysemy.TinyLog import Prometheus qualified @@ -152,7 +152,7 @@ paginateSem q p r = do handleErrors :: forall r. - ( Member (State Int) r, + ( Member (AtomicState Int) r, Member TinyLog r ) => ByteString -> @@ -167,7 +167,28 @@ handleErrors key action = do Log.msg (Log.val "error occurred during migration") . Log.field "key" (show key) . Log.field "error" (show e) - modify (+ 1) + atomicModify (+ 1) + +handleLockAndDBErrors :: + ( Member (AtomicState Int) r, + Member TinyLog r + ) => + ByteString -> + (Sem (Error MigrationLockError : Error Hasql.UsageError : r) ()) -> + Sem r () +handleLockAndDBErrors key action = do + eithErr <- runError (runError action) + case eithErr of + Right (Right _) -> pure () + Right (Left e) -> logError (show e) + Left e -> logError (show e) + where + logError e = do + warn $ + Log.msg (Log.val "error occurred during migration") + . Log.field "key" (show key) + . Log.field "error" e + atomicModify (+ 1) withExclusiveMigrationLockAndTimeout :: forall x r. diff --git a/libs/wire-subsystems/src/Wire/MigrationLock.hs b/libs/wire-subsystems/src/Wire/MigrationLock.hs index 8c97876170f..c75bec048cb 100644 --- a/libs/wire-subsystems/src/Wire/MigrationLock.hs +++ b/libs/wire-subsystems/src/Wire/MigrationLock.hs @@ -86,6 +86,8 @@ data MigrationLockError = TimedOutAcquiringLock instance APIError MigrationLockError where toResponse = waiErrorToJSONResponse . migrationLockErrorToWai +instance Exception MigrationLockError + migrationLockErrorToHttpError :: MigrationLockError -> HttpError migrationLockErrorToHttpError = StdError . migrationLockErrorToWai @@ -117,7 +119,8 @@ withMigrationLocks lockType maxWait lockables action = do pool <- (.rawPool) <$> input @HasqlPoolExt.Pool lockThread <- async . embed . Hasql.use pool $ do - let lockIds = fmap lockKey lockables + -- Sort lockIds to avoid deadlocks + let lockIds = sort $ fmap lockKey lockables Session.statement lockIds acquireLocks liftIO $ putMVar lockAcquired () @@ -154,11 +157,11 @@ withMigrationLocks lockType maxWait lockables action = do LockExclusive -> [resultlessStatement|SELECT (1 :: int) FROM (SELECT pg_advisory_lock(lockId) - FROM (SELECT UNNEST($1 :: bigint[]) as lockId))|] + FROM (SELECT UNNEST($1 :: bigint[]) as lockId) AS t) AS t2|] LockShared -> [resultlessStatement|SELECT (1 :: int) FROM (SELECT pg_advisory_lock_shared(lockId) - FROM (SELECT UNNEST($1 :: bigint[]) as lockId))|] + FROM (SELECT UNNEST($1 :: bigint[]) as lockId) AS t) AS t2|] releaseLocks :: Hasql.Statement [Int64] () releaseLocks = @@ -167,15 +170,13 @@ withMigrationLocks lockType maxWait lockables action = do LockExclusive -> [resultlessStatement|SELECT (1 :: int) FROM (SELECT pg_advisory_unlock(lockId) - FROM (SELECT UNNEST($1 :: bigint[]) as lockId))|] + FROM (SELECT UNNEST($1 :: bigint[]) as lockId) AS t) AS t2|] LockShared -> [resultlessStatement|SELECT (1 :: int) FROM (SELECT pg_advisory_unlock_shared(lockId) - FROM (SELECT UNNEST($1 :: bigint[]) as lockId))|] + FROM (SELECT UNNEST($1 :: bigint[]) as lockId) AS t) AS t2|] -------------------------------------------------------------------------------- --- INSTANCES - -- Combines team id and feature name into one lock key to keep per-feature locks distinct within a team -- without introducing a separate lock table; rotate+xor mixes the two hashes to reduce collisions. instance MigrationLockable (TeamId, Text) where diff --git a/libs/wire-subsystems/src/Wire/PostgresMigrations.hs b/libs/wire-subsystems/src/Wire/PostgresMigrations.hs index cc0ccefa378..75b696f8e74 100644 --- a/libs/wire-subsystems/src/Wire/PostgresMigrations.hs +++ b/libs/wire-subsystems/src/Wire/PostgresMigrations.hs @@ -90,7 +90,7 @@ runAllMigrations pool logger = do unlockNonTransactionMigration :: Hasql.Statement Int64 () unlockNonTransactionMigration = - [resultlessStatement|SELECT (1 :: integer) FROM (SELECT pg_advisory_unlock($1 :: bigint))|] + [resultlessStatement|SELECT (1 :: integer) FROM (SELECT pg_advisory_unlock($1 :: bigint)) AS t|] -- We don't have to use 'bracket' here because failing in the session should -- cause the session to drop and any acquired locks get automatically diff --git a/libs/wire-subsystems/src/Wire/SparAPIAccess.hs b/libs/wire-subsystems/src/Wire/SparAPIAccess.hs index b2df76bd01a..0a6005162d7 100644 --- a/libs/wire-subsystems/src/Wire/SparAPIAccess.hs +++ b/libs/wire-subsystems/src/Wire/SparAPIAccess.hs @@ -27,6 +27,7 @@ import Wire.API.User.IdentityProvider data SparAPIAccess m a where GetIdentityProviders :: TeamId -> SparAPIAccess m IdPList DeleteTeam :: TeamId -> SparAPIAccess m () + DeleteScimUser :: TeamId -> UserId -> SparAPIAccess m () LookupScimUserInfo :: UserId -> SparAPIAccess m ScimUserInfo makeSem ''SparAPIAccess diff --git a/libs/wire-subsystems/src/Wire/SparAPIAccess/Rpc.hs b/libs/wire-subsystems/src/Wire/SparAPIAccess/Rpc.hs index fc08de1b81d..a76692c5ffd 100644 --- a/libs/wire-subsystems/src/Wire/SparAPIAccess/Rpc.hs +++ b/libs/wire-subsystems/src/Wire/SparAPIAccess/Rpc.hs @@ -49,6 +49,7 @@ interpretSparAPIAccessToRpc sparEndpoint = runInputConst sparEndpoint . \case GetIdentityProviders tid -> getIdentityProvidersImpl tid DeleteTeam tid -> deleteTeamImpl tid + DeleteScimUser tid uid -> deleteScimUserImpl tid uid LookupScimUserInfo uid -> lookupScimUserInfoImpl uid sparRequest :: @@ -93,6 +94,15 @@ deleteTeamImpl tid = do . paths ["i", "teams", toByteString' tid] . expect2xx +deleteScimUserImpl :: (Member (Input Endpoint) r, Member Rpc r) => TeamId -> UserId -> Sem r () +deleteScimUserImpl tid uid = do + void $ sparRequest delReq + where + delReq = + method DELETE + . paths ["i", "scim", "users", toByteString' tid, toByteString' uid] + . expect2xx + -- | Get the SCIM user info for a user. lookupScimUserInfoImpl :: ( Member (Error ParseException) r, diff --git a/libs/wire-subsystems/src/Wire/TeamFeatureStore/Migration.hs b/libs/wire-subsystems/src/Wire/TeamFeatureStore/Migration.hs index 1edeb7daf2c..048193e3f16 100644 --- a/libs/wire-subsystems/src/Wire/TeamFeatureStore/Migration.hs +++ b/libs/wire-subsystems/src/Wire/TeamFeatureStore/Migration.hs @@ -27,11 +27,11 @@ import Hasql.Pool.Extended qualified as Hasql import Imports import Polysemy import Polysemy.Async +import Polysemy.AtomicState import Polysemy.Conc import Polysemy.Error import Polysemy.Input import Polysemy.Resource (Resource, resourceToIOFinal) -import Polysemy.State import Polysemy.TinyLog import Prometheus qualified import System.Logger qualified as Log @@ -49,7 +49,7 @@ migrateAllTeamFeatures :: Member (Embed IO) r, Member (Input ClientState) r, Member TinyLog r, - Member (State Int) r, + Member (AtomicState Int) r, Member Async r, Member Race r, Member Resource r @@ -65,7 +65,7 @@ migrateAllTeamFeatures migOpts migCounter migDuration = do .| C.mapM_ (traverse_ (\row@(tid, feat, _, _, _) -> handleErrors (toByteString' (idToText tid <> " - " <> feat)) (migrateTeamFeature migOpts migCounter migDuration row))) type EffectStack = - [ State Int, + [ AtomicState Int, Input ClientState, Input Hasql.Pool, Resource, @@ -107,7 +107,7 @@ interpreter cassClient pgPool logger name = . resourceToIOFinal . runInputConst pgPool . runInputConst cassClient - . runState 0 + . atomicStateToIO 0 migrateTeamFeature :: ( PGConstraints r, @@ -134,7 +134,7 @@ migrateTeamFeature migOpts migCounter migDuration (tid, name, status, lockStatus liftIO $ Prometheus.incCounter migCounter handleErrors :: - ( Member (State Int) r, + ( Member (AtomicState Int) r, Member TinyLog r ) => ByteString -> @@ -149,10 +149,10 @@ handleErrors key action = do Log.msg (Log.val "error occurred during migration") . Log.field "key" (show key) . Log.field "error" (show e) - modify (+ 1) + atomicModify (+ 1) Left e -> do warn $ Log.msg (Log.val "error occurred during migration") . Log.field "key" (show key) . Log.field "error" (show e) - modify (+ 1) + atomicModify (+ 1) diff --git a/libs/wire-subsystems/src/Wire/UserStore/Cassandra.hs b/libs/wire-subsystems/src/Wire/UserStore/Cassandra.hs index 6226347fece..54fefc2d485 100644 --- a/libs/wire-subsystems/src/Wire/UserStore/Cassandra.hs +++ b/libs/wire-subsystems/src/Wire/UserStore/Cassandra.hs @@ -15,27 +15,42 @@ -- You should have received a copy of the GNU Affero General Public License along -- with this program. If not, see . -module Wire.UserStore.Cassandra (interpretUserStoreCassandra) where +module Wire.UserStore.Cassandra + ( interpretUserStoreCassandra, + interpretUserStoreToCassandraAndPostgres, + ) +where import Cassandra import Cassandra.Exec (prepared) import Control.Lens ((^.)) import Data.Handle import Data.Id -import Database.CQL.Protocol +import Data.Map qualified as Map +import Data.UUID qualified as UUID +import Database.CQL.Protocol hiding (Error) import Imports import Polysemy +import Polysemy.Async (Async) +import Polysemy.Conc (Race) import Polysemy.Embed import Polysemy.Error +import Polysemy.Resource (Resource) +import Polysemy.Time +import Polysemy.TinyLog (TinyLog) import Wire.API.Password (Password) import Wire.API.Provider.Service import Wire.API.Team.Feature (FeatureStatus) import Wire.API.User hiding (DeleteUser) import Wire.API.User.RichInfo import Wire.API.User.Search (SetSearchable (SetSearchable)) +import Wire.MigrationLock +import Wire.Postgres (PGConstraints) import Wire.StoredUser import Wire.UserStore +import Wire.UserStore qualified as UserStore import Wire.UserStore.IndexUser hiding (userId) +import Wire.UserStore.Postgres (interpretUserStorePostgres) import Wire.UserStore.Unique interpretUserStoreCassandra :: (Member (Embed IO) r) => ClientState -> InterpreterFor UserStore r @@ -79,6 +94,197 @@ interpretUserStoreCassandra casClient = LookupServiceUsers pid sid mPagingState -> lookupServiceUsersImpl pid sid (paginationStateCassandra =<< mPagingState) LookupServiceUsersForTeam pid sid tid mPagingState -> lookupServiceUsersForTeamImpl pid sid tid (paginationStateCassandra =<< mPagingState) +interpretUserStoreToCassandraAndPostgres :: + ( PGConstraints r, + Member Async r, + Member TinyLog r, + Member Race r, + Member Resource r, + Member (Error MigrationLockError) r + ) => + ClientState -> InterpreterFor UserStore r +interpretUserStoreToCassandraAndPostgres casClient = + interpret $ \case + CreateUser new mbConv -> do + -- Store new users in postgresql + withMigrationLocks LockShared (MilliSeconds 500) [new.id] $ do + isUserInCass <- interpretUserStoreCassandra casClient $ UserStore.doesUserExist new.id + if isUserInCass + then interpretUserStoreCassandra casClient $ UserStore.createUser new mbConv + else interpretUserStorePostgres $ UserStore.createUser new mbConv + ActivateUser uid identity -> + runAppropriateInterpreter casClient uid $ UserStore.activateUser uid identity + DeactivateUser uid -> + runAppropriateInterpreter casClient uid $ UserStore.deactivateUser uid + GetUsers uids -> + withMigrationLocks LockShared (Seconds 2) uids $ do + let indexByUserId = foldr (\storedUser -> Map.insert storedUser.id storedUser) Map.empty + cassUsers <- indexByUserId <$> interpretUserStoreCassandra casClient (UserStore.getUsers uids) + pgUsers <- indexByUserId <$> interpretUserStorePostgres (UserStore.getUsers uids) + pure $ mapMaybe (\uid -> Map.lookup uid pgUsers <|> Map.lookup uid cassUsers) uids + DoesUserExist uid -> do + withMigrationLocks LockShared (MilliSeconds 500) [uid] $ do + isUserInPg <- interpretUserStorePostgres $ UserStore.doesUserExist uid + if isUserInPg + then pure True + else interpretUserStoreCassandra casClient $ UserStore.doesUserExist uid + GetIndexUser uid -> + runAppropriateInterpreter casClient uid $ UserStore.getIndexUser uid + GetIndexUsersPaginated pageSize mPagingState -> do + paginateOverCassandraAndPostgres + (\size state -> interpretUserStoreCassandra casClient $ UserStore.getIndexUsersPaginated size state) + (\size state -> interpretUserStorePostgres $ UserStore.getIndexUsersPaginated size state) + (PagingExitingUsers $ Id UUID.nil) + pageSize + mPagingState + UpdateUser uid update -> + runAppropriateInterpreter casClient uid $ UserStore.updateUser uid update + UpdateEmail uid email -> + runAppropriateInterpreter casClient uid $ UserStore.updateEmail uid email + DeleteEmail uid -> + runAppropriateInterpreter casClient uid $ UserStore.deleteEmail uid + UpdateEmailUnvalidated uid email -> + runAppropriateInterpreter casClient uid $ UserStore.updateEmailUnvalidated uid email + DeleteEmailUnvalidated uid -> + runAppropriateInterpreter casClient uid $ UserStore.deleteEmailUnvalidated uid + LookupName uid -> + runAppropriateInterpreter casClient uid $ UserStore.lookupName uid + LookupHandle hdl -> do + let action = UserStore.lookupHandle hdl + interpretUserStorePostgres action >>= \case + Nothing -> interpretUserStoreCassandra casClient action + Just user -> pure $ Just user + GlimpseHandle hdl -> do + let action = UserStore.glimpseHandle hdl + interpretUserStorePostgres action >>= \case + Nothing -> interpretUserStoreCassandra casClient action + Just uid -> pure $ Just uid + UpdateUserHandleEither uid update -> do + -- There is no easy way to handle the race condition that Alice in + -- Cassandra and Bob in Postgresql don't claim the same handle. If they + -- race to claim a handle, they _can_ both succeed. In this case, the + -- migration code _could_ fail to migrate the Alice user, so it has to be + -- careful about handling this case. + withMigrationLocks LockShared (MilliSeconds 500) [uid] $ do + let glimpseAction = UserStore.glimpseHandle update.new + cassGlimpse <- interpretUserStoreCassandra casClient glimpseAction + pgGlimpse <- interpretUserStorePostgres glimpseAction + case (cassGlimpse, pgGlimpse) of + (_, Just pgClaimer) + | pgClaimer == uid -> pure $ Right () + | otherwise -> pure $ Left StoredUserUpdateHandleExists + (Just casClaimer, Nothing) + | casClaimer == uid -> pure $ Right () + | otherwise -> pure $ Left StoredUserUpdateHandleExists + (Nothing, Nothing) -> do + isUserInPg <- interpretUserStorePostgres $ UserStore.doesUserExist uid + let action = UserStore.updateUserHandleEither uid update + if isUserInPg + then interpretUserStorePostgres action + else interpretUserStoreCassandra casClient action + UpdateSSOId uid ssoId -> + runAppropriateInterpreter casClient uid $ UserStore.updateSSOId uid ssoId + UpdateManagedBy uid managedBy -> + runAppropriateInterpreter casClient uid $ UserStore.updateManagedBy uid managedBy + UpdateAccountStatus uid accountStatus -> + runAppropriateInterpreter casClient uid $ UserStore.updateAccountStatus uid accountStatus + UpdateRichInfo uid richInfo -> + runAppropriateInterpreter casClient uid $ UserStore.updateRichInfo uid richInfo + UpdateFeatureConferenceCalling uid feat -> + runAppropriateInterpreter casClient uid $ UserStore.updateFeatureConferenceCalling uid feat + LookupFeatureConferenceCalling uid -> + runAppropriateInterpreter casClient uid $ UserStore.lookupFeatureConferenceCalling uid + DeleteUser user -> + runAppropriateInterpreter casClient (userId user) $ UserStore.deleteUser user + LookupStatus uid -> + runAppropriateInterpreter casClient uid $ UserStore.lookupStatus uid + IsActivated uid -> + runAppropriateInterpreter casClient uid $ UserStore.isActivated uid + LookupLocale uid -> + runAppropriateInterpreter casClient uid $ UserStore.lookupLocale uid + GetUserTeam uid -> + runAppropriateInterpreter casClient uid $ UserStore.getUserTeam uid + UpdateUserTeam uid tid -> + runAppropriateInterpreter casClient uid $ UserStore.updateUserTeam uid tid + GetRichInfo uid -> + runAppropriateInterpreter casClient uid $ UserStore.getRichInfo uid + UpsertHashedPassword uid pw -> + runAppropriateInterpreter casClient uid $ UserStore.upsertHashedPassword uid pw + LookupHashedPassword uid -> + runAppropriateInterpreter casClient uid $ UserStore.lookupHashedPassword uid + GetUserAuthenticationInfo uid -> + runAppropriateInterpreter casClient uid $ UserStore.getUserAuthenticationInfo uid + SetUserSearchable uid searchable -> + runAppropriateInterpreter casClient uid $ UserStore.setUserSearchable uid searchable + DeleteServiceUser pid sid bid -> + runAppropriateInterpreter casClient (botUserId bid) $ UserStore.deleteServiceUser pid sid bid + LookupServiceUsers pid sid mPagingState -> + -- Ignoring the size paramter here makes us potentially return upto 199 + -- bots instead of 100, but this is ok as this is temporary and the + -- callers are not doing anything wrong with a longer list. + paginateOverCassandraAndPostgres + (\_size state -> interpretUserStoreCassandra casClient $ UserStore.lookupServiceUsers pid sid state) + (\_size state -> interpretUserStorePostgres $ UserStore.lookupServiceUsers pid sid state) + (BotId $ Id UUID.nil) + 100 + mPagingState + LookupServiceUsersForTeam pid sid tid mPagingState -> + -- Ignoring the size paramter here makes us potentially return upto 199 + -- bots instead of 100, but this is ok as this is temporary and the + -- callers are not doing anything wrong with a longer list. + paginateOverCassandraAndPostgres + (\_size state -> interpretUserStoreCassandra casClient $ UserStore.lookupServiceUsersForTeam pid sid tid state) + (\_size state -> interpretUserStorePostgres $ UserStore.lookupServiceUsersForTeam pid sid tid state) + (BotId $ Id UUID.nil) + 100 + mPagingState + +runAppropriateInterpreter :: + ( PGConstraints r, + Member TinyLog r, + Member (Error MigrationLockError) r, + Member Async r, + Member Race r, + Member Resource r + ) => + ClientState -> UserId -> InterpreterFor UserStore r +runAppropriateInterpreter casClient uid action = + withMigrationLocks LockShared (MilliSeconds 500) [uid] $ do + isUserInPg <- interpretUserStorePostgres $ UserStore.doesUserExist uid + if isUserInPg + then interpretUserStorePostgres action + else interpretUserStoreCassandra casClient action + +paginateOverCassandraAndPostgres :: + (Int32 -> Maybe (GeneralPaginationState pgMarker) -> Sem r (PageWithState pgMarker pageItem)) -> + (Int32 -> Maybe (GeneralPaginationState pgMarker) -> Sem r (PageWithState pgMarker pageItem)) -> + pgMarker -> + Int32 -> + Maybe (GeneralPaginationState pgMarker) -> + Sem r (PageWithState pgMarker pageItem) +paginateOverCassandraAndPostgres getCasPage getPgPage pgStartingMarker pageSize mPagingState = do + let getPageFromCassandra = do + casPage <- getCasPage pageSize mPagingState + if pwsHasMore casPage + then pure casPage + else do + let casSize = fromIntegral (length casPage.pwsResults) + remainingSize = pageSize - casSize + if remainingSize > 0 + then do + pgPage <- getPageFromPostgres remainingSize Nothing + pure + PageWithState + { pwsResults = casPage.pwsResults <> pgPage.pwsResults, + pwsState = pgPage.pwsState + } + else pure $ casPage {pwsState = Just (PaginationStatePostgres pgStartingMarker)} + getPageFromPostgres remainingSize mPgMarker = + getPgPage remainingSize (PaginationStatePostgres <$> mPgMarker) + case mPagingState of + Just (PaginationStatePostgres pgMarker) -> getPageFromPostgres pageSize (Just pgMarker) + _ -> getPageFromCassandra + createUserImpl :: NewStoredUser -> Maybe (ConvId, Maybe TeamId) -> Client () createUserImpl new mbConv = retry x5 . batch $ do setType BatchLogged diff --git a/libs/wire-subsystems/src/Wire/UserStore/Migration.hs b/libs/wire-subsystems/src/Wire/UserStore/Migration.hs new file mode 100644 index 00000000000..ebfe29541d8 --- /dev/null +++ b/libs/wire-subsystems/src/Wire/UserStore/Migration.hs @@ -0,0 +1,379 @@ +{-# LANGUAGE RecordWildCards #-} +{-# OPTIONS_GHC -Wno-ambiguous-fields #-} + +-- This file is part of the Wire Server implementation. +-- +-- Copyright (C) 2026 Wire Swiss GmbH +-- +-- This program is free software: you can redistribute it and/or modify it under +-- the terms of the GNU Affero General Public License as published by the Free +-- Software Foundation, either version 3 of the License, or (at your option) any +-- later version. +-- +-- This program is distributed in the hope that it will be useful, but WITHOUT +-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +-- details. +-- +-- You should have received a copy of the GNU Affero General Public License along +-- with this program. If not, see . + +module Wire.UserStore.Migration where + +import Cassandra hiding (Set) +import Cassandra.Util +import Conduit +import Data.Conduit.List qualified as C +import Data.Handle +import Data.Id +import Data.Json.Util (UTCTimeMillis) +import Data.Misc +import Data.Time +import Database.CQL.Protocol (Record (..), TupleType) +import Hasql.Pool.Extended +import Hasql.Statement qualified as Hasql +import Hasql.TH (resultlessStatement, singletonStatement) +import Hasql.Transaction qualified as Transaction +import Hasql.Transaction.Sessions (IsolationLevel (..), Mode (..)) +import Imports +import Polysemy +import Polysemy.Async +import Polysemy.AtomicState +import Polysemy.Conc +import Polysemy.Error +import Polysemy.Input +import Polysemy.Resource +import Polysemy.TinyLog +import Prometheus qualified +import System.Logger.Class qualified as Log +import Wire.API.Password +import Wire.API.PostgresMarshall +import Wire.API.User +import Wire.API.User.RichInfo +import Wire.Migration +import Wire.MigrationLock +import Wire.Postgres +import Wire.Sem.Concurrency +import Wire.Sem.Concurrency.IO (unsafelyPerformConcurrency) +import Wire.Sem.Logger +import Wire.Sem.Logger.TinyLog (loggerToTinyLog) +import Wire.UserStore.Migration.Types +import Wire.UserStore.Postgres + +migrateUsersLoop :: + MigrationOptions -> + ClientState -> + Pool -> + Log.Logger -> + Prometheus.Counter -> + Prometheus.Counter -> + Prometheus.Counter -> + Prometheus.Vector Text Prometheus.Histogram -> + IO () +migrateUsersLoop migOpts cassClient pgPool logger migCounter migFinished migFailed migDuration = + migrationLoop + logger + "users" + migFinished + migFailed + (interpreter cassClient pgPool logger "users") + (migrateAllUsers migOpts migCounter migDuration) + +type EffectStack = + [ AtomicState Int, + Input ClientState, + Input Pool, + Resource, + Async, + Race, + TinyLog, + Embed IO, + Concurrency 'Unsafe, + Final IO + ] + +interpreter :: ClientState -> Pool -> Log.Logger -> ByteString -> Sem EffectStack a -> IO (Int, a) +interpreter cassClient pgPool logger name = + runFinal + . unsafelyPerformConcurrency + . embedToFinal + . loggerToTinyLog logger + . mapLogger (Log.field "migration" name .) + . raiseUnder + . interpretRace + . asyncToIOFinal + . resourceToIOFinal + . runInputConst pgPool + . runInputConst cassClient + . atomicStateToIO 0 + +migrateAllUsers :: + ( Member TinyLog r, + Member (Input ClientState) r, + Member (Embed IO) r, + Member (AtomicState Int) r, + Member (Concurrency Unsafe) r, + Member (Input Pool) r, + Member Async r, + Member Race r, + Member Resource r + ) => + MigrationOptions -> Prometheus.Counter -> Prometheus.Vector Text Prometheus.Histogram -> ConduitM () Void (Sem r) () +migrateAllUsers migOpts migCounter migDuration = do + lift $ info $ Log.msg (Log.val "migrateAllUsers") + withCount (paginateSem select (paramsP LocalQuorum () migOpts.pageSize) x5) + .| logRetrievedPage migOpts.pageSize runIdentity + .| C.mapM_ (unsafePooledMapConcurrentlyN_ migOpts.parallelism (\uid -> handleLockAndDBErrors "user" (migrateUser migOpts.timeout migCounter migDuration uid))) + where + select :: PrepQuery R () (Identity UserId) + select = "select id from user" + +migrateUser :: + ( PGConstraints r, + Member TinyLog r, + Member (Error MigrationLockError) r, + Member Async r, + Member Race r, + Member Resource r, + Member (Input ClientState) r + ) => + Duration -> Prometheus.Counter -> Prometheus.Vector Text Prometheus.Histogram -> UserId -> Sem r () +migrateUser migTimeout migCounter migDuration uid = + withExclusiveMigrationLockAndTimeout migTimeout migDuration [uid] $ do + cState <- input + mCassData <- runClient cState $ getUserData uid + case mCassData of + Nothing -> pure () + Just cassData -> do + let eithPGRow = mkUserRowPG cassData.id cassData.user cassData.handleClaimValidity cassData.richInfo + case eithPGRow of + Left e -> + warn $ + Log.msg (Log.val "Invalid user found, skipping") + . Log.field "id" (idToText cassData.id) + . Log.field "error" (show e) + Right pgRow -> do + case cassData.handleClaimValidity of + HandleClaimValid -> pure () + HandleNotClaimed -> + info $ + Log.msg (Log.val "This user has a handle which is not 'claimed' by anyone, this user will lose their handle") + . Log.field "user" (idToText pgRow.id_) + . Log.field "handle" (show $ fromHandle <$> cassData.user.handle) + HandleClaimedByAnotherUser claimedBy -> do + warn $ + Log.msg (Log.val "This user has a handle claimed by someone else, this user will lose their handle") + . Log.field "user" (idToText pgRow.id_) + . Log.field "handle" (show $ fromHandle <$> cassData.user.handle) + . Log.field "legitimate_claim_by" (idToText claimedBy) + saveToPostgres pgRow cassData.serviceConv + let mServiceTeam = (.teamId) =<< cassData.serviceConv + runClient cState $ deleteFromCassandra pgRow.id_ pgRow.handle ((,,mServiceTeam) <$> pgRow.providerId <*> pgRow.serviceId) + markDeletionComplete pgRow.id_ + liftIO $ Prometheus.incCounter migCounter + +getUserData :: UserId -> Client (Maybe RawUserData) +getUserData uid = do + mUserRow <- asRecord <$$> query1 selectUserRow (params LocalQuorum (Identity uid)) + case mUserRow of + Nothing -> pure Nothing + Just user -> do + serviceConv <- case (,) <$> user.providerId <*> user.serviceId of + Nothing -> pure Nothing + Just (pid, sid) -> asRecord <$$> query1 selectServiceConv (params LocalQuorum (pid, sid, uid)) + handleClaimValidity <- case user.handle of + Nothing -> pure HandleClaimValid + Just h -> do + mClaimedBy <- runIdentity <$$> query1 selectHandleClaim (params LocalQuorum (Identity h)) + case mClaimedBy of + Nothing -> pure HandleNotClaimed + Just claimedBy + | claimedBy == uid -> pure HandleClaimValid + | otherwise -> pure $ HandleClaimedByAnotherUser claimedBy + richInfo <- runIdentity <$$> query1 selectRichInfo (params LocalQuorum (Identity uid)) + pure $ Just RawUserData {id = uid, ..} + where + selectUserRow :: PrepQuery R (Identity UserId) (TupleType UserRowCass) + selectUserRow = + "SELECT accent_id, activated, country, email, email_unvalidated,\ + \expires, feature_conference_calling, handle, language, managed_by, \ + \name, password, provider, searchable, service,\ + \sso_id, status, supported_protocols, team, text_status,\ + \user_type, assets, picture, writetime(activated)\ + \FROM user WHERE id = ?" + + selectServiceConv :: PrepQuery R (ProviderId, ServiceId, UserId) (TupleType ServiceConv) + selectServiceConv = "SELECT conv, team FROM service_user WHERE provider = ? AND service = ? AND user = ?" + + selectHandleClaim :: PrepQuery R (Identity Handle) (Identity UserId) + selectHandleClaim = "SELECT user FROM user_handle WHERE handle = ?" + + selectRichInfo :: PrepQuery R (Identity UserId) (Identity RichInfoAssocList) + selectRichInfo = "SELECT json FROM rich_info where user = ?" + +data InvalidUserError = UserHasNoName | UserHasNoActivated + deriving (Show) + +mkUserRowPG :: UserId -> UserRowCass -> HandleClaimValidity -> Maybe RichInfoAssocList -> Either InvalidUserError UserRowPG +mkUserRowPG id_ cass@UserRowCass {..} handleClaimValidity richInfo = run . runError $ do + pgName <- note UserHasNoName cass.name + pgActivated <- note UserHasNoActivated cass.activated + createdAt <- note UserHasNoActivated $ writetimeToUTC <$> cass.activatedWriteTime + pure $ + UserRowPG + { accentId = fromMaybe defaultAccentId cass.accentId, + userType = fromMaybe UserTypeRegular cass.userType, + name = pgName, + activated = pgActivated, + handle = case handleClaimValidity of + HandleClaimValid -> cass.handle + HandleNotClaimed -> + -- In this case if we just give this handle to the current user, + -- there could be other users with the same situation. We cannot tie + -- break here, so we just take away the handle from all users + Nothing + HandleClaimedByAnotherUser _ -> + -- Handle is claimed by someone else, so this user cannot get to + -- keep it. + Nothing, + .. + } + +{- ORMOLU_DISABLE -} +type UserTuplePG = + (UserId, ColourId, Bool, Maybe Country, Maybe EmailAddress, + Maybe EmailAddress, Maybe UTCTimeMillis, Maybe Int32, Maybe Handle, Maybe Language, + Maybe ManagedBy, Name, Maybe Password, Maybe ProviderId, Maybe ServiceId, + Maybe UserSSOId, Maybe AccountStatus, Maybe (Set BaseProtocolTag), Maybe TeamId, Maybe TextStatus, + UserType, Maybe Pict, Maybe RichInfoAssocList, Maybe Bool, UTCTime + ) + +userRowPGToTuple :: UserRowPG -> UserTuplePG +userRowPGToTuple user = + (user.id_, user.accentId, user.activated, user.country,user.email, + user.emailUnvalidated, user.expires, user.featureConferenceCalling, user.handle, user.language, + user.managedBy, user.name, user.password, user.providerId, user.serviceId, + user.ssoId, user.status, user.supportedProtocols, user.teamId, user.textStatus, + user.userType, user.pict, user.richInfo, user.searchable, user.createdAt) +{- ORMOLU_ENABLE -} + +saveToPostgres :: (PGConstraints r, Member TinyLog r) => UserRowPG -> Maybe ServiceConv -> Sem r () +saveToPostgres user mServiceConv = do + isHandleRemoved <- runTransactionWithRetry Serializable Write $ do + isHandleRemoved <- case user.status of + -- bots are deleted by just updating their status to deleted and deleting + -- the rows in service_user and service_team tables. + Just Deleted + | user.userType /= UserTypeBot -> do + Transaction.statement (user.id_, user.teamId, user.createdAt) insertDeleted + pure False + _ -> do + removeHandle <- + maybe + (pure False) + (\h -> Transaction.statement (user.id_, h) isHandleTaken) + user.handle + let userTuple = + userRowPGToTuple $ + if removeHandle + then user {handle = Nothing} + else user + Transaction.statement userTuple insertUser + for_ user.assets $ \assets -> do + Transaction.statement user.id_ deleteAssetsStatement + Transaction.statement (mkAssetRows user.id_ assets) insertAssetsStatement + when (user.status /= Just Deleted) $ do + for_ mServiceConv $ \serviceConv -> + Transaction.statement (user.id_, serviceConv.convId, serviceConv.teamId) insertBotConv + pure removeHandle + Transaction.statement user.id_ markPendingDelete + pure isHandleRemoved + + when isHandleRemoved . warn $ + Log.msg (Log.val "Duplicate handle claim found, this user doesn't have a handle anymore") + . Log.field "user" (idToText user.id_) + . Log.field "handle" (show $ fromHandle <$> user.handle) + where + isHandleTaken :: Hasql.Statement (UserId, Handle) Bool + isHandleTaken = + dimapPG + [singletonStatement| + SELECT EXISTS (SELECT 1 FROM wire_user where handle = $2 :: text AND id != $1 :: uuid) :: bool + |] + insertDeleted :: Hasql.Statement (UserId, Maybe TeamId, UTCTime) () + insertDeleted = + lmapPG + [resultlessStatement| + INSERT INTO deleted_user + (id, team, created_at) + VALUES ($1 :: uuid, $2 :: uuid?, $3 :: timestamptz) + ON CONFLICT (id) DO NOTHING + |] + insertUser :: Hasql.Statement UserTuplePG () + insertUser = + lmapPG + [resultlessStatement| + INSERT INTO wire_user + (id, accent_id, activated, country, email, + email_unvalidated, expires, feature_conference_calling, handle, language, + managed_by, name, password, provider, service, + sso_id, account_status, supported_protocols, team, text_status, + user_type, picture, rich_info, searchable, created_at + ) + VALUES + ($1 :: uuid, $2 :: integer, $3 :: boolean, $4 :: text?, $5 :: text?, + $6 :: text?, $7 :: timestamptz?, $8 :: integer?, $9 :: text?, $10 :: text?, + $11 :: integer?, $12 :: text, $13 :: text?, $14 :: uuid?, $15 :: uuid?, + $16 :: jsonb?, $17 :: integer?, $18 :: integer?, $19 :: uuid?, $20 :: text?, + $21 :: integer, $22 :: jsonb?, $23 :: jsonb?, $24 :: boolean?, $25 :: timestamptz + ) + ON CONFLICT (id) DO NOTHING + |] + insertBotConv :: Hasql.Statement (UserId, ConvId, Maybe TeamId) () + insertBotConv = + lmapPG + [resultlessStatement| + INSERT INTO bot_conv + (id, conv, conv_team) + VALUES ($1 :: uuid, $2 :: uuid, $3 :: uuid?) + |] + + markPendingDelete :: Hasql.Statement UserId () + markPendingDelete = + lmapPG + [resultlessStatement| + INSERT INTO user_migration_pending_deletes (id) + VALUES ($1 :: uuid) + ON CONFLICT (id) DO NOTHING + |] + +markDeletionComplete :: (PGConstraints r) => UserId -> Sem r () +markDeletionComplete uid = + runStatement uid stmt + where + stmt :: Hasql.Statement UserId () + stmt = lmapPG [resultlessStatement|DELETE FROM user_migration_pending_deletes WHERE id = $1 :: uuid|] + +deleteFromCassandra :: UserId -> Maybe Handle -> Maybe (ProviderId, ServiceId, Maybe TeamId) -> Client () +deleteFromCassandra uid mHandle mService = do + for_ mHandle $ \handle -> write deleteHandle (params LocalQuorum (Identity handle)) + for_ mService $ \(pid, sid, mTid) -> do + write deleteServiceUser (params LocalQuorum (pid, sid, uid)) + for_ mTid $ \tid -> write deleteServiceTeam (params LocalQuorum (pid, sid, tid, uid)) + write deleteRichInfo (params LocalQuorum (Identity uid)) + write deleteUser (params LocalQuorum (Identity uid)) + where + deleteUser :: PrepQuery W (Identity UserId) () + deleteUser = "DELETE FROM user WHERE id = ?" + + deleteHandle :: PrepQuery W (Identity Handle) () + deleteHandle = "DELETE FROM user_handle WHERE handle = ?" + + deleteServiceUser :: PrepQuery W (ProviderId, ServiceId, UserId) () + deleteServiceUser = "DELETE FROM service_user WHERE provider = ? AND service = ? AND user = ?" + + deleteServiceTeam :: PrepQuery W (ProviderId, ServiceId, TeamId, UserId) () + deleteServiceTeam = "DELETE FROM service_team WHERE provider = ? AND service = ? AND team = ? AND user = ?" + + deleteRichInfo :: PrepQuery W (Identity UserId) () + deleteRichInfo = "DELETE FROM rich_info WHERE user = ?" diff --git a/libs/wire-subsystems/src/Wire/UserStore/Migration/Types.hs b/libs/wire-subsystems/src/Wire/UserStore/Migration/Types.hs new file mode 100644 index 00000000000..07619adc6c5 --- /dev/null +++ b/libs/wire-subsystems/src/Wire/UserStore/Migration/Types.hs @@ -0,0 +1,111 @@ +{-# LANGUAGE TemplateHaskell #-} + +-- This file is part of the Wire Server implementation. +-- +-- Copyright (C) 2026 Wire Swiss GmbH +-- +-- This program is free software: you can redistribute it and/or modify it under +-- the terms of the GNU Affero General Public License as published by the Free +-- Software Foundation, either version 3 of the License, or (at your option) any +-- later version. +-- +-- This program is distributed in the hope that it will be useful, but WITHOUT +-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +-- details. +-- +-- You should have received a copy of the GNU Affero General Public License along +-- with this program. If not, see . + +module Wire.UserStore.Migration.Types where + +import Cassandra.Util +import Data.Handle +import Data.Id +import Data.Json.Util +import Data.Time +import Database.CQL.Protocol (Record (..), TupleType, recordInstance) +import Imports +import Wire.API.Password +import Wire.API.User +import Wire.API.User.RichInfo + +data RawUserData = RawUserData + { id :: UserId, + user :: UserRowCass, + richInfo :: Maybe RichInfoAssocList, + serviceConv :: Maybe ServiceConv, + handleClaimValidity :: HandleClaimValidity + } + +data HandleClaimValidity + = HandleClaimValid + | HandleNotClaimed + | HandleClaimedByAnotherUser UserId + +-- | Some fields are read as 'Maybe' even if they're supposed to always be +-- there. This is to deal with potential old data in the DB. +data UserRowCass = UserRowCass + { accentId :: Maybe ColourId, + activated :: Maybe Bool, + country :: Maybe Country, + email :: Maybe EmailAddress, + emailUnvalidated :: Maybe EmailAddress, + expires :: Maybe UTCTimeMillis, + featureConferenceCalling :: Maybe Int32, + handle :: Maybe Handle, + language :: Maybe Language, + managedBy :: Maybe ManagedBy, + name :: Maybe Name, + password :: Maybe Password, + providerId :: Maybe ProviderId, + searchable :: Maybe Bool, + serviceId :: Maybe ServiceId, + ssoId :: Maybe UserSSOId, + status :: Maybe AccountStatus, + supportedProtocols :: Maybe (Set BaseProtocolTag), + teamId :: Maybe TeamId, + textStatus :: Maybe TextStatus, + userType :: Maybe UserType, + assets :: Maybe [Asset], + pict :: Maybe Pict, + activatedWriteTime :: Maybe (Writetime ()) + } + +data ServiceConv = ServiceConv + { convId :: ConvId, + teamId :: Maybe TeamId + } + +data UserRowPG = UserRowPG + { id_ :: UserId, + accentId :: ColourId, + activated :: Bool, + country :: Maybe Country, + email :: Maybe EmailAddress, + emailUnvalidated :: Maybe EmailAddress, + expires :: Maybe UTCTimeMillis, + featureConferenceCalling :: Maybe Int32, + handle :: Maybe Handle, + language :: Maybe Language, + managedBy :: Maybe ManagedBy, + name :: Name, + password :: Maybe Password, + providerId :: Maybe ProviderId, + searchable :: Maybe Bool, + serviceId :: Maybe ServiceId, + ssoId :: Maybe UserSSOId, + status :: Maybe AccountStatus, + supportedProtocols :: Maybe (Set BaseProtocolTag), + teamId :: Maybe TeamId, + textStatus :: Maybe TextStatus, + userType :: UserType, + assets :: Maybe [Asset], + pict :: Maybe Pict, + richInfo :: Maybe RichInfoAssocList, + createdAt :: UTCTime + } + +recordInstance ''UserRowCass + +recordInstance ''ServiceConv diff --git a/libs/wire-subsystems/src/Wire/UserStore/Postgres.hs b/libs/wire-subsystems/src/Wire/UserStore/Postgres.hs index 88177b95cde..ca9e002bfc5 100644 --- a/libs/wire-subsystems/src/Wire/UserStore/Postgres.hs +++ b/libs/wire-subsystems/src/Wire/UserStore/Postgres.hs @@ -18,7 +18,13 @@ -- You should have received a copy of the GNU Affero General Public License along -- with this program. If not, see . -module Wire.UserStore.Postgres (interpretUserStorePostgres) where +module Wire.UserStore.Postgres + ( interpretUserStorePostgres, + deleteAssetsStatement, + insertAssetsStatement, + mkAssetRows, + ) +where import Cassandra (GeneralPaginationState (PaginationStatePostgres), PageWithState (..), paginationStatePostgres) import Data.Handle diff --git a/libs/wire-subsystems/test/unit/Wire/ConversationSubsystem/MLS/CheckClientsSpec.hs b/libs/wire-subsystems/test/unit/Wire/ConversationSubsystem/MLS/CheckClientsSpec.hs new file mode 100644 index 00000000000..addded975bd --- /dev/null +++ b/libs/wire-subsystems/test/unit/Wire/ConversationSubsystem/MLS/CheckClientsSpec.hs @@ -0,0 +1,169 @@ +-- This file is part of the Wire Server implementation. +-- +-- Copyright (C) 2026 Wire Swiss GmbH +-- +-- This program is free software: you can redistribute it and/or modify it +-- under the terms of the GNU Affero General Public License as published by the +-- Free Software Foundation, either version 3 of the License, or (at your +-- option) any later version. +-- +-- This program is distributed in the hope that it will be useful, but WITHOUT +-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +-- FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License +-- for more details. +-- +-- You should have received a copy of the GNU Affero General Public License +-- along with this program. If not, see . + +module Wire.ConversationSubsystem.MLS.CheckClientsSpec (spec) where + +import Data.Domain (Domain (..)) +import Data.Id +import Data.Map qualified as Map +import Data.Qualified +import Data.UUID qualified as UUID +import Galley.Types.Error (InternalError (..)) +import Imports +import Polysemy +import Polysemy.Async (asyncToIOFinal) +import Polysemy.Error (Error, runError, throw) +import Test.Hspec +import Wire.API.Conversation +import Wire.API.Conversation.Protocol +import Wire.API.Error (runErrorS) +import Wire.API.Error.Galley (GalleyError (MLSClientMismatch, MLSIdentityMismatch), MLSProtocolError) +import Wire.API.Federation.Client (FederatorClient) +import Wire.API.Federation.Error (FederationError (..)) +import Wire.API.MLS.CipherSuite +import Wire.API.MLS.KeyPackage (KeyPackage) +import Wire.API.MLS.LeafNode (LeafIndex) +import Wire.API.MLS.SubConversation (ConvOrSubChoice (..)) +import Wire.BrigAPIAccess (BrigAPIAccess (..)) +import Wire.ConversationStore.MLS.Types +import Wire.ConversationSubsystem.MLS.CheckClients +import Wire.FederationAPIAccess (FederationAPIAccess (..)) +import Wire.StoredConversation (MLSMigrationState (..)) + +data TestBrigFailure = TestBrigFailure + deriving stock (Show) + +data BrigBehavior + = BrigCrashes + | BrigUnused + +spec :: Spec +spec = describe "Wire.ConversationSubsystem.MLS.CheckClients" do + it "aborts the commit when a concurrent brig client-data fetch crashes" $ do + result <- runCheckClients BrigCrashes + case result of + Right (Left (InternalErrorWithDescription _)) -> pure () + _ -> + expectationFailure $ + "expected InternalErrorWithDescription, got: " <> show result + + it "still treats a hushed FederationError as user-unreachable" $ do + result <- runCheckClients BrigUnused + case result of + Right (Right unreachable) -> + fmap qUnqualified unreachable `shouldBe` [userId] + _ -> + expectationFailure $ + "expected unreachable user, got: " <> show result + +-- | Runs 'checkClients' with a layering that mirrors galley's production +-- stack (cf. Galley.App): all pure error interpreters ('runError' and +-- 'runErrorS') sit outside 'asyncToIOFinal', so an 'Error'-effect throw +-- inside a spawned child collapses to 'Nothing' instead of propagating. +runCheckClients :: + BrigBehavior -> + IO (Either TestBrigFailure (Either InternalError [Qualified UserId])) +runCheckClients behavior = + runFinal @IO + . runError @TestBrigFailure + . runError @InternalError + . (fmap (fromMaybe (error "unexpected MLSIdentityMismatch")) . runErrorS @'MLSIdentityMismatch) + . (fmap (fromMaybe (error "unexpected MLSClientMismatch")) . runErrorS @'MLSClientMismatch) + . (fmap (either (error "unexpected MLSProtocolError") id) . runError @MLSProtocolError) + . asyncToIOFinal + . embedToFinal @IO + . interpretTestBrig behavior + . interpretTestFederation + $ checkClients lConv csSuite (newCM (qUserId behavior)) + +interpretTestBrig :: + (Polysemy.Member (Error TestBrigFailure) r) => + BrigBehavior -> + Sem (BrigAPIAccess ': r) a -> + Sem r a +interpretTestBrig behavior = + interpret $ \case + GetLocalMLSClients {} -> case behavior of + BrigCrashes -> throw TestBrigFailure + BrigUnused -> error "unexpected GetLocalMLSClients call in test" + _ -> error "unexpected BrigAPIAccess call in test" + +interpretTestFederation :: + Sem (FederationAPIAccess FederatorClient ': r) a -> + Sem r a +interpretTestFederation = + interpret $ \case + -- Mirrors the production federation failure path: getRemoteMLSClients + -- throws the returned FederationError in client code, where + -- getClientData hushes it into an inner 'Nothing'. + RunFederatedEither _ _ -> pure (Left FederationNotImplemented) + _ -> error "unexpected FederationAPIAccess call in test" + +ownDomain :: Domain +ownDomain = Domain "example.com" + +-- | The added user is remote, so the client-data fetch goes through the +-- federation path in both scenarios. +remoteDomain :: Domain +remoteDomain = Domain "other.example.com" + +lConv :: Local ConvOrSubConv +lConv = toLocalUnsafe ownDomain convOrSub + +convOrSub :: ConvOrSubConv +convOrSub = + Conv + MLSConversation + { mcId = convId, + mcMetadata = defConversationMetadata Nothing, + mcMLSData = ConversationMLSData {cnvmlsGroupId = groupId, cnvmlsActiveData = Nothing}, + mcLocalMembers = [], + mcRemoteMembers = [], + mcMembers = mempty, + mcIndexMap = mempty, + mcMigrationState = MLSMigrationMLS + } + +-- | One user (not a conversation member) adding one client. With 'Nothing' +-- client data this user is classified unreachable. The user domain selects +-- the client-data fetch path: local via BrigAPIAccess, remote via the +-- federation path. +newCM :: Qualified UserId -> ClientMap (LeafIndex, Maybe KeyPackage) +newCM quser = ClientMap (Map.singleton quser (Map.singleton testClientId (0, Nothing))) + +mkUuid :: String -> UUID.UUID +mkUuid = fromJust . UUID.fromString + +userId :: UserId +userId = Id (mkUuid "00000000-0000-0000-0000-000000000001") + +convId :: ConvId +convId = Id (mkUuid "00000000-0000-0000-0000-000000000002") + +testClientId :: ClientId +testClientId = ClientId 3 + +groupId :: GroupId +groupId = GroupId "check-clients-spec" + +csSuite :: CipherSuiteTag +csSuite = MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + +qUserId :: BrigBehavior -> Qualified UserId +qUserId = \case + BrigCrashes -> Qualified userId ownDomain + BrigUnused -> Qualified userId remoteDomain diff --git a/libs/wire-subsystems/test/unit/Wire/MeetingNotifierSpec.hs b/libs/wire-subsystems/test/unit/Wire/MeetingNotifierSpec.hs index eb5ac1d066e..2c78b199681 100644 --- a/libs/wire-subsystems/test/unit/Wire/MeetingNotifierSpec.hs +++ b/libs/wire-subsystems/test/unit/Wire/MeetingNotifierSpec.hs @@ -32,6 +32,7 @@ import Polysemy.TinyLog (TinyLog) import Test.Hspec import Wire.API.Event.Meeting qualified as MeetingEvent import Wire.API.Meeting qualified as API +import Wire.API.Push.V2 qualified as PushV2 import Wire.MeetingNotifier import Wire.MeetingNotifier.Interpreter import Wire.MeetingsStore qualified as Store @@ -72,6 +73,7 @@ spec = do length pushes `shouldBe` 1 let push = head pushes push.recipients `shouldBe` [userRecipient addedUser] + push.route `shouldBe` PushV2.RouteAny case fromJSON (Object push.json) :: Result MeetingEvent.Event of Error err -> expectationFailure err Success event -> event `shouldBe` expectedEvent diff --git a/libs/wire-subsystems/test/unit/Wire/MeetingsSubsystem/InterpreterSpec.hs b/libs/wire-subsystems/test/unit/Wire/MeetingsSubsystem/InterpreterSpec.hs index 145bf63ba8b..532711007f3 100644 --- a/libs/wire-subsystems/test/unit/Wire/MeetingsSubsystem/InterpreterSpec.hs +++ b/libs/wire-subsystems/test/unit/Wire/MeetingsSubsystem/InterpreterSpec.hs @@ -49,6 +49,7 @@ import Wire.API.Error.Galley (GalleyError (TeamMemberNotFound, TeamNotFound), In import Wire.API.Event.Meeting qualified as MeetingEvent import Wire.API.Meeting qualified as API import Wire.API.PostgresMarshall (PostgresUnmarshall (postgresUnmarshall)) +import Wire.API.Push.V2 qualified as PushV2 import Wire.API.Team.Feature import Wire.API.Team.Member (TeamMember, mkTeamMember) import Wire.API.Team.Permission (fullPermissions) @@ -1629,11 +1630,11 @@ spec = describe "MeetingsSubsystem.Interpreter" $ do Left err -> fail $ "Error: " <> show err Right pushes -> do let push = head pushes - -- Order is deterministic: 'members' is a literal list, 'map - -- localMemberToRecipient' preserves order, and mkMeetingEventPush - -- no longer filters or reorders recipients. + -- Recipient order is preserved: 'members' is a literal list and + -- mkMeetingEventPush maps 'localMemberToRecipient' over it. map (.recipientUserId) push.recipients `shouldBe` [uid1, uid2] push.conn `shouldBe` Just originConn + push.route `shouldBe` PushV2.RouteAny describe "V16 operations" $ do let now = UTCTime (fromGregorian 2026 1 1) 0 diff --git a/libs/wire-subsystems/test/unit/Wire/MockInterpreters/SparAPIAccess.hs b/libs/wire-subsystems/test/unit/Wire/MockInterpreters/SparAPIAccess.hs index 4122706e412..48f314d0528 100644 --- a/libs/wire-subsystems/test/unit/Wire/MockInterpreters/SparAPIAccess.hs +++ b/libs/wire-subsystems/test/unit/Wire/MockInterpreters/SparAPIAccess.hs @@ -31,6 +31,7 @@ miniSparAPIAccess = interpret $ \case GetIdentityProviders tid -> Map.findWithDefault (IdPList []) tid <$> input DeleteTeam {} -> error "DeleteTeam not implemented in miniSparAPIAccess" + DeleteScimUser {} -> error "DeleteScimUser not implemented in miniSparAPIAccess" LookupScimUserInfo {} -> error "LookupScimUserInfo not implemented in miniSparAPIAccess" emptySparAPIAccess :: InterpreterFor SparAPIAccess r diff --git a/libs/wire-subsystems/wire-subsystems.cabal b/libs/wire-subsystems/wire-subsystems.cabal index f7627036f1c..66662926e3d 100644 --- a/libs/wire-subsystems/wire-subsystems.cabal +++ b/libs/wire-subsystems/wire-subsystems.cabal @@ -500,6 +500,8 @@ library Wire.UserStore Wire.UserStore.Cassandra Wire.UserStore.IndexUser + Wire.UserStore.Migration + Wire.UserStore.Migration.Types Wire.UserStore.Postgres Wire.UserStore.Unique Wire.UserSubsystem @@ -634,6 +636,7 @@ test-suite wire-subsystems-tests Wire.ConversationSubsystem.AdminlessGroupsSpec Wire.ConversationSubsystem.InterpreterSpec Wire.ConversationSubsystem.MessageSpec + Wire.ConversationSubsystem.MLS.CheckClientsSpec Wire.ConversationSubsystem.One2OneSpec Wire.EmailSubsystem.TemplateFixtures Wire.EmailSubsystem.TemplateSpec diff --git a/postgres-schema.sql b/postgres-schema.sql index b2d1587ab49..de4a57a0f2e 100644 --- a/postgres-schema.sql +++ b/postgres-schema.sql @@ -1614,6 +1614,17 @@ CREATE TABLE public.user_group_member ( ALTER TABLE public.user_group_member OWNER TO "wire-server"; +-- +-- Name: user_migration_pending_deletes; Type: TABLE; Schema: public; Owner: wire-server +-- + +CREATE TABLE public.user_migration_pending_deletes ( + id uuid NOT NULL +); + + +ALTER TABLE public.user_migration_pending_deletes OWNER TO "wire-server"; + -- -- Name: wire_user; Type: TABLE; Schema: public; Owner: wire-server -- @@ -2012,6 +2023,14 @@ ALTER TABLE ONLY public.user_group ADD CONSTRAINT user_group_pkey PRIMARY KEY (team_id, id); +-- +-- Name: user_migration_pending_deletes user_migration_pending_deletes_pkey; Type: CONSTRAINT; Schema: public; Owner: wire-server +-- + +ALTER TABLE ONLY public.user_migration_pending_deletes + ADD CONSTRAINT user_migration_pending_deletes_pkey PRIMARY KEY (id); + + -- -- Name: wire_user wire_user_handle_key; Type: CONSTRAINT; Schema: public; Owner: wire-server -- diff --git a/services/background-worker/background-worker.integration.yaml b/services/background-worker/background-worker.integration.yaml index e264ce14016..b0bd0d172e4 100644 --- a/services/background-worker/background-worker.integration.yaml +++ b/services/background-worker/background-worker.integration.yaml @@ -58,6 +58,7 @@ migrationOptions: migrateConversationCodes: false migrateTeamFeatures: false migrateDomainRegistration: false +migrateUsers: false # Background jobs consumer configuration for integration backgroundJobs: diff --git a/services/background-worker/src/Wire/BackendNotificationPusher.hs b/services/background-worker/src/Wire/BackendNotificationPusher.hs index cadce5c0270..0654dbd3344 100644 --- a/services/background-worker/src/Wire/BackendNotificationPusher.hs +++ b/services/background-worker/src/Wire/BackendNotificationPusher.hs @@ -207,10 +207,23 @@ pushNotification runningFlag targetDomain (msg, envelope) = do -- compute the best usable version in a notification let bestVersion = bodyVersions >=> flip latestCommonVersion remoteVersions case pairedMaximumOn bestVersion (toList (notifications bundle)) of - (_, Nothing) -> - Log.fatal $ - Log.msg (Log.val "No federation API version in common, the notification will be ignored") - . Log.field "domain" (domainText targetDomain) + (_, Nothing) -> do + metrics <- asks backendNotificationMetrics + case bundle.unsupportedVersionPolicy of + KeepQueued -> do + Log.fatal $ + Log.msg (Log.val "No federation API version in common; the notification will remain queued") + . Log.field "domain" (domainText targetDomain) + . Log.field "paths" (Text.intercalate "," $ map (.path) $ toList bundle.notifications) + withLabel metrics.stuckQueuesGauge (domainText targetDomain) (flip setGauge 1) + DropIfUnsupported -> do + Log.warn $ + Log.msg (Log.val "Dropping notification because the target backend supports no compatible federation API version") + . Log.field "domain" (domainText targetDomain) + . Log.field "paths" (Text.intercalate "," $ map (.path) $ toList bundle.notifications) + lift $ ack envelope + withLabel metrics.droppedUnsupportedVersionCounter (domainText targetDomain) incCounter + withLabel metrics.stuckQueuesGauge (domainText targetDomain) (flip setGauge 0) (notif, cveVersion) -> do ceFederator <- asks (.federatorInternal) ceHttp2Manager <- asks http2Manager diff --git a/services/background-worker/src/Wire/BackgroundWorker.hs b/services/background-worker/src/Wire/BackgroundWorker.hs index b57ba12df40..6c12b02e816 100644 --- a/services/background-worker/src/Wire/BackgroundWorker.hs +++ b/services/background-worker/src/Wire/BackgroundWorker.hs @@ -78,6 +78,14 @@ run opts galleyOpts = do withNamedLogger "migrate-domain-registration" $ Migrations.domainRegistration opts.migrationOptions else pure $ pure () + cleanupUsersMigration <- + if opts.migrateUsers + then + runAppT env $ + withNamedLogger "migrate-users" $ + Migrations.users opts.migrationOptions + else pure $ pure () + cleanupJobs <- runAppT env $ withNamedLogger "background-job-consumer" $ @@ -89,13 +97,14 @@ run opts galleyOpts = do let cleanup = void $ runConcurrently $ - (,,,,,,,) + (,,,,,,,,) <$> Concurrently cleanupDeadUserNotifWatcher <*> Concurrently cleanupBackendNotifPusher <*> Concurrently cleanupConvMigration <*> Concurrently cleanUpConvCodesMigration <*> Concurrently cleanupTeamFeaturesMigration <*> Concurrently cleanupDomainRegistrationMigration + <*> Concurrently cleanupUsersMigration <*> Concurrently cleanupJobRunner <*> Concurrently cleanupJobs diff --git a/services/background-worker/src/Wire/BackgroundWorker/Env.hs b/services/background-worker/src/Wire/BackgroundWorker/Env.hs index ed784a33db9..10886fd8332 100644 --- a/services/background-worker/src/Wire/BackgroundWorker/Env.hs +++ b/services/background-worker/src/Wire/BackgroundWorker/Env.hs @@ -118,6 +118,7 @@ data Env = Env data BackendNotificationMetrics = BackendNotificationMetrics { pushedCounter :: Vector Text Counter, + droppedUnsupportedVersionCounter :: Vector Text Counter, errorCounter :: Vector Text Counter, stuckQueuesGauge :: Vector Text Gauge } @@ -130,6 +131,7 @@ mkBackendNotificationMetrics :: IO BackendNotificationMetrics mkBackendNotificationMetrics = BackendNotificationMetrics <$> register (vector "targetDomain" $ counter $ Prometheus.Info "wire_backend_notifications_pushed" "Number of notifications pushed") + <*> register (vector "targetDomain" $ counter $ Prometheus.Info "wire_backend_notifications_dropped_unsupported_version" "Number of notifications dropped because the target backend supports no compatible federation API version") <*> register (vector "targetDomain" $ counter $ Prometheus.Info "wire_backend_notifications_errors" "Number of errors that occurred while pushing notifications") <*> register (vector "targetDomain" $ gauge $ Prometheus.Info "wire_backend_notifications_stuck_queues" "Set to 1 when pushing notifications is stuck") diff --git a/services/background-worker/src/Wire/BackgroundWorker/Options.hs b/services/background-worker/src/Wire/BackgroundWorker/Options.hs index 61df5d5d14f..035460cfc32 100644 --- a/services/background-worker/src/Wire/BackgroundWorker/Options.hs +++ b/services/background-worker/src/Wire/BackgroundWorker/Options.hs @@ -55,6 +55,7 @@ data Opts = Opts migrateConversationCodes :: !Bool, migrateTeamFeatures :: !Bool, migrateDomainRegistration :: !Bool, + migrateUsers :: !Bool, jobs :: JobConfig, meetingsCleanup :: MeetingsCleanupConfig, backgroundJobs :: BackgroundJobsConfig diff --git a/services/background-worker/src/Wire/PostgresMigrations.hs b/services/background-worker/src/Wire/PostgresMigrations.hs index 604cab0140c..28c6a789a4a 100644 --- a/services/background-worker/src/Wire/PostgresMigrations.hs +++ b/services/background-worker/src/Wire/PostgresMigrations.hs @@ -24,10 +24,11 @@ import UnliftIO import Wire.BackgroundWorker.Env import Wire.BackgroundWorker.Util import Wire.CodeStore.Migration -import Wire.ConversationStore.Migration +import Wire.ConversationStore.Migration qualified as ConversationStore import Wire.DomainRegistrationStore.Migration import Wire.Migration (MigrationOptions) import Wire.TeamFeatureStore.Migration +import Wire.UserStore.Migration qualified as UserStore conversations :: MigrationOptions -> AppT IO CleanupAction conversations migOpts = do @@ -45,8 +46,8 @@ conversations migOpts = do userMigFailed <- register $ counter $ Prometheus.Info "wire_user_remote_convs_migration_failed" "Whether the migration of remote conversation membership data to Postgresql has failed" userMigDuration <- register $ vector "outcome" $ histogram (Prometheus.Info "wire_user_remote_convs_migration_duration_seconds" "Duration of remote conversation membership migration attempts") defaultBuckets - convLoop <- async . lift $ migrateConvsLoop migOpts cassClient pgPool logger convMigCounter convMigFinished convMigFailed convMigDuration - userLoop <- async . lift $ migrateUsersLoop migOpts cassClient pgPool logger userMigCounter userMigFinished userMigFailed userMigDuration + convLoop <- async . lift $ ConversationStore.migrateConvsLoop migOpts cassClient pgPool logger convMigCounter convMigFinished convMigFailed convMigDuration + userLoop <- async . lift $ ConversationStore.migrateUsersLoop migOpts cassClient pgPool logger userMigCounter userMigFinished userMigFailed userMigDuration Log.info logger $ Log.msg (Log.val "started conversation migration") pure $ do @@ -107,3 +108,21 @@ domainRegistration migOpts = do pure $ do Log.info logger $ Log.msg (Log.val "cancelling domain registration migration") cancel migrationLoop + +users :: MigrationOptions -> AppT IO CleanupAction +users migOpts = do + cassClient <- asks (.cassandraBrig) + pgPool <- asks (.hasqlPool) + logger <- asks (.logger) + Log.info logger $ Log.msg (Log.val "starting user migration") + count <- register $ counter $ Prometheus.Info "wire_users_migrated_to_pg" "Number of user rows migrated to Postgresql" + finished <- register $ counter $ Prometheus.Info "wire_users_migration_finished" "Whether the user migration to Postgresql is finished successfully" + failed <- register $ counter $ Prometheus.Info "wire_users_migration_failed" "Whether the user migration to Postgresql has failed" + duration <- register $ vector "outcome" $ histogram (Prometheus.Info "wire_users_migration_duration_seconds" "Duration of user migration attempts") defaultBuckets + + migrationLoop <- async . lift $ UserStore.migrateUsersLoop migOpts cassClient pgPool logger count finished failed duration + + Log.info logger $ Log.msg (Log.val "started user migration") + pure $ do + Log.info logger $ Log.msg (Log.val "cancelling user migration") + cancel migrationLoop diff --git a/services/background-worker/test/Test/Wire/BackendNotificationPusherSpec.hs b/services/background-worker/test/Test/Wire/BackendNotificationPusherSpec.hs index 7222120d93a..be46a03c648 100644 --- a/services/background-worker/test/Test/Wire/BackendNotificationPusherSpec.hs +++ b/services/background-worker/test/Test/Wire/BackendNotificationPusherSpec.hs @@ -66,6 +66,7 @@ import Wire.API.Federation.API.Brig import Wire.API.Federation.API.Common import Wire.API.Federation.API.Galley import Wire.API.Federation.BackendNotifications +import Wire.API.Federation.Version import Wire.API.RawJson import Wire.API.Team.FeatureFlags import Wire.BackendNotificationPusher @@ -77,6 +78,17 @@ import Wire.RateLimit.Interpreter (newRateLimitEnv) spec :: Spec spec = do + describe "PayloadBundle" $ do + it "should default to keeping a notification queued when decoding a bundle without a policy" $ do + let bundle = testBundle KeepQueued (rangeFromVersion V1) + oldBundle = Aeson.object ["notifications" .= bundle.notifications] + Aeson.fromJSON @(PayloadBundle 'Brig) oldBundle `shouldBe` Aeson.Success bundle + + it "should use the safe keep-queued policy when combining bundles with different policies" $ do + let keepQueuedBundle = testBundle KeepQueued (rangeFromVersion V1) + dropBundle = testBundle DropIfUnsupported (rangeFromVersion V1) + (keepQueuedBundle <> dropBundle).unsupportedVersionPolicy `shouldBe` KeepQueued + describe "pushNotification" $ do it "should push notifications" $ do let origDomain = Domain "origin.example.com" @@ -253,6 +265,119 @@ spec = do getVectorWith env.backendNotificationMetrics.pushedCounter getCounter `shouldReturn` [(domainText targetDomain, 1)] + it "should leave an unsupported notification queued by default" $ do + let targetDomain = Domain "target.example.com" + bundle = testBundle KeepQueued (rangeFromVersion V1) + envelope <- newMockEnvelope + let msg = + Q.newMsg + { Q.msgBody = Aeson.encode bundle, + Q.msgContentType = Just "application/json" + } + runningFlag <- newMVar () + (env, fedReqs) <- + withTempMockFederator def {versions = [0]} . runTestAppT $ do + wait =<< pushNotification runningFlag targetDomain (msg, envelope) + ask + + readIORef envelope.acks `shouldReturn` 0 + readIORef envelope.rejections `shouldReturn` [] + fedReqs `shouldBe` [] + getVectorWith env.backendNotificationMetrics.droppedUnsupportedVersionCounter getCounter + `shouldReturn` [] + getVectorWith env.backendNotificationMetrics.stuckQueuesGauge getGauge + `shouldReturn` [(domainText targetDomain, 1)] + + it "should drop an unsupported notification when configured" $ do + let targetDomain = Domain "target.example.com" + bundle = testBundle DropIfUnsupported (rangeFromVersion V1) + envelope <- newMockEnvelope + let msg = + Q.newMsg + { Q.msgBody = Aeson.encode bundle, + Q.msgContentType = Just "application/json" + } + runningFlag <- newMVar () + (env, fedReqs) <- + withTempMockFederator def {versions = [0]} . runTestAppT $ do + wait =<< pushNotification runningFlag targetDomain (msg, envelope) + ask + + readIORef envelope.acks `shouldReturn` 1 + readIORef envelope.rejections `shouldReturn` [] + fedReqs `shouldBe` [] + getVectorWith env.backendNotificationMetrics.droppedUnsupportedVersionCounter getCounter + `shouldReturn` [(domainText targetDomain, 1)] + getVectorWith env.backendNotificationMetrics.stuckQueuesGauge getGauge + `shouldReturn` [(domainText targetDomain, 0)] + + it "should deliver a compatible notification with the drop policy" $ do + let targetDomain = Domain "target.example.com" + bundle = testBundle DropIfUnsupported (rangeFromVersion V1) + envelope <- newMockEnvelope + let msg = + Q.newMsg + { Q.msgBody = Aeson.encode bundle, + Q.msgContentType = Just "application/json" + } + runningFlag <- newMVar () + (env, fedReqs) <- + withTempMockFederator def {versions = [1]} . runTestAppT $ do + wait =<< pushNotification runningFlag targetDomain (msg, envelope) + ask + + readIORef envelope.acks `shouldReturn` 1 + readIORef envelope.rejections `shouldReturn` [] + fedReqs + `shouldBe` [ FederatedRequest + { frTargetDomain = targetDomain, + frOriginDomain = testOriginDomain, + frComponent = Brig, + frRPC = "unsupported-version-test", + frBody = Aeson.encode testNotificationBody + } + ] + getVectorWith env.backendNotificationMetrics.droppedUnsupportedVersionCounter getCounter + `shouldReturn` [] + + it "should retry delivery failures instead of applying the drop policy" $ do + isRemoteBrokenRef <- newIORef True + fedCalls <- newIORef (0 :: Int) + let mockRemote :: req -> IO MockResponse + mockRemote _ = do + isRemoteBroken <- readIORef isRemoteBrokenRef + atomicModifyIORef fedCalls $ \c -> (c + 1, ()) + pure $ + if isRemoteBroken + then MockResponse status200 "text/html" "down for maintenance" + else MockResponse status200 "application/json" (Aeson.encode EmptyResponse) + targetDomain = Domain "target.example.com" + bundle = testBundle DropIfUnsupported (rangeFromVersion V1) + envelope <- newMockEnvelope + let msg = + Q.newMsg + { Q.msgBody = Aeson.encode bundle, + Q.msgContentType = Just "application/json" + } + runningFlag <- newMVar () + env <- testEnv + pushThread <- + async $ withTempMockFederator def {handler = mockRemote, versions = [1]} . runTestAppTWithEnv env $ do + wait =<< pushNotification runningFlag targetDomain (msg, envelope) + + untilM $ (>= 2) <$> readIORef fedCalls + readIORef envelope.acks `shouldReturn` 0 + getVectorWith env.backendNotificationMetrics.droppedUnsupportedVersionCounter getCounter + `shouldReturn` [] + + writeIORef isRemoteBrokenRef False + void $ wait pushThread + + readIORef envelope.acks `shouldReturn` 1 + readIORef envelope.rejections `shouldReturn` [] + getVectorWith env.backendNotificationMetrics.droppedUnsupportedVersionCounter getCounter + `shouldReturn` [] + it "should reject invalid notifications" $ do envelope <- newMockEnvelope let msg = @@ -487,6 +612,28 @@ spec = do calls `shouldSatisfy` (\c -> length c >= 2) mapM_ (\vhost -> vhost `shouldBe` rabbitmqVHost) calls +testOriginDomain :: Domain +testOriginDomain = Domain "origin.example.com" + +testNotificationBody :: Aeson.Value +testNotificationBody = Aeson.object ["foo" .= ("bar" :: Text)] + +testBundle :: UnsupportedVersionPolicy -> VersionRange -> PayloadBundle 'Brig +testBundle policy versions = + PayloadBundle + { notifications = + pure + BackendNotification + { targetComponent = Brig, + ownDomain = testOriginDomain, + path = "/unsupported-version-test", + body = RawJson $ Aeson.encode testNotificationBody, + bodyVersions = Just versions, + requestId = Just $ RequestId defRequestId + }, + unsupportedVersionPolicy = policy + } + untilM :: (Monad m) => m Bool -> m () untilM action = do b <- action diff --git a/services/brig/brig.cabal b/services/brig/brig.cabal index 89b1d88f7a7..613e931c9ef 100644 --- a/services/brig/brig.cabal +++ b/services/brig/brig.cabal @@ -183,6 +183,7 @@ library Brig.Schema.V91_UpdateDomainRegistrationSchema_AddWebappUrl Brig.Schema.V92_AddUserType Brig.Schema.V93_AddScimPendingUserEmail + Brig.Schema.V94_ReduceUserGCGracePeriod Brig.Team.API Brig.Team.Template Brig.Template @@ -489,6 +490,7 @@ test-suite brig-tests Test.Brig.Effects.Delay Test.Brig.InternalNotification Test.Brig.MLS + Test.Brig.Options hs-source-dirs: test/unit ghc-options: diff --git a/services/brig/docs/swagger-v17.json b/services/brig/docs/swagger-v17.json index 2c63648dc97..22cea431331 100644 --- a/services/brig/docs/swagger-v17.json +++ b/services/brig/docs/swagger-v17.json @@ -1,57 +1,41 @@ { "components": { "schemas": { - "": { - "enum": [ - "audio", - "books", - "business", - "design", - "education", - "entertainment", - "finance", - "fitness", - "food-drink", - "games", - "graphics", - "health", - "integration", - "lifestyle", - "media", - "medical", - "movies", - "music", - "news", - "photography", - "poll", - "productivity", - "quiz", - "rating", - "shopping", - "social", - "sports", - "travel", - "tutorial", - "video", - "weather" - ], - "type": "string" - }, "ASCII": { "example": "aGVsbG8", "type": "string" }, - "Access": { - "description": "How users can join conversations", + "AcceptTeamInvitation_Nzg5NzI3MjA2": { + "description": "Accept an invitation to join a team on Wire.", + "properties": { + "code": { + "$ref": "#/components/schemas/ASCII" + }, + "password": { + "description": "The user account password.", + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "required": [ + "code", + "password" + ], + "type": "object" + }, + "AccessRoleLegacy_LTYwOTAxMDI1": { + "deprecated": true, + "description": "Deprecated, please use access_role_v2", "enum": [ "private", - "invite", - "link", - "code" + "team", + "activated", + "non_activated" ], "type": "string" }, - "AccessRole": { + "AccessRole_Mzk3MDYzMzcw": { "description": "Which users/services can join conversations. This replaces legacy access roles and allows a more fine grained configuration of access roles, and in particular a separation of guest and services access.\n\nThis field is optional. If it is not present, the default will be `[team_member, non_team_member, service]`. Please note that an empty list is not allowed when creating a new conversation.", "enum": [ "team_member", @@ -61,18 +45,13 @@ ], "type": "string" }, - "AccessRoleLegacy": { - "deprecated": true, - "description": "Deprecated, please use access_role_v2", + "AccessTokenType_LTgyOTY0NDE5": { "enum": [ - "private", - "team", - "activated", - "non_activated" + "DPoP" ], "type": "string" }, - "AccessToken": { + "AccessToken_ODIyMTczMjMw": { "properties": { "access_token": { "description": "The opaque access token string", @@ -83,7 +62,7 @@ "type": "integer" }, "token_type": { - "$ref": "#/components/schemas/TokenType" + "$ref": "#/components/schemas/TokenType_NTkyMzk4MjIz" }, "user": { "$ref": "#/components/schemas/UUID" @@ -97,9 +76,23 @@ ], "type": "object" }, - "AccessTokenType": { + "Access_NjkyMzE5ODc0": { + "description": "How users can join conversations", "enum": [ - "DPoP" + "private", + "invite", + "link", + "code" + ], + "type": "string" + }, + "AccountStatus_NzkzNDU1ODU5": { + "enum": [ + "active", + "suspended", + "deleted", + "ephemeral", + "pending-invitation" ], "type": "string" }, @@ -113,11 +106,12 @@ "modify_conversation_access", "modify_other_conversation_member", "leave_conversation", - "delete_conversation" + "delete_conversation", + "modify_add_permission" ], "type": "string" }, - "Activate": { + "Activate_MzUzNzIxODUw": { "description": "Data for an activation request.", "properties": { "code": { @@ -140,7 +134,7 @@ ], "type": "object" }, - "ActivationResponse": { + "ActivationResponse_LTIyOTY5NDE3": { "description": "Response body of a successful activation request", "properties": { "email": { @@ -156,25 +150,7 @@ }, "type": "object" }, - "AddBot": { - "properties": { - "locale": { - "$ref": "#/components/schemas/Locale" - }, - "provider": { - "$ref": "#/components/schemas/UUID" - }, - "service": { - "$ref": "#/components/schemas/UUID" - } - }, - "required": [ - "provider", - "service" - ], - "type": "object" - }, - "AddBotResponse": { + "AddBotResponse_ODA5MzA2NTA1": { "properties": { "accent_id": { "format": "int32", @@ -184,7 +160,7 @@ }, "assets": { "items": { - "$ref": "#/components/schemas/UserAsset" + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" }, "type": "array" }, @@ -193,7 +169,7 @@ "type": "string" }, "event": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" }, "id": { "$ref": "#/components/schemas/UUID" @@ -214,94 +190,67 @@ ], "type": "object" }, - "AllTeamFeatures": { + "AddBot_NjI0ODkyODk3": { "properties": { - "appLock": { - "$ref": "#/components/schemas/AppLockConfig.LockableFeature" - }, - "classifiedDomains": { - "$ref": "#/components/schemas/ClassifiedDomainsConfig.LockableFeature" - }, - "conferenceCalling": { - "$ref": "#/components/schemas/ConferenceCallingConfig.LockableFeature" - }, - "conversationGuestLinks": { - "$ref": "#/components/schemas/GuestLinksConfig.LockableFeature" - }, - "digitalSignatures": { - "$ref": "#/components/schemas/DigitalSignaturesConfig.LockableFeature" - }, - "enforceFileDownloadLocation": { - "$ref": "#/components/schemas/EnforceFileDownloadLocation.LockableFeature" - }, - "exposeInvitationURLsToTeamAdmin": { - "$ref": "#/components/schemas/ExposeInvitationURLsToTeamAdminConfig.LockableFeature" - }, - "fileSharing": { - "$ref": "#/components/schemas/FileSharingConfig.LockableFeature" - }, - "legalhold": { - "$ref": "#/components/schemas/LegalholdConfig.LockableFeature" - }, - "limitedEventFanout": { - "$ref": "#/components/schemas/LimitedEventFanoutConfig.LockableFeature" - }, - "mls": { - "$ref": "#/components/schemas/MLSConfig.LockableFeature" - }, - "mlsE2EId": { - "$ref": "#/components/schemas/MlsE2EIdConfig.LockableFeature" - }, - "mlsMigration": { - "$ref": "#/components/schemas/MlsMigration.LockableFeature" - }, - "outlookCalIntegration": { - "$ref": "#/components/schemas/OutlookCalIntegrationConfig.LockableFeature" - }, - "searchVisibility": { - "$ref": "#/components/schemas/SearchVisibilityAvailableConfig.LockableFeature" - }, - "searchVisibilityInbound": { - "$ref": "#/components/schemas/SearchVisibilityInboundConfig.LockableFeature" - }, - "selfDeletingMessages": { - "$ref": "#/components/schemas/SelfDeletingMessagesConfig.LockableFeature" - }, - "sndFactorPasswordChallenge": { - "$ref": "#/components/schemas/SndFactorPasswordChallengeConfig.LockableFeature" + "locale": { + "$ref": "#/components/schemas/Locale" }, - "sso": { - "$ref": "#/components/schemas/SSOConfig.LockableFeature" + "provider": { + "$ref": "#/components/schemas/UUID" }, - "validateSAMLemails": { - "$ref": "#/components/schemas/ValidateSAMLEmailsConfig.LockableFeature" + "service": { + "$ref": "#/components/schemas/UUID" } }, "required": [ - "legalhold", - "sso", - "searchVisibility", - "searchVisibilityInbound", - "validateSAMLemails", - "digitalSignatures", - "appLock", - "fileSharing", - "classifiedDomains", - "conferenceCalling", - "selfDeletingMessages", - "conversationGuestLinks", - "sndFactorPasswordChallenge", - "mls", - "exposeInvitationURLsToTeamAdmin", - "outlookCalIntegration", - "mlsE2EId", - "mlsMigration", - "enforceFileDownloadLocation", - "limitedEventFanout" + "provider", + "service" ], "type": "object" }, - "Alpha": { + "AddPermissionUpdate_LTU3MzEwOTY4": { + "description": "The action of changing the permission to add members to a channel", + "properties": { + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + } + }, + "required": [ + "add_permission" + ], + "type": "object" + }, + "AddPermission_LTE1MzgzNzE3": { + "enum": [ + "admins", + "everyone" + ], + "type": "string" + }, + "AdminlessReminder_LTkyMDUxNTk5": { + "properties": { + "deletion_scheduled_for": { + "$ref": "#/components/schemas/UTCTimeMillis" + } + }, + "required": [ + "deletion_scheduled_for" + ], + "type": "object" + }, + "AllowedGlobalOperationsConfig_MzAwOTU1MDkx": { + "properties": { + "mlsConversationReset": { + "type": "boolean" + } + }, + "required": [ + "mlsConversationReset" + ], + "type": "object" + }, + "Alpha_LTE4NDUxNDQ4": { + "description": "ISO 4217 alphabetic codes. This is only stored by the backend, not processed. It can be removed once billing supports currency changes after team creation.", "enum": [ "AED", "AFN", @@ -482,9 +431,28 @@ "ZMW", "ZWL" ], + "example": "EUR", "type": "string" }, - "AppLockConfig": { + "AppInfo_MjgwNTkwOTUz": { + "properties": { + "category": { + "description": "Category name (if uncertain, pick \"other\")", + "type": "string" + }, + "description": { + "maxLength": 300, + "minLength": 0, + "type": "string" + } + }, + "required": [ + "category", + "description" + ], + "type": "object" + }, + "AppLockConfigB_Covered_Identity_NDIxOTc2Njkz": { "properties": { "enforceAppLock": { "type": "boolean" @@ -502,63 +470,48 @@ ], "type": "object" }, - "AppLockConfig.Feature": { + "ApproveLegalHoldForUserRequest_NjEyNzYyMTIx": { "properties": { - "config": { - "$ref": "#/components/schemas/AppLockConfig" - }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" - }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" } }, - "required": [ - "status", - "config" - ], "type": "object" }, - "AppLockConfig.LockableFeature": { + "AssetKey": { + "description": "S3 asset key for an icon image with retention information.", + "example": "3-1-47de4580-ae51-4650-acbb-d10c028cb0ac", + "type": "string" + }, + "AssetSize_OTAwMDA3ODY2": { + "enum": [ + "preview", + "complete" + ], + "type": "string" + }, + "AssetSource": {}, + "Asset_LTIyMjc1NDEz": { "properties": { - "config": { - "$ref": "#/components/schemas/AppLockConfig" - }, - "lockStatus": { - "$ref": "#/components/schemas/LockStatus" + "key": { + "$ref": "#/components/schemas/AssetKey" }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" + "size": { + "$ref": "#/components/schemas/AssetSize_OTAwMDA3ODY2" }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "type": { + "$ref": "#/components/schemas/MTYxOTI3NjM3" } }, "required": [ - "status", - "lockStatus", - "config" + "key", + "type" ], "type": "object" }, - "ApproveLegalHoldForUserRequest": { - "properties": { - "password": { - "maxLength": 1024, - "minLength": 6, - "type": "string" - } - }, - "type": "object" - }, - "Asset": { + "Asset_Qualified_AssetKey_MzU1MjMxNTA5": { "properties": { "domain": { "$ref": "#/components/schemas/Domain" @@ -579,34 +532,38 @@ ], "type": "object" }, - "AssetKey": { - "example": "3-1-47de4580-ae51-4650-acbb-d10c028cb0ac", - "type": "string" - }, - "AssetSize": { - "enum": [ - "preview", - "complete" - ], - "type": "string" - }, - "AssetSource": {}, - "AssetType": { - "enum": [ - "image" + "AuthSFTServer_LTY5MzcyOTE0": { + "description": "Inspired by WebRTC 'RTCIceServer' object, contains details of SFT servers", + "properties": { + "credential": { + "$ref": "#/components/schemas/ASCII" + }, + "urls": { + "description": "Array containing exactly one SFT server address of the form 'https://:'", + "items": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "type": "array" + }, + "username": { + "$ref": "#/components/schemas/SFTUsername" + } + }, + "required": [ + "urls" ], - "type": "string" + "type": "object" }, "AuthnRequest": { "properties": { "iD": { - "$ref": "#/components/schemas/ID_*_AuthnRequest" + "$ref": "#/components/schemas/Id_AuthnRequest" }, "issueInstant": { "$ref": "#/components/schemas/Time" }, "issuer": { - "type": "string" + "$ref": "#/components/schemas/URI" }, "nameIDPolicy": { "$ref": "#/components/schemas/NameIdPolicy" @@ -623,30 +580,31 @@ "example": "ZXhhbXBsZQo=", "type": "string" }, - "BaseProtocol": { + "Base64URLByteString": { + "example": "ZXhhbXBsZQo=", + "type": "string" + }, + "BaseProtocolTag_LTM0MDE1NTEx": { "enum": [ "proteus", "mls" ], "type": "string" }, - "BindingNewTeamUser": { + "BindingNewTeamUser_LTY0MDQxMDEw": { "properties": { "currency": { - "$ref": "#/components/schemas/Alpha" + "$ref": "#/components/schemas/Alpha_LTE4NDUxNDQ4" }, "icon": { "$ref": "#/components/schemas/Icon" }, "icon_key": { - "description": "team icon asset key", + "description": "The decryption key for the team icon S3 asset", "maxLength": 256, "minLength": 1, "type": "string" }, - "members": { - "description": "initial team member ids (between 1 and 127)" - }, "name": { "description": "team name", "maxLength": 256, @@ -660,15 +618,14 @@ ], "type": "object" }, - "Body": {}, - "BotConvView": { + "BotConvView_LTYzMjIzMjQz": { "properties": { "id": { "$ref": "#/components/schemas/UUID" }, "members": { "items": { - "$ref": "#/components/schemas/OtherMember" + "$ref": "#/components/schemas/OtherMember_LTgzNzE2MTk4" }, "type": "array" }, @@ -682,7 +639,7 @@ ], "type": "object" }, - "BotUserView": { + "BotUserView_LTE2MTkwMTcw": { "properties": { "accent_id": { "format": "int32", @@ -712,136 +669,415 @@ ], "type": "object" }, - "CheckHandles": { + "CellsBackend_LTE1Nzg3NzQ2": { "properties": { - "handles": { - "items": { - "type": "string" - }, - "maxItems": 50, - "minItems": 1, - "type": "array" - }, - "return": { - "maximum": 10, - "minimum": 1, - "type": "integer" + "url": { + "$ref": "#/components/schemas/HttpsUrl" } }, "required": [ - "handles", - "return" + "url" ], "type": "object" }, - "CipherSuiteTag": { - "description": "The cipher suite of the corresponding MLS group", - "maximum": 65535, - "minimum": 0, - "type": "integer" + "CellsCollaboraStatus_MTgzNTQyNzUz": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ], + "type": "object" }, - "ClassifiedDomainsConfig": { + "CellsCollabora_LTMzNDA5MDIz": { "properties": { - "domains": { - "items": { - "$ref": "#/components/schemas/Domain" - }, - "type": "array" + "edition": { + "$ref": "#/components/schemas/CollaboraEdition_LTg2NDA1NDQ4" } }, "required": [ - "domains" + "edition" ], "type": "object" }, - "ClassifiedDomainsConfig.LockableFeature": { + "CellsConfigB_Covered_Identity_LTE1NzkwOTcz": { + "example": { + "channels": { + "default": "enabled", + "enabled": true + }, + "collabora": { + "enabled": false + }, + "groups": { + "default": "enabled", + "enabled": true + }, + "metadata": { + "namespaces": { + "usermetaTags": { + "allowFreeValues": true, + "defaultValues": [] + } + } + }, + "one2one": { + "default": "enabled", + "enabled": true + }, + "publicLinks": { + "enableFiles": true, + "enableFolders": true, + "enforceExpirationDefault": 0, + "enforceExpirationMax": 0, + "enforcePassword": false + }, + "storage": { + "perFileQuotaBytes": "100000000", + "recycle": { + "allowSkip": false, + "autoPurgeDays": 30, + "disable": false + } + }, + "users": { + "externals": true, + "guests": false + } + }, "properties": { - "config": { - "$ref": "#/components/schemas/ClassifiedDomainsConfig" + "channels": { + "$ref": "#/components/schemas/CellsProperty_NzcxMDIzMzk0" }, - "lockStatus": { - "$ref": "#/components/schemas/LockStatus" + "collabora": { + "$ref": "#/components/schemas/CellsCollaboraStatus_MTgzNTQyNzUz" }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" + "groups": { + "$ref": "#/components/schemas/CellsProperty_NzcxMDIzMzk0" }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "metadata": { + "$ref": "#/components/schemas/CellsMetadata_LTY1OTM5MTM0" + }, + "one2one": { + "$ref": "#/components/schemas/CellsProperty_NzcxMDIzMzk0" + }, + "publicLinks": { + "$ref": "#/components/schemas/CellsPublicLinks_MjgxMzQ3Mzk4" + }, + "storage": { + "$ref": "#/components/schemas/CellsConfigStorage_LTM0NDMwODM4" + }, + "users": { + "$ref": "#/components/schemas/CellsUsers_LTQ4NTEyODA1" } }, "required": [ - "status", - "lockStatus", - "config" + "channels", + "groups", + "one2one", + "users", + "collabora", + "publicLinks", + "storage", + "metadata" ], "type": "object" }, - "Client": { + "CellsConfigStorage_LTM0NDMwODM4": { "properties": { - "capabilities": { - "$ref": "#/components/schemas/ClientCapabilityList" + "perFileQuotaBytes": { + "type": "string" }, - "class": { - "$ref": "#/components/schemas/ClientClass" + "recycle": { + "$ref": "#/components/schemas/CellsRecycle_LTQxMTg3NTkx" + } + }, + "required": [ + "perFileQuotaBytes", + "recycle" + ], + "type": "object" + }, + "CellsInternalConfigB_Covered_Identity_LTUzMDkwOTAz": { + "properties": { + "backend": { + "$ref": "#/components/schemas/CellsBackend_LTE1Nzg3NzQ2" }, - "cookie": { - "type": "string" + "collabora": { + "$ref": "#/components/schemas/CellsCollabora_LTMzNDA5MDIz" }, - "id": { - "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", - "type": "string" + "storage": { + "$ref": "#/components/schemas/CellsStorage_LTY2Mzc5NzY1" + } + }, + "required": [ + "backend", + "collabora", + "storage" + ], + "type": "object" + }, + "CellsMetadata_LTY1OTM5MTM0": { + "properties": { + "namespaces": { + "$ref": "#/components/schemas/CellsNamespaces_MzUxMjEzOTQw" + } + }, + "required": [ + "namespaces" + ], + "type": "object" + }, + "CellsNamespaces_MzUxMjEzOTQw": { + "properties": { + "usermetaTags": { + "$ref": "#/components/schemas/CellsUserMetaTags_LTc4Njk4NTY0" + } + }, + "required": [ + "usermetaTags" + ], + "type": "object" + }, + "CellsPropertyStatus_MTQ5NjE2MzQ4": { + "enum": [ + "enabled", + "disabled", + "enforced" + ], + "type": "string" + }, + "CellsProperty_NzcxMDIzMzk0": { + "properties": { + "default": { + "$ref": "#/components/schemas/CellsPropertyStatus_MTQ5NjE2MzQ4" }, - "label": { - "type": "string" + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled", + "default" + ], + "type": "object" + }, + "CellsPublicLinks_MjgxMzQ3Mzk4": { + "properties": { + "enableFiles": { + "type": "boolean" }, - "last_active": { - "$ref": "#/components/schemas/UTCTime" + "enableFolders": { + "type": "boolean" }, - "mls_public_keys": { - "$ref": "#/components/schemas/MLSPublicKeys" + "enforceExpirationDefault": { + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" }, - "model": { + "enforceExpirationMax": { + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "enforcePassword": { + "type": "boolean" + } + }, + "required": [ + "enableFiles", + "enableFolders", + "enforcePassword", + "enforceExpirationMax", + "enforceExpirationDefault" + ], + "type": "object" + }, + "CellsRecycle_LTQxMTg3NTkx": { + "properties": { + "allowSkip": { + "type": "boolean" + }, + "autoPurgeDays": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "disable": { + "type": "boolean" + } + }, + "required": [ + "autoPurgeDays", + "disable", + "allowSkip" + ], + "type": "object" + }, + "CellsState_LTg4MDEwNDA5": { + "enum": [ + "disabled", + "pending", + "ready" + ], + "type": "string" + }, + "CellsStorage_LTY2Mzc5NzY1": { + "properties": { + "perUserQuotaBytes": { + "example": "-1", "type": "string" }, - "time": { - "$ref": "#/components/schemas/UTCTimeMillis" + "totalLimitBytes": { + "example": "-1", + "type": "string" + } + }, + "required": [ + "perUserQuotaBytes" + ], + "type": "object" + }, + "CellsUserMetaTags_LTc4Njk4NTY0": { + "properties": { + "allowFreeValues": { + "type": "boolean" }, - "type": { - "$ref": "#/components/schemas/ClientType" + "defaultValues": { + "items": { + "type": "string" + }, + "type": "array" } }, "required": [ - "id", - "type", - "time" + "defaultValues", + "allowFreeValues" + ], + "type": "object" + }, + "CellsUsers_LTQ4NTEyODA1": { + "properties": { + "externals": { + "type": "boolean" + }, + "guests": { + "type": "boolean" + } + }, + "required": [ + "externals", + "guests" + ], + "type": "object" + }, + "ChallengeToken_Mzk3NTcwOTM3": { + "properties": { + "challenge_token": { + "$ref": "#/components/schemas/Token" + } + }, + "required": [ + "challenge_token" ], "type": "object" }, - "ClientCapability": { + "ChannelPermissions_Mzc1MTM3NTg2": { "enum": [ - "legalhold-implicit-consent" + "team-members", + "everyone", + "admins" ], "type": "string" }, - "ClientCapabilityList": { + "ChannelsConfigB_Covered_Identity_ODk2MTk3NDQ4": { "properties": { - "capabilities": { - "description": "Hints provided by the client for the backend so it can behave in a backwards-compatible way.", + "allowed_to_create_channels": { + "$ref": "#/components/schemas/ChannelPermissions_Mzc1MTM3NTg2" + }, + "allowed_to_open_channels": { + "$ref": "#/components/schemas/ChannelPermissions_Mzc1MTM3NTg2" + } + }, + "required": [ + "allowed_to_create_channels", + "allowed_to_open_channels" + ], + "type": "object" + }, + "CheckHandles_LTc0OTkxMzAx": { + "properties": { + "handles": { + "items": { + "type": "string" + }, + "maxItems": 50, + "minItems": 1, + "type": "array" + }, + "return": { + "maximum": 10, + "minimum": 1, + "type": "integer" + } + }, + "required": [ + "handles", + "return" + ], + "type": "object" + }, + "CheckUserGroupName_LTg0ODU1OTk1": { + "properties": { + "name": { + "maxLength": 4000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "CipherSuiteTag": { + "description": "The cipher suite of the corresponding MLS group", + "maximum": 65535, + "minimum": 0, + "type": "integer" + }, + "ClassifiedDomainsConfig_LTg4MDcwMDg2": { + "properties": { + "domains": { "items": { - "$ref": "#/components/schemas/ClientCapability" + "$ref": "#/components/schemas/Domain" }, "type": "array" } }, "required": [ - "capabilities" + "domains" ], "type": "object" }, - "ClientClass": { + "ClientCapabilityList": { + "items": { + "$ref": "#/components/schemas/ClientCapability_MTY2NDAzMjM3" + }, + "type": "array" + }, + "ClientCapability_MTY2NDAzMjM3": { + "enum": [ + "legalhold-implicit-consent", + "consumable-notifications" + ], + "type": "string" + }, + "ClientClass_NjE3MDgwNzcx": { "enum": [ "phone", "tablet", @@ -850,7 +1086,7 @@ ], "type": "string" }, - "ClientIdentity": { + "ClientIdentity_MjAxMjI3NTUw": { "properties": { "client_id": { "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", @@ -870,13 +1106,7 @@ ], "type": "object" }, - "ClientListv6": { - "items": { - "$ref": "#/components/schemas/Client" - }, - "type": "array" - }, - "ClientMismatch": { + "ClientMismatch_ODUyODM0MDQ0": { "properties": { "deleted": { "$ref": "#/components/schemas/UserClients" @@ -899,14 +1129,14 @@ ], "type": "object" }, - "ClientPrekey": { + "ClientPrekey_LTcyODUzMTcw": { "properties": { "client": { "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", "type": "string" }, "prekey": { - "$ref": "#/components/schemas/Prekey" + "$ref": "#/components/schemas/UncheckedPrekeyBundle_LTU1MzQzOTgy" } }, "required": [ @@ -915,7 +1145,7 @@ ], "type": "object" }, - "ClientType": { + "ClientType_MjQ0OTQwMzcw": { "enum": [ "temporary", "permanent", @@ -923,13 +1153,13 @@ ], "type": "string" }, - "Clientv6": { + "Client_MTM1OTcwOTQ1": { "properties": { "capabilities": { "$ref": "#/components/schemas/ClientCapabilityList" }, "class": { - "$ref": "#/components/schemas/ClientClass" + "$ref": "#/components/schemas/ClientClass_NjE3MDgwNzcx" }, "cookie": { "type": "string" @@ -954,7 +1184,7 @@ "$ref": "#/components/schemas/UTCTimeMillis" }, "type": { - "$ref": "#/components/schemas/ClientType" + "$ref": "#/components/schemas/ClientType_MjQ0OTQwMzcw" } }, "required": [ @@ -964,17 +1194,33 @@ ], "type": "object" }, - "CodeChallengeMethod": { + "CodeChallengeMethod_NTIxNzk0NDgw": { "description": "The method used to encode the code challenge. Only `S256` is supported.", "enum": [ "S256" ], "type": "string" }, + "CollaboraEdition_LTg2NDA1NDQ4": { + "enum": [ + "NO", + "CODE", + "COOL" + ], + "type": "string" + }, + "CollaboratorPermission_NDg5NTg2ODgy": { + "description": "

Permission granted to a team collaborator.

  • `create_team_conversation`: equivalent to the `CreateConversation` and `AddRemoveConvMember` permissions for team members (both implied in the `member` role); allows creating team group conversations and adding members to them.
  • \n
  • `implicit_connection`: team members are implicitly connected to each other, allowing conversations (1:1 or group) without an explicit connection request. This permission grants the same to a collaborator.
\n

NB: a member of team A can always open conversations with a collaborator of team A; the permission only controls the collaborator's abilities.

", + "enum": [ + "create_team_conversation", + "implicit_connection" + ], + "type": "string" + }, "CommitBundle": { "description": "This object can only be parsed in TLS format. Please refer to the MLS specification for details." }, - "CompletePasswordReset": { + "CompletePasswordReset_LTYzMDAxNDA1": { "properties": { "code": { "$ref": "#/components/schemas/ASCII" @@ -995,59 +1241,43 @@ ], "type": "object" }, - "ConferenceCallingConfig": { - "properties": { - "useSFTForOneToOneCalls": { - "type": "boolean" - } - }, - "type": "object" - }, - "ConferenceCallingConfig.Feature": { + "CompletePasswordReset_NDcyMjY5OTc4": { + "description": "Data to complete a password reset", "properties": { - "config": { - "$ref": "#/components/schemas/ConferenceCallingConfig" + "code": { + "$ref": "#/components/schemas/ASCII" }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" + "email": { + "$ref": "#/components/schemas/Email" }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "key": { + "$ref": "#/components/schemas/ASCII" + }, + "password": { + "description": "New password (6 - 1024 characters)", + "maxLength": 1024, + "minLength": 8, + "type": "string" + }, + "phone": { + "$ref": "#/components/schemas/PhoneNumber" } }, "required": [ - "status" + "code", + "password" ], "type": "object" }, - "ConferenceCallingConfig.LockableFeature": { + "ConferenceCallingConfigB_Covered_Identity_NDMwMjcyMzM1": { "properties": { - "config": { - "$ref": "#/components/schemas/ConferenceCallingConfig" - }, - "lockStatus": { - "$ref": "#/components/schemas/LockStatus" - }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" - }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "useSFTForOneToOneCalls": { + "type": "boolean" } }, - "required": [ - "status", - "lockStatus" - ], "type": "object" }, - "Connect": { + "Connect_ODY3OTE4NTYx": { "properties": { "email": { "type": "string" @@ -1059,7 +1289,7 @@ "type": "string" }, "qualified_recipient": { - "$ref": "#/components/schemas/Qualified_UserId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" }, "recipient": { "$ref": "#/components/schemas/UUID" @@ -1070,10 +1300,10 @@ ], "type": "object" }, - "ConnectionUpdate": { + "ConnectionUpdate_LTU3MTA1OTA5": { "properties": { "status": { - "$ref": "#/components/schemas/Relation" + "$ref": "#/components/schemas/Relation_LTE4OTU5MTk4" } }, "required": [ @@ -1081,32 +1311,28 @@ ], "type": "object" }, - "Connections_Page": { + "Connections_PagingState": { + "type": "string" + }, + "ContactStatusState_LTg2MjAyNzAx": { + "enum": [ + "contactable", + "non-contactable" + ], + "type": "string" + }, + "ContactStatus_LTUzNzk1MzM4": { "properties": { - "connections": { - "items": { - "$ref": "#/components/schemas/UserConnection" - }, - "type": "array" - }, - "has_more": { - "type": "boolean" - }, - "paging_state": { - "$ref": "#/components/schemas/Connections_PagingState" + "state": { + "$ref": "#/components/schemas/ContactStatusState_LTg2MjAyNzAx" } }, "required": [ - "connections", - "has_more", - "paging_state" + "state" ], "type": "object" }, - "Connections_PagingState": { - "type": "string" - }, - "Contact": { + "Contact_LTcwODE3Mjc5": { "description": "Contact discovered through search", "properties": { "accent_id": { @@ -1124,39 +1350,42 @@ "type": "string" }, "qualified_id": { - "$ref": "#/components/schemas/Qualified_UserId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" }, "team": { "$ref": "#/components/schemas/UUID" + }, + "type": { + "$ref": "#/components/schemas/UserType_LTU1OTU4OTM5" } }, "required": [ "qualified_id", - "name" + "name", + "type" ], "type": "object" }, - "ConvMembers": { + "ConvMembers_LTc2MDg1NDg2": { "description": "Users of a conversation", "properties": { "others": { "description": "All other current users of this conversation", "items": { - "$ref": "#/components/schemas/OtherMember" + "$ref": "#/components/schemas/OtherMember_LTgzNzE2MTk4" }, "type": "array" }, "self": { - "$ref": "#/components/schemas/Member" + "$ref": "#/components/schemas/Member_OTA5OTgyNzcw" } }, "required": [ - "self", "others" ], "type": "object" }, - "ConvTeamInfo": { + "ConvTeamInfo_Mzc5NjcyNjAz": { "description": "Team information of this conversation", "properties": { "managed": { @@ -1172,7 +1401,7 @@ ], "type": "object" }, - "ConvType": { + "ConvType_MzM0NTE3ODE5": { "enum": [ 0, 1, @@ -1181,104 +1410,17 @@ ], "type": "integer" }, - "Conversation": { - "description": "A conversation object as returned from the server", - "properties": { - "access": { - "items": { - "$ref": "#/components/schemas/Access" - }, - "type": "array" - }, - "access_role": { - "items": { - "$ref": "#/components/schemas/AccessRole" - }, - "type": "array" - }, - "cipher_suite": { - "$ref": "#/components/schemas/CipherSuiteTag" - }, - "creator": { - "$ref": "#/components/schemas/UUID" - }, - "epoch": { - "description": "The epoch number of the corresponding MLS group", - "format": "int64", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" - }, - "epoch_timestamp": { - "$ref": "#/components/schemas/UTCTime" - }, - "group_id": { - "$ref": "#/components/schemas/GroupId" - }, - "id": { - "$ref": "#/components/schemas/UUID" - }, - "last_event": { - "type": "string" - }, - "last_event_time": { - "type": "string" - }, - "members": { - "$ref": "#/components/schemas/ConvMembers" - }, - "message_timer": { - "description": "Per-conversation message timer (can be null)", - "format": "int64", - "maximum": 9223372036854775807, - "minimum": -9223372036854775808, - "type": "integer" - }, - "name": { - "type": "string" - }, - "protocol": { - "$ref": "#/components/schemas/Protocol" - }, - "qualified_id": { - "$ref": "#/components/schemas/Qualified_ConvId" - }, - "receipt_mode": { - "description": "Conversation receipt mode", - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer" - }, - "team": { - "$ref": "#/components/schemas/UUID" - }, - "type": { - "$ref": "#/components/schemas/ConvType" - } - }, - "required": [ - "qualified_id", - "type", - "access", - "access_role", - "members", - "group_id", - "epoch" - ], - "type": "object" - }, - "ConversationAccessData": { + "ConversationAccessData_MjMxMTI5ODc3": { "properties": { "access": { "items": { - "$ref": "#/components/schemas/Access" + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" }, "type": "array" }, "access_role": { "items": { - "$ref": "#/components/schemas/AccessRole" + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" }, "type": "array" } @@ -1289,35 +1431,16 @@ ], "type": "object" }, - "ConversationAccessDataV2": { - "properties": { - "access": { - "items": { - "$ref": "#/components/schemas/Access" - }, - "type": "array" - }, - "access_role": { - "$ref": "#/components/schemas/AccessRoleLegacy" - }, - "access_role_v2": { - "items": { - "$ref": "#/components/schemas/AccessRole" - }, - "type": "array" - } - }, - "required": [ - "access" - ], - "type": "object" - }, - "ConversationCode": { + "ConversationCodeInfo_LTc5MzgzNjg3": { "description": "Contains conversation properties to update", "properties": { "code": { "$ref": "#/components/schemas/ASCII" }, + "has_password": { + "description": "Whether the conversation has a password", + "type": "boolean" + }, "key": { "$ref": "#/components/schemas/ASCII" }, @@ -1327,35 +1450,29 @@ }, "required": [ "key", - "code" + "code", + "uri", + "has_password" ], "type": "object" }, - "ConversationCodeInfo": { + "ConversationCode_Mjg3OTI1NTMx": { "description": "Contains conversation properties to update", "properties": { "code": { "$ref": "#/components/schemas/ASCII" }, - "has_password": { - "description": "Whether the conversation has a password", - "type": "boolean" - }, "key": { "$ref": "#/components/schemas/ASCII" - }, - "uri": { - "$ref": "#/components/schemas/HttpsUrl" } }, "required": [ "key", - "code", - "has_password" + "code" ], "type": "object" }, - "ConversationCoverView": { + "ConversationCoverView_LTMwNDkxMTA1": { "description": "Limited view of Conversation.", "properties": { "has_password": { @@ -1374,32 +1491,21 @@ ], "type": "object" }, - "ConversationIds_Page": { + "ConversationHistoryUpdate_LTg5MDQ5Nzgx": { "properties": { - "has_more": { - "type": "boolean" - }, - "paging_state": { - "$ref": "#/components/schemas/ConversationIds_PagingState" - }, - "qualified_conversations": { - "items": { - "$ref": "#/components/schemas/Qualified_ConvId" - }, - "type": "array" + "history": { + "$ref": "#/components/schemas/History" } }, "required": [ - "qualified_conversations", - "has_more", - "paging_state" + "history" ], "type": "object" }, "ConversationIds_PagingState": { "type": "string" }, - "ConversationMessageTimerUpdate": { + "ConversationMessageTimerUpdate_LTcxMjUwNzQ4": { "description": "Contains conversation properties to update", "properties": { "message_timer": { @@ -1411,7 +1517,22 @@ }, "type": "object" }, - "ConversationReceiptModeUpdate": { + "ConversationPage_LTIwMDU2NDI3": { + "description": "This is the last page if it contains fewer rows than requested. There may be 0 rows on a page.", + "properties": { + "page": { + "items": { + "$ref": "#/components/schemas/ConversationSearchResult_NDI0MTcyMDU3" + }, + "type": "array" + } + }, + "required": [ + "page" + ], + "type": "object" + }, + "ConversationReceiptModeUpdate_NDE4MzUzNTU3": { "description": "Contains conversation receipt mode to update to. Receipt mode tells clients whether certain types of receipts should be sent in the given conversation or not. How this value is interpreted is up to clients.", "properties": { "receipt_mode": { @@ -1427,7 +1548,7 @@ ], "type": "object" }, - "ConversationRename": { + "ConversationRename_ODkwODg1MzQ0": { "properties": { "name": { "description": "The new conversation name", @@ -1439,6 +1560,20 @@ ], "type": "object" }, + "ConversationReset_MzU1Nzc5MjAw": { + "properties": { + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "new_group_id": { + "$ref": "#/components/schemas/GroupId" + } + }, + "required": [ + "group_id" + ], + "type": "object" + }, "ConversationRole": { "properties": { "actions": { @@ -1467,200 +1602,59 @@ ], "type": "object" }, - "ConversationV2": { - "description": "A conversation object as returned from the server", + "ConversationSearchResult_NDI0MTcyMDU3": { "properties": { "access": { "items": { - "$ref": "#/components/schemas/Access" + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" }, "type": "array" }, - "access_role": { - "$ref": "#/components/schemas/AccessRoleLegacy" - }, - "access_role_v2": { - "items": { - "$ref": "#/components/schemas/AccessRole" - }, - "type": "array" - }, - "cipher_suite": { - "$ref": "#/components/schemas/CipherSuiteTag" - }, - "creator": { - "$ref": "#/components/schemas/UUID" - }, - "epoch": { - "description": "The epoch number of the corresponding MLS group", - "format": "int64", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" - }, - "epoch_timestamp": { - "$ref": "#/components/schemas/Epoch Timestamp" - }, - "group_id": { - "$ref": "#/components/schemas/GroupId" + "admin_count": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" }, "id": { "$ref": "#/components/schemas/UUID" }, - "last_event": { - "type": "string" - }, - "last_event_time": { - "type": "string" - }, - "members": { - "$ref": "#/components/schemas/ConvMembers" - }, - "message_timer": { - "description": "Per-conversation message timer (can be null)", - "format": "int64", + "member_count": { "maximum": 9223372036854775807, "minimum": -9223372036854775808, "type": "integer" }, "name": { "type": "string" - }, - "protocol": { - "$ref": "#/components/schemas/Protocol" - }, - "qualified_id": { - "$ref": "#/components/schemas/Qualified_ConvId" - }, - "receipt_mode": { - "description": "Conversation receipt mode", - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer" - }, - "team": { - "$ref": "#/components/schemas/UUID" - }, - "type": { - "$ref": "#/components/schemas/ConvType" } }, "required": [ - "qualified_id", - "type", + "id", "access", - "members", - "group_id", - "epoch", - "epoch_timestamp", - "cipher_suite" + "member_count", + "admin_count" ], "type": "object" }, - "ConversationV3v3": { + "Conversation_GroupConvType_MzQzMTQ1OTg3": { "description": "A conversation object as returned from the server", "properties": { "access": { "items": { - "$ref": "#/components/schemas/Access" + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" }, "type": "array" }, "access_role": { "items": { - "$ref": "#/components/schemas/AccessRole" + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" }, "type": "array" }, - "cipher_suite": { - "$ref": "#/components/schemas/CipherSuiteTag" - }, - "creator": { - "$ref": "#/components/schemas/UUID" - }, - "epoch": { - "description": "The epoch number of the corresponding MLS group", - "format": "int64", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" - }, - "epoch_timestamp": { - "$ref": "#/components/schemas/Epoch Timestamp" - }, - "group_id": { - "$ref": "#/components/schemas/GroupId" - }, - "id": { - "$ref": "#/components/schemas/UUID" - }, - "last_event": { - "type": "string" - }, - "last_event_time": { - "type": "string" - }, - "members": { - "$ref": "#/components/schemas/ConvMembers" - }, - "message_timer": { - "description": "Per-conversation message timer (can be null)", - "format": "int64", - "maximum": 9223372036854775807, - "minimum": -9223372036854775808, - "type": "integer" - }, - "name": { - "type": "string" - }, - "protocol": { - "$ref": "#/components/schemas/Protocol" - }, - "qualified_id": { - "$ref": "#/components/schemas/Qualified_ConvId" - }, - "receipt_mode": { - "description": "Conversation receipt mode", - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer" - }, - "team": { - "$ref": "#/components/schemas/UUID" - }, - "type": { - "$ref": "#/components/schemas/ConvType" - } - }, - "required": [ - "qualified_id", - "type", - "access", - "access_role", - "members", - "group_id", - "epoch", - "epoch_timestamp", - "cipher_suite" - ], - "type": "object" - }, - "ConversationV6v6": { - "description": "A conversation object as returned from the server", - "properties": { - "access": { - "items": { - "$ref": "#/components/schemas/Access" - }, - "type": "array" + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" }, - "access_role": { - "items": { - "$ref": "#/components/schemas/AccessRole" - }, - "type": "array" + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" }, "cipher_suite": { "$ref": "#/components/schemas/CipherSuiteTag" @@ -1678,11 +1672,14 @@ "epoch_timestamp": { "$ref": "#/components/schemas/UTCTime" }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" + }, "group_id": { "$ref": "#/components/schemas/GroupId" }, - "id": { - "$ref": "#/components/schemas/UUID" + "history": { + "$ref": "#/components/schemas/History" }, "last_event": { "type": "string" @@ -1691,7 +1688,7 @@ "type": "string" }, "members": { - "$ref": "#/components/schemas/ConvMembers" + "$ref": "#/components/schemas/ConvMembers_LTc2MDg1NDg2" }, "message_timer": { "description": "Per-conversation message timer (can be null)", @@ -1703,11 +1700,14 @@ "name": { "type": "string" }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, "protocol": { - "$ref": "#/components/schemas/Protocol" + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" }, "qualified_id": { - "$ref": "#/components/schemas/Qualified_ConvId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" }, "receipt_mode": { "description": "Conversation receipt mode", @@ -1720,7 +1720,7 @@ "$ref": "#/components/schemas/UUID" }, "type": { - "$ref": "#/components/schemas/ConvType" + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" } }, "required": [ @@ -1734,26 +1734,26 @@ ], "type": "object" }, - "ConversationsResponse": { + "ConversationsResponse_GroupConvType_ODkxMjM2ODM0": { "description": "Response object for getting metadata of a list of conversations", "properties": { "failed": { "description": "The server failed to fetch these conversations, most likely due to network issues while contacting a remote server", "items": { - "$ref": "#/components/schemas/Qualified_ConvId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" }, "type": "array" }, "found": { "items": { - "$ref": "#/components/schemas/Conversation" + "$ref": "#/components/schemas/OwnConversation_GroupConvType_LTU2MzYxNTg0" }, "type": "array" }, "not_found": { "description": "These conversations either don't exist or are deleted.", "items": { - "$ref": "#/components/schemas/Qualified_ConvId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" }, "type": "array" } @@ -1765,7 +1765,29 @@ ], "type": "object" }, - "Cookie": { + "CookieList_LTM4MzYwNzAz": { + "description": "List of cookie information", + "properties": { + "cookies": { + "items": { + "$ref": "#/components/schemas/Cookie_LTkyMDA3OTI5" + }, + "type": "array" + } + }, + "required": [ + "cookies" + ], + "type": "object" + }, + "CookieType_LTE0MjczNzY3": { + "enum": [ + "session", + "persistent" + ], + "type": "string" + }, + "Cookie_LTkyMDA3OTI5": { "properties": { "created": { "$ref": "#/components/schemas/UTCTime" @@ -1789,7 +1811,7 @@ "type": "integer" }, "type": { - "$ref": "#/components/schemas/CookieType" + "$ref": "#/components/schemas/CookieType_LTE0MjczNzY3" } }, "required": [ @@ -1800,29 +1822,7 @@ ], "type": "object" }, - "CookieList": { - "description": "List of cookie information", - "properties": { - "cookies": { - "items": { - "$ref": "#/components/schemas/Cookie" - }, - "type": "array" - } - }, - "required": [ - "cookies" - ], - "type": "object" - }, - "CookieType": { - "enum": [ - "session", - "persistent" - ], - "type": "string" - }, - "CreateConversationCodeRequest": { + "CreateConversationCodeRequest_NTYzMTA1NDYz": { "description": "Request body for creating a conversation code", "properties": { "password": { @@ -1834,21 +1834,27 @@ }, "type": "object" }, - "CreateGroupConversationv6": { + "CreateGroupConversation_GroupConvType_MTQ3OTc4NDk3": { "description": "A created group-conversation object extended with a list of failed-to-add users", "properties": { "access": { "items": { - "$ref": "#/components/schemas/Access" + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" }, "type": "array" }, "access_role": { "items": { - "$ref": "#/components/schemas/AccessRole" + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" }, "type": "array" }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" + }, "cipher_suite": { "$ref": "#/components/schemas/CipherSuiteTag" }, @@ -1867,15 +1873,18 @@ }, "failed_to_add": { "items": { - "$ref": "#/components/schemas/Qualified_UserId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" }, "type": "array" }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" + }, "group_id": { "$ref": "#/components/schemas/GroupId" }, - "id": { - "$ref": "#/components/schemas/UUID" + "history": { + "$ref": "#/components/schemas/History" }, "last_event": { "type": "string" @@ -1884,7 +1893,7 @@ "type": "string" }, "members": { - "$ref": "#/components/schemas/ConvMembers" + "$ref": "#/components/schemas/ConvMembers_LTc2MDg1NDg2" }, "message_timer": { "description": "Per-conversation message timer (can be null)", @@ -1896,11 +1905,14 @@ "name": { "type": "string" }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, "protocol": { - "$ref": "#/components/schemas/Protocol" + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" }, "qualified_id": { - "$ref": "#/components/schemas/Qualified_ConvId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" }, "receipt_mode": { "description": "Conversation receipt mode", @@ -1913,7 +1925,7 @@ "$ref": "#/components/schemas/UUID" }, "type": { - "$ref": "#/components/schemas/ConvType" + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" } }, "required": [ @@ -1928,7 +1940,7 @@ ], "type": "object" }, - "CreateOAuthAuthorizationCodeRequest": { + "CreateOAuthAuthorizationCodeRequest_LTQ3NzI1Mjkz": { "properties": { "client_id": { "$ref": "#/components/schemas/UUID" @@ -1937,13 +1949,13 @@ "$ref": "#/components/schemas/OAuthCodeChallenge" }, "code_challenge_method": { - "$ref": "#/components/schemas/CodeChallengeMethod" + "$ref": "#/components/schemas/CodeChallengeMethod_NTIxNzk0NDgw" }, "redirect_uri": { "$ref": "#/components/schemas/RedirectUrl" }, "response_type": { - "$ref": "#/components/schemas/OAuthResponseType" + "$ref": "#/components/schemas/OAuthResponseType_ODI2Mjg3NzQx" }, "scope": { "description": "The scopes which are requested to get authorization for, separated by a space", @@ -1965,16 +1977,39 @@ ], "type": "object" }, - "CreateScimToken": { + "CreateScimTokenResponse_LTIzOTU2NDU4": { + "properties": { + "info": { + "$ref": "#/components/schemas/ScimTokenInfo_LTI5NjgwNzA1" + }, + "token": { + "type": "string" + } + }, + "required": [ + "token", + "info" + ], + "type": "object" + }, + "CreateScimToken_OTY0NjYxMDQ2": { "properties": { "description": { "type": "string" }, + "idp": { + "$ref": "#/components/schemas/UUID" + }, + "name": { + "type": "string" + }, "password": { + "maxLength": 1024, + "minLength": 6, "type": "string" }, "verification_code": { - "type": "string" + "$ref": "#/components/schemas/ASCII" } }, "required": [ @@ -1982,23 +2017,37 @@ ], "type": "object" }, - "CreateScimTokenResponse": { + "CreateUserTeam_MzI4NDQ1Mzkw": { "properties": { - "info": { - "$ref": "#/components/schemas/ScimTokenInfo" + "team_id": { + "$ref": "#/components/schemas/UUID" }, - "token": { - "description": "Authentication token", + "team_name": { "type": "string" } }, "required": [ - "token", - "info" + "team_id", + "team_name" + ], + "type": "object" + }, + "CreatedApp_LTM3NjUxOTY1": { + "properties": { + "cookie": { + "$ref": "#/components/schemas/SomeUserToken" + }, + "user": { + "$ref": "#/components/schemas/UserProfile_LTQzMTQxMTE1" + } + }, + "required": [ + "user", + "cookie" ], "type": "object" }, - "CustomBackend": { + "CustomBackend_LTQxODI0MjQ0": { "description": "Description of a custom backend", "properties": { "config_json_url": { @@ -2017,7 +2066,7 @@ "DPoPAccessToken": { "type": "string" }, - "DPoPAccessTokenResponse": { + "DPoPAccessTokenResponse_LTgyODU5MDE3": { "properties": { "expires_in": { "format": "int64", @@ -2029,7 +2078,7 @@ "$ref": "#/components/schemas/DPoPAccessToken" }, "type": { - "$ref": "#/components/schemas/AccessTokenType" + "$ref": "#/components/schemas/AccessTokenType_LTgyOTY0NDE5" } }, "required": [ @@ -2039,18 +2088,7 @@ ], "type": "object" }, - "DeleteClient": { - "properties": { - "password": { - "description": "The password of the authenticated user for verification. The password is not required for deleting temporary clients.", - "maxLength": 1024, - "minLength": 6, - "type": "string" - } - }, - "type": "object" - }, - "DeleteKeyPackages": { + "DeleteKeyPackages_LTQxNTcxNjY3": { "properties": { "key_packages": { "items": { @@ -2066,7 +2104,7 @@ ], "type": "object" }, - "DeleteProvider": { + "DeleteProvider_MzYxMzM3Mjg2": { "properties": { "password": { "maxLength": 1024, @@ -2079,7 +2117,7 @@ ], "type": "object" }, - "DeleteService": { + "DeleteService_LTY2NzY5NzMz": { "properties": { "password": { "maxLength": 1024, @@ -2092,26 +2130,31 @@ ], "type": "object" }, - "DeleteSubConversationRequest": { - "description": "Delete an MLS subconversation", + "DeleteUser_NjE0MjE2Mjkz": { "properties": { - "epoch": { - "format": "int64", - "maximum": 18446744073709551615, - "minimum": 0, + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "type": "object" + }, + "DeletionCodeTimeout_LTU1MTk0NDI3": { + "properties": { + "expires_in": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, "type": "integer" - }, - "group_id": { - "$ref": "#/components/schemas/GroupId" } }, "required": [ - "group_id", - "epoch" + "expires_in" ], "type": "object" }, - "DeleteUser": { + "DisableLegalHoldForUserRequest_LTYyMDYxOTEy": { "properties": { "password": { "maxLength": 1024, @@ -2121,74 +2164,134 @@ }, "type": "object" }, - "DeletionCodeTimeout": { + "Domain": { + "example": "example.com", + "type": "string" + }, + "DomainOwnershipToken_NTU0ODc1NDE5": { "properties": { - "expires_in": { - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer" + "domain_ownership_token": { + "$ref": "#/components/schemas/Token" } }, "required": [ - "expires_in" + "domain_ownership_token" ], "type": "object" }, - "DeprecatedMatchingResult": { - "deprecated": true, + "DomainRedirectConfigTag_MjE2MDI4MDIw": { + "enum": [ + "remove", + "backend", + "no-registration" + ], + "type": "string" + }, + "DomainRedirectConfig_NTI5NDE5MDQy": { "properties": { - "auto-connects": { - "items": {}, - "type": "array" + "backend": { + "$ref": "#/components/schemas/HttpsUrl_HttpsUrl_NjUyMDgzNzk3" }, - "results": { - "items": {}, - "type": "array" + "domain_redirect": { + "$ref": "#/components/schemas/DomainRedirectConfigTag_MjE2MDI4MDIw" } }, "required": [ - "results", - "auto-connects" + "domain_redirect", + "backend" ], "type": "object" }, - "DigitalSignaturesConfig.LockableFeature": { + "DomainRedirectResponse_V10_LTEyMjI4NTM0": { "properties": { - "lockStatus": { - "$ref": "#/components/schemas/LockStatus" + "backend": { + "$ref": "#/components/schemas/HttpsUrl_Maybe_HttpsUrl_LTQ1MDkyMzY2" }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" + "domain_redirect": { + "$ref": "#/components/schemas/DomainRedirectTag_LTY3NjU1MDEy" }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "due_to_existing_account": { + "type": "boolean" + }, + "sso_code": { + "$ref": "#/components/schemas/UUID" } }, "required": [ - "status", - "lockStatus" + "domain_redirect", + "sso_code", + "backend" ], "type": "object" }, - "DisableLegalHoldForUserRequest": { + "DomainRedirectTag_LTY3NjU1MDEy": { + "enum": [ + "none", + "locked", + "sso", + "backend", + "no-registration", + "pre-authorized" + ], + "type": "string" + }, + "DomainRegistrationResponse_V10_MjE0NDkxODY4": { "properties": { - "password": { - "maxLength": 1024, - "minLength": 6, - "type": "string" + "authorized_team": { + "$ref": "#/components/schemas/UUID" + }, + "backend": { + "$ref": "#/components/schemas/HttpsUrl_Maybe_HttpsUrl_LTQ1MDkyMzY2" + }, + "dns_verification_token": { + "$ref": "#/components/schemas/ASCII" + }, + "domain": { + "$ref": "#/components/schemas/Domain" + }, + "domain_redirect": { + "$ref": "#/components/schemas/DomainRedirectTag_LTY3NjU1MDEy" + }, + "sso_code": { + "$ref": "#/components/schemas/UUID" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "team_invite": { + "$ref": "#/components/schemas/TeamInviteTag_LTQyNTMyNzA0" } }, + "required": [ + "domain", + "domain_redirect", + "sso_code", + "backend", + "team_invite", + "team" + ], "type": "object" }, - "Domain": { - "example": "example.com", - "type": "string" + "DomainVerificationChallenge_NjIwMzA1MjE5": { + "properties": { + "dns_verification_token": { + "$ref": "#/components/schemas/ASCII" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "token": { + "$ref": "#/components/schemas/Token" + } + }, + "required": [ + "id", + "token", + "dns_verification_token" + ], + "type": "object" }, - "EdMemberLeftReason": { + "EdMemberLeftReason_OTAyMDA4NzEw": { "enum": [ "left", "user-deleted", @@ -2196,12 +2299,39 @@ ], "type": "string" }, + "EdMemberLeftReason_QualifiedUserIdList_LTYyOTg2OTQ1": { + "properties": { + "qualified_user_ids": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "type": "array" + }, + "reason": { + "$ref": "#/components/schemas/EdMemberLeftReason_OTAyMDA4NzEw" + }, + "user_ids": { + "deprecated": true, + "description": "Deprecated, use qualified_user_ids", + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + } + }, + "required": [ + "reason", + "qualified_user_ids", + "user_ids" + ], + "type": "object" + }, "Either_OAuthAccessTokenRequest_OAuthRefreshAccessTokenRequest": { "oneOf": [ { "properties": { "Left": { - "$ref": "#/components/schemas/OAuthAccessTokenRequest" + "$ref": "#/components/schemas/OAuthAccessTokenRequest_LTYyNTcyMzI4" } }, "required": [ @@ -2213,7 +2343,7 @@ { "properties": { "Right": { - "$ref": "#/components/schemas/OAuthRefreshAccessTokenRequest" + "$ref": "#/components/schemas/OAuthRefreshAccessTokenRequest_LTUwNjA3OTI1" } }, "required": [ @@ -2227,7 +2357,7 @@ "Email": { "type": "string" }, - "EmailUpdate": { + "EmailUpdate_LTYwODE0ODQ5": { "properties": { "email": { "$ref": "#/components/schemas/Email" @@ -2238,89 +2368,98 @@ ], "type": "object" }, - "EnforceFileDownloadLocation": { - "properties": { - "enforcedDownloadLocation": { - "type": "string" - } - }, - "type": "object" - }, - "EnforceFileDownloadLocation.Feature": { + "EmailUpdate_NjQ5MDg1OTY0": { "properties": { - "config": { - "$ref": "#/components/schemas/EnforceFileDownloadLocation" - }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" - }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "email": { + "$ref": "#/components/schemas/Email" } }, "required": [ - "status", - "config" + "email" ], "type": "object" }, - "EnforceFileDownloadLocation.LockableFeature": { + "EnforceFilDwadLtCgB_vIy_LTQ2NjU1Nzcx": { "properties": { - "config": { - "$ref": "#/components/schemas/EnforceFileDownloadLocation" - }, - "lockStatus": { - "$ref": "#/components/schemas/LockStatus" - }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" - }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "enforcedDownloadLocation": { + "type": "string" } }, - "required": [ - "status", - "lockStatus", - "config" - ], "type": "object" }, - "Epoch Timestamp": { + "EpochTimestamp": { "example": "2021-05-12T10:52:02Z", "format": "yyyy-mm-ddThh:MM:ssZ", "type": "string" }, - "Event": { + "EventType_LTQ3NTQyNDYz": { + "enum": [ + "conversation.member-join", + "conversation.member-leave", + "conversation.member-update", + "conversation.rename", + "conversation.access-update", + "conversation.receipt-mode-update", + "conversation.message-timer-update", + "conversation.code-update", + "conversation.code-delete", + "conversation.create", + "conversation.create-meeting", + "conversation.delete", + "conversation.delete-meeting", + "conversation.mls-reset", + "conversation.connect-request", + "conversation.typing", + "conversation.otr-message-add", + "conversation.mls-message-add", + "conversation.mls-welcome", + "conversation.protocol-update", + "conversation.add-permission-update", + "conversation.history-update", + "conversation.adminless-reminder" + ], + "type": "string" + }, + "EventVia_Mjc4MzcyNzE0": { + "enum": [ + "scim", + "user" + ], + "type": "string" + }, + "Event_LTMwMTMyODM5": { "properties": { "conversation": { "$ref": "#/components/schemas/UUID" }, "data": { - "description": "Encrypted message of a conversation", + "description": "The action of changing the permission to add members to a channel", "example": "ZXhhbXBsZQo=", "properties": { "access": { "items": { - "$ref": "#/components/schemas/Access" + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" }, "type": "array" }, "access_role": { - "$ref": "#/components/schemas/AccessRoleLegacy" + "$ref": "#/components/schemas/AccessRoleLegacy_LTYwOTAxMDI1" }, "access_role_v2": { "items": { - "$ref": "#/components/schemas/AccessRole" + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" }, "type": "array" }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "add_type": { + "$ref": "#/components/schemas/JoinType_LTY4MDg2MzA5" + }, + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" + }, "cipher_suite": { "$ref": "#/components/schemas/CipherSuiteTag" }, @@ -2337,6 +2476,12 @@ "description": "Extra (symmetric) data (i.e. ciphertext, Base64 in JSON) that is common with all other recipients.", "type": "string" }, + "deletion_scheduled_for": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "depth": { + "$ref": "#/components/schemas/HistoryDuration" + }, "email": { "type": "string" }, @@ -2348,7 +2493,10 @@ "type": "integer" }, "epoch_timestamp": { - "$ref": "#/components/schemas/Epoch Timestamp" + "$ref": "#/components/schemas/EpochTimestamp" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" }, "group_id": { "$ref": "#/components/schemas/GroupId" @@ -2363,6 +2511,9 @@ "hidden_ref": { "type": "string" }, + "history": { + "$ref": "#/components/schemas/History" + }, "id": { "$ref": "#/components/schemas/UUID" }, @@ -2376,7 +2527,7 @@ "type": "string" }, "members": { - "$ref": "#/components/schemas/ConvMembers" + "$ref": "#/components/schemas/OwnConvMembers_LTEwMzUzODMy" }, "message": { "type": "string" @@ -2391,6 +2542,9 @@ "name": { "type": "string" }, + "new_group_id": { + "$ref": "#/components/schemas/GroupId" + }, "otr_archived": { "type": "boolean" }, @@ -2406,26 +2560,29 @@ "minimum": -2147483648, "type": "integer" }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, "protocol": { - "$ref": "#/components/schemas/Protocol" + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" }, "qualified_id": { - "$ref": "#/components/schemas/Qualified_ConvId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" }, "qualified_recipient": { - "$ref": "#/components/schemas/Qualified_UserId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" }, "qualified_target": { - "$ref": "#/components/schemas/Qualified_UserId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" }, "qualified_user_ids": { "items": { - "$ref": "#/components/schemas/Qualified_UserId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" }, "type": "array" }, "reason": { - "$ref": "#/components/schemas/EdMemberLeftReason" + "$ref": "#/components/schemas/EdMemberLeftReason_OTAyMDA4NzEw" }, "receipt_mode": { "description": "Conversation receipt mode", @@ -2443,7 +2600,7 @@ "type": "string" }, "status": { - "$ref": "#/components/schemas/TypingStatus" + "$ref": "#/components/schemas/TypingStatus_LTg5MzcyNDMy" }, "target": { "$ref": "#/components/schemas/UUID" @@ -2456,7 +2613,7 @@ "type": "string" }, "type": { - "$ref": "#/components/schemas/ConvType" + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" }, "uri": { "$ref": "#/components/schemas/HttpsUrl" @@ -2471,13 +2628,14 @@ }, "users": { "items": { - "$ref": "#/components/schemas/SimpleMember" + "$ref": "#/components/schemas/SimpleMember_NTY5MTcxMzcx" }, "type": "array" } }, "required": [ "users", + "add_type", "reason", "qualified_user_ids", "user_ids", @@ -2486,6 +2644,7 @@ "access", "key", "code", + "uri", "has_password", "qualified_id", "type", @@ -2499,7 +2658,10 @@ "sender", "recipient", "text", - "status" + "status", + "add_permission", + "depth", + "deletion_scheduled_for" ], "type": "object" }, @@ -2507,19 +2669,25 @@ "$ref": "#/components/schemas/UUID" }, "qualified_conversation": { - "$ref": "#/components/schemas/Qualified_ConvId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" }, "qualified_from": { - "$ref": "#/components/schemas/Qualified_UserId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" }, "subconv": { "type": "string" }, + "team": { + "$ref": "#/components/schemas/UUID" + }, "time": { "$ref": "#/components/schemas/UTCTimeMillis" }, "type": { - "$ref": "#/components/schemas/EventType" + "$ref": "#/components/schemas/EventType_LTQ3NTQyNDYz" + }, + "via": { + "$ref": "#/components/schemas/EventVia_Mjc4MzcyNzE0" } }, "required": [ @@ -2527,36 +2695,39 @@ "data", "qualified_conversation", "qualified_from", + "via", "time" ], "type": "object" }, - "EventType": { - "enum": [ - "conversation.member-join", - "conversation.member-leave", - "conversation.member-update", - "conversation.rename", - "conversation.access-update", - "conversation.receipt-mode-update", - "conversation.message-timer-update", - "conversation.code-update", - "conversation.code-delete", - "conversation.create", - "conversation.delete", - "conversation.connect-request", - "conversation.typing", - "conversation.otr-message-add", - "conversation.mls-message-add", - "conversation.mls-welcome", - "conversation.protocol-update" + "Featur_EnfocilDwdLCgBIy_MjcxMzc1NDA5": { + "properties": { + "config": { + "$ref": "#/components/schemas/EnforceFilDwadLtCgB_vIy_LTQ2NjU1Nzcx" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "config" ], - "type": "string" + "type": "object" }, - "ExposeInvitationURLsToTeamAdminConfig.Feature": { + "Featur_SlfDingMsCoBIdy_LTg2MzYzNjc2": { "properties": { + "config": { + "$ref": "#/components/schemas/SelfDeletingMessagesConfigB_Covered_Identity_LTY0NzQ4MzU1" + }, "status": { - "$ref": "#/components/schemas/FeatureStatus" + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, "ttl": { "example": "unlimited", @@ -2566,17 +2737,18 @@ } }, "required": [ - "status" + "status", + "config" ], "type": "object" }, - "ExposeInvitationURLsToTeamAdminConfig.LockableFeature": { + "Featur_Vsiond_16PvAmlGpCfgBIy_MjY0MDMyNDA1V16": { "properties": { - "lockStatus": { - "$ref": "#/components/schemas/LockStatus" + "config": { + "$ref": "#/components/schemas/Versiond_16_PvtAmlGupCfgBaIy_NDc4OTU0NTE3" }, "status": { - "$ref": "#/components/schemas/FeatureStatus" + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, "ttl": { "example": "unlimited", @@ -2587,30 +2759,87 @@ }, "required": [ "status", - "lockStatus" + "config" ], "type": "object" }, - "FeatureStatus": { + "FeatureStatus_LTMzMTUwODEw": { "enum": [ "enabled", "disabled" ], "type": "string" }, - "FederatedUserSearchPolicy": { - "description": "Search policy that was applied when searching for users", - "enum": [ - "no_search", - "exact_handle_search", - "full_search" + "Feature_AppLockConfigB_Bare_Identity_MTAzMjI5NDYy": { + "properties": { + "config": { + "$ref": "#/components/schemas/AppLockConfigB_Covered_Identity_NDIxOTc2Njkz" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "config" ], - "type": "string" + "type": "object" + }, + "Feature_CellsConfigB_Bare_Identity_NzU2NjgxNzEw": { + "properties": { + "config": { + "$ref": "#/components/schemas/CellsConfigB_Covered_Identity_LTE1NzkwOTcz" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "config" + ], + "type": "object" + }, + "Feature_ChannelsConfigB_Bare_Identity_LTU4NTE4MTgx": { + "properties": { + "config": { + "$ref": "#/components/schemas/ChannelsConfigB_Covered_Identity_ODk2MTk3NDQ4" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "config" + ], + "type": "object" }, - "FileSharingConfig.Feature": { + "Feature_ConferenceCallingConfigB_Bare_Identity_Njc2NTcxNTI3": { "properties": { + "config": { + "$ref": "#/components/schemas/ConferenceCallingConfigB_Covered_Identity_NDMwMjcyMzM1" + }, "status": { - "$ref": "#/components/schemas/FeatureStatus" + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, "ttl": { "example": "unlimited", @@ -2624,13 +2853,81 @@ ], "type": "object" }, - "FileSharingConfig.LockableFeature": { + "Feature_ExposeInvitationURLsToTeamAdminConfig_LTY5NzY2Mzg5": { "properties": { - "lockStatus": { - "$ref": "#/components/schemas/LockStatus" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Feature_FileSharingConfig_LTUyNjkxMzM4": { + "properties": { + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Feature_GuestLinksConfig_NjQyMDMxNjg3": { + "properties": { + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Feature_LegalholdConfig_NjM3MTkxNjYw": { + "properties": { + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Feature_MLSConfigB_Bare_Identity_LTI5MjA3MDYy": { + "properties": { + "config": { + "$ref": "#/components/schemas/MLSConfigB_Covered_Identity_LTEzNTk3MzM5" }, "status": { - "$ref": "#/components/schemas/FeatureStatus" + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, "ttl": { "example": "unlimited", @@ -2641,10 +2938,146 @@ }, "required": [ "status", - "lockStatus" + "config" + ], + "type": "object" + }, + "Feature_MeetingsConfig_NDc2MzM0MDE1": { + "properties": { + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Feature_MlsE2EIdConfigB_Bare_Identity_LTUxODYzODEx": { + "properties": { + "config": { + "$ref": "#/components/schemas/MlsE2EIdConfigB_Covered_Identity_NDQ0NjEwNzA3" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "config" + ], + "type": "object" + }, + "Feature_MlsMigrationConfigB_Bare_Identity_LTQyMDAxMTkz": { + "properties": { + "config": { + "$ref": "#/components/schemas/MlsMigrationConfigB_Covered_Identity_LTM3NDQ4Mzg4" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "config" + ], + "type": "object" + }, + "Feature_OutlookCalIntegrationConfig_LTg0MjIxNTMx": { + "properties": { + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Feature_SearchVisibilityAvailableConfig_LTMzNTkxODI1": { + "properties": { + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Feature_SearchVisibilityInboundConfig_MTI1NzQxODY2": { + "properties": { + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Feature_SndFactorPasswordChallengeConfig_NDc0MzUyMzQz": { + "properties": { + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" ], "type": "object" }, + "FederatedUserSearchPolicy_MzkwODA4MTM3": { + "description": "Search policy that was applied when searching for users", + "enum": [ + "no_search", + "exact_handle_search", + "full_search" + ], + "type": "string" + }, "Fingerprint": { "example": "ioy3GeIjgQRsobf2EKGO3O8mq/FofFxHRqy0T4ERIZ8=", "type": "string" @@ -2660,7 +3093,46 @@ }, "type": "object" }, - "GetPaginated_Connections": { + "Frequency_Mzk0ODQwOTM3": { + "enum": [ + "daily", + "weekly", + "monthly", + "yearly" + ], + "type": "string" + }, + "GetByEmailReq_LTY4MzE3Njgy": { + "properties": { + "email": { + "$ref": "#/components/schemas/Email" + } + }, + "required": [ + "email" + ], + "type": "object" + }, + "GetByEmailResp_LTMxNTY3MjA0": { + "properties": { + "sso_code": { + "$ref": "#/components/schemas/UUID" + } + }, + "type": "object" + }, + "GetDomainRegistrationRequest_LTg4NTM1MzM2": { + "properties": { + "email": { + "$ref": "#/components/schemas/Email" + } + }, + "required": [ + "email" + ], + "type": "object" + }, + "GetMuliTabPgRqs_ConcLOrm501_LTIwMjA4NzYw": { "description": "A request to list some or all of a user's Connections, including remote ones", "properties": { "paging_state": { @@ -2676,7 +3148,7 @@ }, "type": "object" }, - "GetPaginated_ConversationIds": { + "GetMuliTabPgRqs_ConvrIdLcOm10_ODU0NjQ1NDMz": { "description": "A request to list some or all of a user's ConversationIds, including remote ones", "properties": { "paging_state": { @@ -2692,6 +3164,21 @@ }, "type": "object" }, + "GroupConvTypeLegacy_NTUxMDI2Mzkw": { + "enum": [ + "group_conversation", + "channel" + ], + "type": "string" + }, + "GroupConvType_LTU4NjU0MTY5": { + "enum": [ + "group_conversation", + "channel", + "meeting" + ], + "type": "string" + }, "GroupId": { "description": "A base64-encoded MLS group ID", "example": "ZXhhbXBsZQo=", @@ -2700,55 +3187,42 @@ "GroupInfoData": { "description": "This object can only be parsed in TLS format. Please refer to the MLS specification for details." }, - "GuestLinksConfig.Feature": { + "Handle": { + "type": "string" + }, + "HandleUpdate_NTI4NDk1OTAx": { "properties": { - "status": { - "$ref": "#/components/schemas/FeatureStatus" - }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "handle": { + "type": "string" } }, "required": [ - "status" + "handle" ], "type": "object" }, - "GuestLinksConfig.LockableFeature": { + "History": { "properties": { - "lockStatus": { - "$ref": "#/components/schemas/LockStatus" - }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" - }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "depth": { + "$ref": "#/components/schemas/HistoryDuration" } }, "required": [ - "status", - "lockStatus" + "depth" ], "type": "object" }, - "Handle": { + "HistoryDuration": { "type": "string" }, - "HandleUpdate": { + "HistorySharingConfig_Mjc4MzA1Nzgw": { "properties": { - "handle": { - "type": "string" + "depth": { + "$ref": "#/components/schemas/HistoryDuration" } }, "required": [ - "handle" + "depth" ], "type": "object" }, @@ -2756,21 +3230,41 @@ "example": "https://example.com", "type": "string" }, - "ID_*_AuthnRequest": { + "HttpsUrl_HttpsUrl_NjUyMDgzNzk3": { "properties": { - "iD": { - "$ref": "#/components/schemas/XmlText" + "config_url": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "webapp_url": { + "$ref": "#/components/schemas/HttpsUrl" } }, "required": [ - "iD" + "config_url", + "webapp_url" + ], + "type": "object" + }, + "HttpsUrl_Maybe_HttpsUrl_LTQ1MDkyMzY2": { + "properties": { + "config_url": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "webapp_url": { + "$ref": "#/components/schemas/HttpsUrl" + } + }, + "required": [ + "config_url" ], "type": "object" }, "Icon": { + "description": "S3 asset key for an icon image with retention information. Allows special value 'default'.", + "example": "3-1-47de4580-ae51-4650-acbb-d10c028cb0ac", "type": "string" }, - "Id": { + "IdObject_ClientId_LTM3NjQyODM5": { "properties": { "id": { "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", @@ -2782,16 +3276,16 @@ ], "type": "object" }, - "IdPConfig_WireIdP": { + "IdPConfig_WireIdP_NDA5MTE4Mjk0": { "properties": { "extraInfo": { - "$ref": "#/components/schemas/WireIdP" + "$ref": "#/components/schemas/WireIdP_ODMzOTExMzYw" }, "id": { - "$ref": "#/components/schemas/UUID" + "$ref": "#/components/schemas/URI" }, "metadata": { - "$ref": "#/components/schemas/IdPMetadata" + "$ref": "#/components/schemas/IdPMetadata_MTI3NzE4MTA0" } }, "required": [ @@ -2805,7 +3299,7 @@ "properties": { "providers": { "items": { - "$ref": "#/components/schemas/IdPConfig_WireIdP" + "$ref": "#/components/schemas/IdPConfig_WireIdP_NDA5MTE4Mjk0" }, "type": "array" } @@ -2815,17 +3309,27 @@ ], "type": "object" }, - "IdPMetadata": { + "IdPMetadataInfo": { + "maxProperties": 1, + "minProperties": 1, + "properties": { + "value": { + "type": "string" + } + }, + "type": "object" + }, + "IdPMetadata_MTI3NzE4MTA0": { "properties": { "certAuthnResponse": { "items": { - "type": "string" + "$ref": "#/components/schemas/SignedCertificate" }, "minItems": 1, "type": "array" }, "issuer": { - "type": "string" + "$ref": "#/components/schemas/URI" }, "requestURI": { "type": "string" @@ -2838,18 +3342,66 @@ ], "type": "object" }, - "IdPMetadataInfo": { - "maxProperties": 1, - "minProperties": 1, + "Id_AuthnRequest": { "properties": { - "value": { + "iD": { + "type": "string" + } + }, + "required": [ + "iD" + ], + "type": "object" + }, + "InvitationList_ODk4NTQxODc3": { + "description": "A list of sent team invitations.", + "properties": { + "has_more": { + "description": "Indicator that the server has more invitations than returned.", + "type": "boolean" + }, + "invitations": { + "items": { + "$ref": "#/components/schemas/Invitation_NTkzMDYwODc1" + }, + "type": "array" + } + }, + "required": [ + "invitations", + "has_more" + ], + "type": "object" + }, + "InvitationRequest_LTcyMDIzNDc0": { + "description": "A request to join a team on Wire.", + "properties": { + "allow_existing": { + "description": "Whether invitations to existing users are allowed.", + "type": "boolean" + }, + "email": { + "$ref": "#/components/schemas/Email" + }, + "locale": { + "$ref": "#/components/schemas/Locale" + }, + "name": { + "description": "Name of the invitee (1 - 128 characters).", + "maxLength": 128, + "minLength": 1, "type": "string" + }, + "role": { + "$ref": "#/components/schemas/Role_LTIzMjAzMjky" } }, + "required": [ + "email" + ], "type": "object" }, - "Invitation": { - "description": "An invitation to join a team on Wire", + "InvitationUserView_LTUyMTE3Nzkz": { "properties": { "created_at": { "$ref": "#/components/schemas/UTCTimeMillis" @@ -2857,12 +3409,18 @@ "created_by": { "$ref": "#/components/schemas/UUID" }, + "created_by_email": { + "$ref": "#/components/schemas/Email" + }, "email": { "$ref": "#/components/schemas/Email" }, "id": { "$ref": "#/components/schemas/UUID" }, + "managed_by": { + "$ref": "#/components/schemas/ManagedBy_NTI0ODc0NTQx" + }, "name": { "description": "Name of the invitee (1 - 128 characters)", "maxLength": 128, @@ -2870,13 +3428,13 @@ "type": "string" }, "role": { - "$ref": "#/components/schemas/Role" + "$ref": "#/components/schemas/Role_LTIzMjAzMjky" }, "team": { "$ref": "#/components/schemas/UUID" }, "url": { - "$ref": "#/components/schemas/URIRef Absolute" + "$ref": "#/components/schemas/URIRef_Absolute" } }, "required": [ @@ -2887,58 +3445,53 @@ ], "type": "object" }, - "InvitationList": { - "description": "A list of sent team invitations.", + "Invitation_NTkzMDYwODc1": { + "description": "An invitation to join a team on Wire. If invitee is invited from an existing personal account, inviter email is included.", "properties": { - "has_more": { - "description": "Indicator that the server has more invitations than returned.", - "type": "boolean" + "created_at": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "created_by": { + "$ref": "#/components/schemas/UUID" }, - "invitations": { - "items": { - "$ref": "#/components/schemas/Invitation" - }, - "type": "array" - } - }, - "required": [ - "invitations", - "has_more" - ], - "type": "object" - }, - "InvitationRequest": { - "description": "A request to join a team on Wire.", - "properties": { "email": { "$ref": "#/components/schemas/Email" }, - "locale": { - "$ref": "#/components/schemas/Locale" + "id": { + "$ref": "#/components/schemas/UUID" }, "name": { - "description": "Name of the invitee (1 - 128 characters).", + "description": "Name of the invitee (1 - 128 characters)", "maxLength": 128, "minLength": 1, "type": "string" }, "role": { - "$ref": "#/components/schemas/Role" + "$ref": "#/components/schemas/Role_LTIzMjAzMjky" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "url": { + "$ref": "#/components/schemas/URIRef_Absolute" } }, "required": [ + "team", + "id", + "created_at", "email" ], "type": "object" }, - "InviteQualified": { + "InviteQualified_ODYyODIyNjYz": { "properties": { "conversation_role": { "$ref": "#/components/schemas/RoleName" }, "qualified_users": { "items": { - "$ref": "#/components/schemas/Qualified_UserId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" }, "minItems": 1, "type": "array" @@ -2949,7 +3502,7 @@ ], "type": "object" }, - "JoinConversationByCode": { + "JoinConversationByCode_NjgzMzM4Mjg5": { "description": "Request body for joining a conversation by code", "properties": { "code": { @@ -2962,9 +3515,6 @@ "maxLength": 1024, "minLength": 8, "type": "string" - }, - "uri": { - "$ref": "#/components/schemas/HttpsUrl" } }, "required": [ @@ -2973,25 +3523,21 @@ ], "type": "object" }, - "KeyPackage": { - "example": "a2V5IHBhY2thZ2UgZGF0YQo=", + "JoinType_LTY4MDg2MzA5": { + "enum": [ + "external_add", + "internal_add" + ], "type": "string" }, - "KeyPackageBundle": { - "properties": { - "key_packages": { - "items": { - "$ref": "#/components/schemas/KeyPackageBundleEntry" - }, - "type": "array" - } - }, - "required": [ - "key_packages" - ], + "KeyMap_Value_MzAxODEwOTgx": { "type": "object" }, - "KeyPackageBundleEntry": { + "KeyPackage": { + "example": "a2V5IHBhY2thZ2UgZGF0YQo=", + "type": "string" + }, + "KeyPackageBundleEntry_NDQ2MzQ2MzMz": { "properties": { "client": { "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", @@ -3019,15 +3565,11 @@ ], "type": "object" }, - "KeyPackageRef": { - "example": "ZXhhbXBsZQo=", - "type": "string" - }, - "KeyPackageUpload": { + "KeyPackageBundle_MjU2MjY0MDU2": { "properties": { "key_packages": { "items": { - "$ref": "#/components/schemas/KeyPackage" + "$ref": "#/components/schemas/KeyPackageBundleEntry_NDQ2MzQ2MzMz" }, "type": "array" } @@ -3037,78 +3579,50 @@ ], "type": "object" }, - "LHServiceStatus": { - "enum": [ - "configured", - "not_configured", - "disabled" - ], - "type": "string" - }, - "LegalholdConfig.Feature": { + "KeyPackageCount_LTYwNDg5MDcz": { "properties": { - "status": { - "$ref": "#/components/schemas/FeatureStatus" - }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, + "count": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, "type": "integer" } }, "required": [ - "status" + "count" ], "type": "object" }, - "LegalholdConfig.LockableFeature": { + "KeyPackageRef": { + "example": "ZXhhbXBsZQo=", + "type": "string" + }, + "KeyPackageUpload_NTQ2Mjk2NzEx": { "properties": { - "lockStatus": { - "$ref": "#/components/schemas/LockStatus" - }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" - }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "key_packages": { + "items": { + "$ref": "#/components/schemas/KeyPackage" + }, + "type": "array" } }, "required": [ - "status", - "lockStatus" + "key_packages" ], "type": "object" }, - "LimitedEventFanoutConfig.LockableFeature": { - "properties": { - "lockStatus": { - "$ref": "#/components/schemas/LockStatus" - }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" - }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" - } - }, - "required": [ - "status", - "lockStatus" + "LHServiceStatus_ODc3NzE0Mjg3": { + "enum": [ + "configured", + "not_configured", + "disabled" ], - "type": "object" + "type": "string" }, "LimitedQualifiedUserIdList_500": { "properties": { "qualified_users": { "items": { - "$ref": "#/components/schemas/Qualified_UserId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" }, "type": "array" } @@ -3118,19 +3632,12 @@ ], "type": "object" }, - "List1": { - "items": { - "$ref": "#/components/schemas/ASCII" - }, - "minItems": 1, - "type": "array" - }, - "ListConversations": { + "ListConversations_MjkxMTIwODMz": { "description": "A request to list some of a user's conversations, including remote ones. Maximum 1000 qualified conversation IDs", "properties": { "qualified_ids": { "items": { - "$ref": "#/components/schemas/Qualified_ConvId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" }, "maxItems": 1000, "minItems": 1, @@ -3142,7 +3649,7 @@ ], "type": "object" }, - "ListType": { + "ListType_LTkyMDM4MzA1": { "description": "true if 'members' doesn't contain all team members", "enum": [ true, @@ -3150,18 +3657,18 @@ ], "type": "boolean" }, - "ListUsersById": { + "ListUsersById_LTQ5MTE3NDc0": { "properties": { "failed": { "items": { - "$ref": "#/components/schemas/Qualified_UserId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" }, "minItems": 1, "type": "array" }, "found": { "items": { - "$ref": "#/components/schemas/UserProfile" + "$ref": "#/components/schemas/UserProfile_LTQzMTQxMTE1" }, "type": "array" } @@ -3184,13 +3691,13 @@ "properties": { "qualified_handles": { "items": { - "$ref": "#/components/schemas/Qualified_Handle" + "$ref": "#/components/schemas/Qualified_Handle_Nzg0MDE3Nzk4" }, "type": "array" }, "qualified_ids": { "items": { - "$ref": "#/components/schemas/Qualified_UserId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" }, "type": "array" } @@ -3200,7 +3707,7 @@ "Locale": { "type": "string" }, - "LocaleUpdate": { + "LocaleUpdate_LTgzNjgyOTEw": { "properties": { "locale": { "$ref": "#/components/schemas/Locale" @@ -3211,82 +3718,112 @@ ], "type": "object" }, - "LockStatus": { + "LockStatus_LTIyMTU5OTkw": { "enum": [ "locked", "unlocked" ], "type": "string" }, - "Login": { + "LockableFeature_AllowedGlobalOperationsConfig_NjQ1MjA5MDYw": { "properties": { - "email": { - "$ref": "#/components/schemas/Email" + "config": { + "$ref": "#/components/schemas/AllowedGlobalOperationsConfig_MzAwOTU1MDkx" }, - "handle": { - "$ref": "#/components/schemas/Handle" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "label": { - "type": "string" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, - "password": { - "maxLength": 1024, - "minLength": 6, - "type": "string" + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus", + "config" + ], + "type": "object" + }, + "LockableFeature_AppLockConfigB_Bare_Identity_ODgzNDI0OTU5": { + "properties": { + "config": { + "$ref": "#/components/schemas/AppLockConfigB_Covered_Identity_NDIxOTc2Njkz" }, - "verification_code": { - "$ref": "#/components/schemas/ASCII" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, "required": [ - "password" + "status", + "lockStatus", + "config" ], "type": "object" }, - "MLSConfig": { + "LockableFeature_AppsConfig_MzQyNTMxNTk5": { "properties": { - "allowedCipherSuites": { - "items": { - "$ref": "#/components/schemas/CipherSuiteTag" - }, - "type": "array" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "defaultCipherSuite": { - "$ref": "#/components/schemas/CipherSuiteTag" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, - "defaultProtocol": { - "$ref": "#/components/schemas/Protocol" + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_AssetAuditLogConfig_NDQ3MzcyMzk2": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "protocolToggleUsers": { - "description": "allowlist of users that may change protocols", - "items": { - "$ref": "#/components/schemas/UUID" - }, - "type": "array" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, - "supportedProtocols": { - "items": { - "$ref": "#/components/schemas/Protocol" - }, - "type": "array" + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, "required": [ - "protocolToggleUsers", - "defaultProtocol", - "allowedCipherSuites", - "defaultCipherSuite", - "supportedProtocols" + "status", + "lockStatus" ], "type": "object" }, - "MLSConfig.Feature": { + "LockableFeature_BackgroundEffectsConfig_MTg1MTk3NTM5": { "properties": { - "config": { - "$ref": "#/components/schemas/MLSConfig" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, "status": { - "$ref": "#/components/schemas/FeatureStatus" + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, "ttl": { "example": "unlimited", @@ -3297,20 +3834,20 @@ }, "required": [ "status", - "config" + "lockStatus" ], "type": "object" }, - "MLSConfig.LockableFeature": { + "LockableFeature_CellsConfigB_Bare_Identity_LTgzMDA1NjI3": { "properties": { "config": { - "$ref": "#/components/schemas/MLSConfig" + "$ref": "#/components/schemas/CellsConfigB_Covered_Identity_LTE1NzkwOTcz" }, "lockStatus": { - "$ref": "#/components/schemas/LockStatus" + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, "status": { - "$ref": "#/components/schemas/FeatureStatus" + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, "ttl": { "example": "unlimited", @@ -3326,273 +3863,210 @@ ], "type": "object" }, - "MLSKeys": { + "LockableFeature_ChannelsConfigB_Bare_Identity_NzA2NDEyMDEw": { "properties": { - "ecdsa_secp256r1_sha256": { - "$ref": "#/components/schemas/SomeKey" + "config": { + "$ref": "#/components/schemas/ChannelsConfigB_Covered_Identity_ODk2MTk3NDQ4" }, - "ecdsa_secp384r1_sha384": { - "$ref": "#/components/schemas/SomeKey" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "ecdsa_secp521r1_sha512": { - "$ref": "#/components/schemas/SomeKey" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, - "ed25519": { - "$ref": "#/components/schemas/SomeKey" + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, "required": [ - "ed25519", - "ecdsa_secp256r1_sha256", - "ecdsa_secp384r1_sha384", - "ecdsa_secp521r1_sha512" + "status", + "lockStatus", + "config" ], "type": "object" }, - "MLSKeysByPurpose": { + "LockableFeature_ChatBubblesConfig_NDgwMTQzNjI2": { "properties": { - "removal": { - "$ref": "#/components/schemas/MLSKeys" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, "required": [ - "removal" + "status", + "lockStatus" ], "type": "object" }, - "MLSMessage": { - "description": "This object can only be parsed in TLS format. Please refer to the MLS specification for details." - }, - "MLSMessageSendingStatus": { + "LockableFeature_ClassifiedDomainsConfig_LTY1ODQwODg1": { "properties": { - "events": { - "description": "A list of events caused by sending the message.", - "items": { - "$ref": "#/components/schemas/Event" - }, - "type": "array" + "config": { + "$ref": "#/components/schemas/ClassifiedDomainsConfig_LTg4MDcwMDg2" }, - "time": { - "$ref": "#/components/schemas/UTCTimeMillis" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, "required": [ - "events", - "time" + "status", + "lockStatus", + "config" ], "type": "object" }, - "MLSOne2OneConversation_MLSPublicKey": { + "LockableFeature_ConsumableNotificationsConfig_MjUxMjczMjM0": { "properties": { - "conversation": { - "$ref": "#/components/schemas/Conversation" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "public_keys": { - "$ref": "#/components/schemas/MLSKeysByPurpose" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, "required": [ - "conversation", - "public_keys" + "status", + "lockStatus" ], "type": "object" }, - "MLSPublicKey": { - "example": "ZXhhbXBsZQo=", - "type": "string" - }, - "MLSPublicKeys": { - "additionalProperties": { - "example": "ZXhhbXBsZQo=", - "type": "string" - }, - "description": "Mapping from signature scheme (tags) to public key data", - "example": { - "ecdsa_secp256r1_sha256": "ZXhhbXBsZQo=", - "ecdsa_secp384r1_sha384": "ZXhhbXBsZQo=", - "ecdsa_secp521r1_sha512": "ZXhhbXBsZQo=", - "ed25519": "ZXhhbXBsZQo=" - }, - "type": "object" - }, - "ManagedBy": { - "enum": [ - "wire", - "scim" - ], - "type": "string" - }, - "Member": { - "description": "The user ID of the requestor", + "LockableFeature_DigitalSignaturesConfig_ODM2MDA2NDU4": { "properties": { - "conversation_role": { - "$ref": "#/components/schemas/RoleName" - }, - "hidden": { - "type": "boolean" - }, - "hidden_ref": { - "type": "string" - }, - "id": { - "$ref": "#/components/schemas/UUID" - }, - "otr_archived": { - "type": "boolean" - }, - "otr_archived_ref": { - "type": "string" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "otr_muted_ref": { - "type": "string" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, - "otr_muted_status": { - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, "type": "integer" - }, - "qualified_id": { - "$ref": "#/components/schemas/Qualified_UserId" - }, - "service": { - "$ref": "#/components/schemas/ServiceRef" - }, - "status": {}, - "status_ref": {}, - "status_time": {} + } }, "required": [ - "qualified_id" + "status", + "lockStatus" ], "type": "object" }, - "MemberUpdate": { + "LockableFeature_DomainRegistrationConfig_NzU0NjczNTE0": { "properties": { - "hidden": { - "type": "boolean" - }, - "hidden_ref": { - "type": "string" - }, - "otr_archived": { - "type": "boolean" - }, - "otr_archived_ref": { - "type": "string" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "otr_muted_ref": { - "type": "string" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, - "otr_muted_status": { - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, "type": "integer" } }, + "required": [ + "status", + "lockStatus" + ], "type": "object" }, - "MemberUpdateData": { + "LockableFeature_FileSharingConfig_MjgwNjIzODEz": { "properties": { - "conversation_role": { - "$ref": "#/components/schemas/RoleName" - }, - "hidden": { - "type": "boolean" - }, - "hidden_ref": { - "type": "string" - }, - "otr_archived": { - "type": "boolean" - }, - "otr_archived_ref": { - "type": "string" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "otr_muted_ref": { - "type": "string" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, - "otr_muted_status": { - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, "type": "integer" - }, - "qualified_target": { - "$ref": "#/components/schemas/Qualified_UserId" - }, - "target": { - "$ref": "#/components/schemas/UUID" } }, "required": [ - "qualified_target" + "status", + "lockStatus" ], "type": "object" }, - "MessageSendingStatus": { - "description": "The Proteus message sending status. It has these fields:\n- `time`: Time of sending message.\n- `missing`: Clients that the message /should/ have been encrypted for, but wasn't.\n- `redundant`: Clients that the message /should not/ have been encrypted for, but was.\n- `deleted`: Clients that were deleted.\n- `failed_to_send`: When message sending fails for some clients but succeeds for others, e.g., because a remote backend is unreachable, this field will contain the list of clients for which the message sending failed. This list should be empty when message sending is not even tried, like when some clients are missing.", + "LockableFeature_GuestLinksConfig_LTcwNjU0NDMw": { "properties": { - "deleted": { - "$ref": "#/components/schemas/QualifiedUserClients" - }, - "failed_to_confirm_clients": { - "$ref": "#/components/schemas/QualifiedUserClients" - }, - "failed_to_send": { - "$ref": "#/components/schemas/QualifiedUserClients" - }, - "missing": { - "$ref": "#/components/schemas/QualifiedUserClients" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "redundant": { - "$ref": "#/components/schemas/QualifiedUserClients" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, - "time": { - "$ref": "#/components/schemas/UTCTimeMillis" + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, "required": [ - "time", - "missing", - "redundant", - "deleted", - "failed_to_send", - "failed_to_confirm_clients" + "status", + "lockStatus" ], "type": "object" }, - "MlsE2EIdConfig": { + "LockableFeature_LegalholdConfig_LTc5MTk5OTIw": { "properties": { - "acmeDiscoveryUrl": { - "$ref": "#/components/schemas/HttpsUrl" - }, - "crlProxy": { - "$ref": "#/components/schemas/HttpsUrl" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "useProxyOnMobile": { - "type": "boolean" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, - "verificationExpiration": { - "description": "When a client first tries to fetch or renew a certificate, they may need to login to an identity provider (IdP) depending on their IdP domain authentication policy. The user may have a grace period during which they can \"snooze\" this login. The duration of this grace period (in seconds) is set in the `verificationDuration` parameter, which is enforced separately by each client. After the grace period has expired, the client will not allow the user to use the application until they have logged to refresh the certificate. The default value is 1 day (86400s). The client enrolls using the Automatic Certificate Management Environment (ACME) protocol. The `acmeDiscoveryUrl` parameter must be set to the HTTPS URL of the ACME server discovery endpoint for this team. It is of the form \"https://acme.{backendDomain}/acme/{provisionerName}/discovery\". For example: `https://acme.example.com/acme/provisioner1/discovery`.", - "maximum": 9223372036854775807, - "minimum": -9223372036854775808, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, "type": "integer" } }, "required": [ - "verificationExpiration" + "status", + "lockStatus" ], "type": "object" }, - "MlsE2EIdConfig.Feature": { + "LockableFeature_LimitedEventFanoutConfig_MTg3ODM0NzU0": { "properties": { - "config": { - "$ref": "#/components/schemas/MlsE2EIdConfig" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, "status": { - "$ref": "#/components/schemas/FeatureStatus" + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, "ttl": { "example": "unlimited", @@ -3603,20 +4077,20 @@ }, "required": [ "status", - "config" + "lockStatus" ], "type": "object" }, - "MlsE2EIdConfig.LockableFeature": { + "LockableFeature_MLSConfigB_Bare_Identity_MTg1MTc0NTEw": { "properties": { "config": { - "$ref": "#/components/schemas/MlsE2EIdConfig" + "$ref": "#/components/schemas/MLSConfigB_Covered_Identity_LTEzNTk3MzM5" }, "lockStatus": { - "$ref": "#/components/schemas/LockStatus" + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, "status": { - "$ref": "#/components/schemas/FeatureStatus" + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, "ttl": { "example": "unlimited", @@ -3632,24 +4106,34 @@ ], "type": "object" }, - "MlsMigration": { + "LockableFeature_MeetingsConfig_LTE0OTQ5Nzcw": { "properties": { - "finaliseRegardlessAfter": { - "$ref": "#/components/schemas/UTCTime" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "startTime": { - "$ref": "#/components/schemas/UTCTime" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, + "required": [ + "status", + "lockStatus" + ], "type": "object" }, - "MlsMigration.Feature": { + "LockableFeature_MeetingsPremiumConfig_NDg1ODEyNTA1": { "properties": { - "config": { - "$ref": "#/components/schemas/MlsMigration" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, "status": { - "$ref": "#/components/schemas/FeatureStatus" + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, "ttl": { "example": "unlimited", @@ -3660,20 +4144,20 @@ }, "required": [ "status", - "config" + "lockStatus" ], "type": "object" }, - "MlsMigration.LockableFeature": { + "LockableFeature_MlsE2EIdConfigB_Bare_Identity_MTU2ODkyMDc4": { "properties": { "config": { - "$ref": "#/components/schemas/MlsMigration" + "$ref": "#/components/schemas/MlsE2EIdConfigB_Covered_Identity_NDQ0NjEwNzA3" }, "lockStatus": { - "$ref": "#/components/schemas/LockStatus" + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, "status": { - "$ref": "#/components/schemas/FeatureStatus" + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, "ttl": { "example": "unlimited", @@ -3689,3096 +4173,10595 @@ ], "type": "object" }, - "NameIDFormat": { - "enum": [ - "NameIDFUnspecified", - "NameIDFEmail", - "NameIDFX509", - "NameIDFWindows", - "NameIDFKerberos", - "NameIDFEntity", - "NameIDFPersistent", - "NameIDFTransient" + "LockableFeature_OutlookCalIntegrationConfig_NjQ0MzMyMzY0": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" ], - "type": "string" + "type": "object" }, - "NameIdPolicy": { + "LockableFeature_SSOConfig_NjcyMjU4MDY2": { "properties": { - "allowCreate": { - "type": "boolean" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "format": { - "$ref": "#/components/schemas/NameIDFormat" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, - "spNameQualifier": { - "$ref": "#/components/schemas/XmlText" + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, "required": [ - "format", - "allowCreate" + "status", + "lockStatus" ], "type": "object" }, - "NewAssetToken": { + "LockableFeature_SearchVisibilityAvailableConfig_LTkxMTA5ODk5": { "properties": { - "token": { - "$ref": "#/components/schemas/ASCII" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, "required": [ - "token" + "status", + "lockStatus" ], "type": "object" }, - "NewClient": { + "LockableFeature_SearchVisibilityInboundConfig_NzA5NzczNTgy": { "properties": { - "capabilities": { - "description": "Hints provided by the client for the backend so it can behave in a backwards-compatible way.", - "items": { - "$ref": "#/components/schemas/ClientCapability" - }, - "type": "array" - }, - "class": { - "$ref": "#/components/schemas/ClientClass" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "cookie": { - "description": "The cookie label, i.e. the label used when logging in.", - "type": "string" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, - "label": { - "type": "string" + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_SndFactorPasswordChallengeConfig_MjQ3NzQ2ODgx": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "lastkey": { - "$ref": "#/components/schemas/Prekey" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, - "mls_public_keys": { - "$ref": "#/components/schemas/MLSPublicKeys" - }, - "model": { - "type": "string" - }, - "password": { - "description": "The password of the authenticated user for verification. Note: Required for registration of the 2nd, 3rd, ... client.", - "maxLength": 1024, - "minLength": 6, - "type": "string" - }, - "prekeys": { - "description": "Prekeys for other clients to establish OTR sessions.", - "items": { - "$ref": "#/components/schemas/Prekey" - }, - "type": "array" + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_StealthUsersConfig_LTE1MTk2NzIz": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "type": { - "$ref": "#/components/schemas/ClientType" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, - "verification_code": { - "$ref": "#/components/schemas/ASCII" + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, "required": [ - "prekeys", - "lastkey", - "type" + "status", + "lockStatus" ], "type": "object" }, - "NewConv": { - "description": "JSON object to create a new conversation. When using 'qualified_users' (preferred), you can omit 'users'", + "LockableFtur_CnfigBIdy_NzY1NDU5MDAy": { "properties": { - "access": { - "items": { - "$ref": "#/components/schemas/Access" - }, - "type": "array" + "config": { + "$ref": "#/components/schemas/ConferenceCallingConfigB_Covered_Identity_NDMwMjcyMzM1" }, - "access_role": { - "items": { - "$ref": "#/components/schemas/AccessRole" - }, - "type": "array" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "conversation_role": { - "$ref": "#/components/schemas/RoleName" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, - "message_timer": { - "description": "Per-conversation message timer", - "format": "int64", - "maximum": 9223372036854775807, - "minimum": -9223372036854775808, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFtur_CsInfigBdy_LTQ3MTU3Mjg0": { + "properties": { + "config": { + "$ref": "#/components/schemas/CellsInternalConfigB_Covered_Identity_LTUzMDkwOTAz" }, - "name": { - "maxLength": 256, - "minLength": 1, - "type": "string" - }, - "protocol": { - "$ref": "#/components/schemas/BaseProtocol" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "qualified_users": { - "description": "List of qualified user IDs (excluding the requestor) to be part of this conversation", - "items": { - "$ref": "#/components/schemas/Qualified_UserId" - }, - "type": "array" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, - "receipt_mode": { - "description": "Conversation receipt mode", - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, "type": "integer" - }, - "team": { - "$ref": "#/components/schemas/ConvTeamInfo" - }, - "users": { - "deprecated": true, - "description": "List of user IDs (excluding the requestor) to be part of this conversation (deprecated)", - "items": { - "$ref": "#/components/schemas/UUID" - }, - "type": "array" } }, + "required": [ + "status", + "lockStatus", + "config" + ], "type": "object" }, - "NewLegalHoldService": { + "LockableFtur_EnfiDwdCgBIy_ODA5OTA5MTQ4": { "properties": { - "auth_token": { - "$ref": "#/components/schemas/ASCII" + "config": { + "$ref": "#/components/schemas/EnforceFilDwadLtCgB_vIy_LTQ2NjU1Nzcx" }, - "base_url": { - "$ref": "#/components/schemas/HttpsUrl" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "public_key": { - "$ref": "#/components/schemas/ServiceKeyPEM" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, "required": [ - "base_url", - "public_key", - "auth_token" + "status", + "lockStatus", + "config" ], "type": "object" }, - "NewPasswordReset": { - "description": "Data to initiate a password reset", + "LockableFtur_ExpsInviURTmAdCfg_LTQzMzU2OTY1": { "properties": { - "email": { - "$ref": "#/components/schemas/Email" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "phone": { - "description": "Email", - "type": "string" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, + "required": [ + "status", + "lockStatus" + ], "type": "object" }, - "NewProvider": { + "LockableFtur_MsignCfBIdy_LTE1NjAxNjU2": { "properties": { - "description": { - "maxLength": 1024, - "minLength": 1, - "type": "string" - }, - "email": { - "$ref": "#/components/schemas/Email" + "config": { + "$ref": "#/components/schemas/MlsMigrationConfigB_Covered_Identity_LTM3NDQ4Mzg4" }, - "name": { - "maxLength": 128, - "minLength": 1, - "type": "string" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "password": { - "maxLength": 1024, - "minLength": 6, - "type": "string" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, - "url": { - "$ref": "#/components/schemas/HttpsUrl" + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, "required": [ - "name", - "email", - "url", - "description" + "status", + "lockStatus", + "config" ], "type": "object" }, - "NewProviderResponse": { + "LockableFtur_PvnAdmisGpCfgBIy_MTQxOTU4Mzgw": { "properties": { - "id": { - "$ref": "#/components/schemas/UUID" + "config": { + "$ref": "#/components/schemas/PreventAdminlessGroupsConfigB_Covered_Identity_MjQ2NDYwMTk2" }, - "password": { - "maxLength": 1024, - "minLength": 8, - "type": "string" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, "required": [ - "id" + "status", + "lockStatus", + "config" ], "type": "object" }, - "NewService": { + "LockableFtur_RqiExnmVfCg_NjUyMzgzNzY5": { "properties": { - "assets": { - "items": { - "$ref": "#/components/schemas/UserAsset" - }, - "type": "array" - }, - "auth_token": { - "$ref": "#/components/schemas/ASCII" - }, - "base_url": { - "$ref": "#/components/schemas/HttpsUrl" - }, - "description": { - "maxLength": 1024, - "minLength": 1, - "type": "string" - }, - "name": { - "maxLength": 128, - "minLength": 1, - "type": "string" - }, - "public_key": { - "$ref": "#/components/schemas/ServiceKeyPEM" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" }, - "summary": { - "maxLength": 128, - "minLength": 1, - "type": "string" + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" }, - "tags": { - "items": { - "$ref": "#/components/schemas/" - }, - "maxItems": 3, - "minItems": 1, - "type": "array" + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, "required": [ - "name", - "summary", - "description", - "base_url", - "public_key", - "assets", - "tags" + "status", + "lockStatus" ], "type": "object" }, - "NewServiceResponse": { + "LockableFtur_SfDingMsCBIdy_LTg5MTEwNTA2": { "properties": { - "auth_token": { - "$ref": "#/components/schemas/ASCII" + "config": { + "$ref": "#/components/schemas/SelfDeletingMessagesConfigB_Covered_Identity_LTY0NzQ4MzU1" }, - "id": { - "$ref": "#/components/schemas/UUID" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, "required": [ - "id" + "status", + "lockStatus", + "config" ], "type": "object" }, - "NewTeamMember": { - "description": "Required data when creating new team members", + "LockableFtur_SimpfdUsCnRqQg_Njk5NjU4OTgy": { "properties": { - "member": { - "description": "the team member to add (the legalhold_status field must be null or missing!)", - "properties": { - "created_at": { - "$ref": "#/components/schemas/UTCTimeMillis" - }, - "created_by": { - "$ref": "#/components/schemas/UUID" - }, - "permissions": { - "$ref": "#/components/schemas/Permissions" - }, - "user": { - "$ref": "#/components/schemas/UUID" - } - }, - "required": [ - "user", - "permissions" - ], - "type": "object" + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, "required": [ - "member" + "status", + "lockStatus" ], "type": "object" }, - "NewUser": { + "Login_LTgyNTIzMTM1": { "properties": { - "accent_id": { - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer" - }, - "assets": { - "items": { - "$ref": "#/components/schemas/UserAsset" - }, - "type": "array" - }, "email": { "$ref": "#/components/schemas/Email" }, - "email_code": { - "$ref": "#/components/schemas/ASCII" - }, - "expires_in": { - "maximum": 604800, - "minimum": 1, - "type": "integer" - }, - "invitation_code": { - "$ref": "#/components/schemas/ASCII" + "handle": { + "$ref": "#/components/schemas/Handle" }, "label": { "type": "string" }, - "locale": { - "$ref": "#/components/schemas/Locale" - }, - "managed_by": { - "$ref": "#/components/schemas/ManagedBy" - }, - "name": { - "maxLength": 128, - "minLength": 1, - "type": "string" - }, "password": { "maxLength": 1024, - "minLength": 8, + "minLength": 6, "type": "string" }, - "picture": { - "$ref": "#/components/schemas/Pict" - }, - "sso_id": { - "$ref": "#/components/schemas/UserSSOId" - }, - "supported_protocols": { - "items": { - "$ref": "#/components/schemas/BaseProtocol" - }, - "type": "array" - }, - "team": { - "$ref": "#/components/schemas/BindingNewTeamUser" - }, - "team_code": { + "verification_code": { "$ref": "#/components/schemas/ASCII" - }, - "team_id": { - "$ref": "#/components/schemas/UUID" - }, - "uuid": { - "$ref": "#/components/schemas/UUID" } }, "required": [ - "name" + "password" ], "type": "object" }, - "OAuthAccessTokenRequest": { + "MLSConfigB_Covered_Identity_LTEzNTk3MzM5": { + "description": "allowlist of users that may change protocols", "properties": { - "client_id": { - "$ref": "#/components/schemas/UUID" + "allowedCipherSuites": { + "items": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "type": "array" }, - "code": { - "$ref": "#/components/schemas/OAuthAuthorizationCode" + "defaultCipherSuite": { + "$ref": "#/components/schemas/CipherSuiteTag" }, - "code_verifier": { - "description": "The code verifier to complete the code challenge", - "maxLength": 128, - "minLength": 43, - "type": "string" + "defaultProtocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" }, - "grant_type": { - "$ref": "#/components/schemas/OAuthGrantType" + "groupInfoDiagnostics": { + "type": "boolean" }, - "redirect_uri": { - "$ref": "#/components/schemas/RedirectUrl" + "protocolToggleUsers": { + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + }, + "supportedProtocols": { + "items": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "type": "array" } }, "required": [ - "grant_type", - "client_id", - "code_verifier", - "code", - "redirect_uri" + "protocolToggleUsers", + "defaultProtocol", + "allowedCipherSuites", + "defaultCipherSuite", + "supportedProtocols" ], "type": "object" }, - "OAuthAccessTokenResponse": { + "MLSKeysByPurpose_MLSKeys_SomeKey_NjkxMjk0MTAx": { "properties": { - "access_token": { - "description": "The access token, which has a relatively short lifetime", - "type": "string" - }, - "expires_in": { - "description": "The lifetime of the access token in seconds", - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer" - }, - "refresh_token": { - "description": "The refresh token, which has a relatively long lifetime, and can be used to obtain a new access token", - "type": "string" - }, - "token_type": { - "$ref": "#/components/schemas/OAuthAccessTokenType" + "removal": { + "$ref": "#/components/schemas/MLSKeys_SomeKey_LTUzNDA5MzA3" } }, "required": [ - "access_token", - "token_type", - "expires_in", - "refresh_token" + "removal" ], "type": "object" }, - "OAuthAccessTokenType": { - "description": "The type of the access token. Currently only `Bearer` is supported.", - "enum": [ - "Bearer" - ], - "type": "string" - }, - "OAuthApplication": { + "MLSKeys_SomeKey_LTUzNDA5MzA3": { "properties": { - "id": { - "$ref": "#/components/schemas/UUID" + "ecdsa_secp256r1_sha256": { + "$ref": "#/components/schemas/SomeKey" }, - "name": { - "description": "The OAuth client's name", - "maxLength": 256, - "minLength": 6, - "type": "string" + "ecdsa_secp384r1_sha384": { + "$ref": "#/components/schemas/SomeKey" }, - "sessions": { - "description": "The OAuth client's sessions", - "items": { - "$ref": "#/components/schemas/OAuthSession" - }, - "type": "array" + "ecdsa_secp521r1_sha512": { + "$ref": "#/components/schemas/SomeKey" + }, + "ed25519": { + "$ref": "#/components/schemas/SomeKey" } }, "required": [ - "id", - "name", - "sessions" + "ed25519", + "ecdsa_secp256r1_sha256", + "ecdsa_secp384r1_sha384", + "ecdsa_secp521r1_sha512" ], "type": "object" }, - "OAuthAuthorizationCode": { - "description": "The authorization code", - "type": "string" + "MLSMessage": { + "description": "This object can only be parsed in TLS format. Please refer to the MLS specification for details." }, - "OAuthClient": { + "MLSMessageSendingStatus_NjA1NDA0MTE4": { "properties": { - "application_name": { - "maxLength": 256, - "minLength": 6, - "type": "string" - }, - "client_id": { - "$ref": "#/components/schemas/UUID" + "events": { + "description": "A list of events caused by sending the message.", + "items": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + }, + "type": "array" }, - "redirect_url": { - "$ref": "#/components/schemas/RedirectUrl" + "time": { + "$ref": "#/components/schemas/UTCTimeMillis" } }, "required": [ - "client_id", - "application_name", - "redirect_url" + "events", + "time" ], "type": "object" }, - "OAuthCodeChallenge": { - "description": "Generated by the client from the code verifier (unpadded base64url-encoded SHA256 hash of the code verifier)", - "type": "string" - }, - "OAuthGrantType": { - "description": "Indicates which authorization flow to use. Use `authorization_code` for authorization code flow.", - "enum": [ - "authorization_code", - "refresh_token" - ], - "type": "string" - }, - "OAuthRefreshAccessTokenRequest": { + "MLSOne2OneConversation_SomeKey_GroupConvType_LTg2MTcwMjY3": { "properties": { - "client_id": { - "$ref": "#/components/schemas/UUID" - }, - "grant_type": { - "$ref": "#/components/schemas/OAuthGrantType" + "conversation": { + "$ref": "#/components/schemas/v9_OwnConversation_GroupConvType_LTU2MzYxNTg0" }, - "refresh_token": { - "description": "The refresh token", - "type": "string" + "public_keys": { + "$ref": "#/components/schemas/MLSKeysByPurpose_MLSKeys_SomeKey_NjkxMjk0MTAx" } }, "required": [ - "grant_type", - "client_id", - "refresh_token" + "conversation", + "public_keys" ], "type": "object" }, - "OAuthResponseType": { - "description": "Indicates which authorization flow to use. Use `code` for authorization code flow.", + "MLSPublicKeys": { + "additionalProperties": { + "example": "ZXhhbXBsZQo=", + "type": "string" + }, + "description": "Mapping from signature scheme (tags) to public key data", + "example": { + "ecdsa_secp256r1_sha256": "ZXhhbXBsZQo=", + "ecdsa_secp384r1_sha384": "ZXhhbXBsZQo=", + "ecdsa_secp521r1_sha512": "ZXhhbXBsZQo=", + "ed25519": "ZXhhbXBsZQo=" + }, + "type": "object" + }, + "MLSReset_NzgwODA3ODc4": { + "properties": { + "epoch": { + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + } + }, + "required": [ + "group_id", + "epoch" + ], + "type": "object" + }, + "MTYxOTI3NjM3": { "enum": [ - "code" + "image" + ], + "type": "string" + }, + "ManagedBy_NTI0ODc0NTQx": { + "enum": [ + "wire", + "scim" ], "type": "string" }, - "OAuthRevokeRefreshTokenRequest": { + "MeetingEmailsInvitation_NzgyNzUzMzcz": { + "description": "Emails invitation", "properties": { - "client_id": { - "$ref": "#/components/schemas/UUID" - }, - "refresh_token": { - "description": "The refresh token", - "type": "string" + "emails": { + "items": { + "$ref": "#/components/schemas/Email" + }, + "type": "array" } }, "required": [ - "client_id", - "refresh_token" + "emails" ], "type": "object" }, - "OAuthSession": { + "MeetingWithConversation_LTMyNzA4NzU0": { + "description": "A scheduled meeting with its associated conversation", "properties": { + "conversation": { + "$ref": "#/components/schemas/Conversation_GroupConvType_MzQzMTQ1OTg3" + }, "created_at": { - "$ref": "#/components/schemas/UTCTimeMillis" + "$ref": "#/components/schemas/UTCTime" }, - "refresh_token_id": { - "$ref": "#/components/schemas/UUID" + "end_time": { + "$ref": "#/components/schemas/UTCTime" + }, + "invited_emails": { + "items": { + "$ref": "#/components/schemas/Email" + }, + "type": "array" + }, + "qualified_conversation": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "qualified_creator": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Meeting_MjgxMDUyNjc3" + }, + "recurrence": { + "$ref": "#/components/schemas/Recurrence_LTQ0OTc0ODE2" + }, + "start_time": { + "$ref": "#/components/schemas/UTCTime" + }, + "title": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "tzid": { + "$ref": "#/components/schemas/TimeZone" + }, + "updated_at": { + "$ref": "#/components/schemas/UTCTime" } }, "required": [ - "refresh_token_id", - "created_at" + "qualified_id", + "title", + "qualified_creator", + "start_time", + "end_time", + "tzid", + "qualified_conversation", + "invited_emails", + "created_at", + "updated_at", + "conversation" ], "type": "object" }, - "Object": { - "additionalProperties": true, - "description": "A single notification event", + "Meeting_ODU0OTMzMTgw": { + "description": "A scheduled meeting", "properties": { - "type": { - "description": "Event type", + "created_at": { + "$ref": "#/components/schemas/UTCTime" + }, + "end_time": { + "$ref": "#/components/schemas/UTCTime" + }, + "invited_emails": { + "items": { + "$ref": "#/components/schemas/Email" + }, + "type": "array" + }, + "qualified_conversation": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "qualified_creator": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Meeting_MjgxMDUyNjc3" + }, + "recurrence": { + "$ref": "#/components/schemas/Recurrence_LTQ0OTc0ODE2" + }, + "start_time": { + "$ref": "#/components/schemas/UTCTime" + }, + "title": { + "maxLength": 256, + "minLength": 1, "type": "string" + }, + "tzid": { + "$ref": "#/components/schemas/TimeZone" + }, + "updated_at": { + "$ref": "#/components/schemas/UTCTime" } }, - "title": "Event", + "required": [ + "qualified_id", + "title", + "qualified_creator", + "start_time", + "end_time", + "tzid", + "qualified_conversation", + "invited_emails", + "created_at", + "updated_at" + ], "type": "object" }, - "OtherMember": { + "MemberUpdateData_LTc3Nzc3NTEy": { "properties": { "conversation_role": { "$ref": "#/components/schemas/RoleName" }, - "id": { - "$ref": "#/components/schemas/UUID" + "hidden": { + "type": "boolean" }, - "qualified_id": { - "$ref": "#/components/schemas/Qualified_UserId" + "hidden_ref": { + "type": "string" }, - "service": { - "$ref": "#/components/schemas/ServiceRef" + "otr_archived": { + "type": "boolean" }, - "status": { - "deprecated": true, - "description": "deprecated", - "maximum": 9223372036854775807, - "minimum": -9223372036854775808, + "otr_archived_ref": { + "type": "string" + }, + "otr_muted_ref": { + "type": "string" + }, + "otr_muted_status": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, "type": "integer" + }, + "qualified_target": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "target": { + "$ref": "#/components/schemas/UUID" } }, "required": [ - "qualified_id" + "qualified_target" ], "type": "object" }, - "OtherMemberUpdate": { - "description": "Update user properties of other members relative to a conversation", + "MemberUpdate_LTg4NTQ0OTYz": { "properties": { - "conversation_role": { - "$ref": "#/components/schemas/RoleName" + "hidden": { + "type": "boolean" + }, + "hidden_ref": { + "type": "string" + }, + "otr_archived": { + "type": "boolean" + }, + "otr_archived_ref": { + "type": "string" + }, + "otr_muted_ref": { + "type": "string" + }, + "otr_muted_status": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" } }, "type": "object" }, - "OtrMessage": { - "description": "Encrypted message of a conversation", + "Member_OTA5OTgyNzcw": { + "description": "The user ID of the requestor if the requestor is a member of the conversation", "properties": { - "data": { - "description": "Extra (symmetric) data (i.e. ciphertext, Base64 in JSON) that is common with all other recipients.", - "type": "string" + "conversation_role": { + "$ref": "#/components/schemas/RoleName" }, - "recipient": { - "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "hidden": { + "type": "boolean" + }, + "hidden_ref": { "type": "string" }, - "sender": { - "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "id": { + "$ref": "#/components/schemas/UUID" + }, + "otr_archived": { + "type": "boolean" + }, + "otr_archived_ref": { "type": "string" }, - "text": { - "description": "The ciphertext for the recipient (Base64 in JSON)", + "otr_muted_ref": { "type": "string" - } + }, + "otr_muted_status": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "service": { + "$ref": "#/components/schemas/ServiceRef_LTgxMjY3NzAz" + }, + "status": {}, + "status_ref": {}, + "status_time": {} }, "required": [ - "sender", - "recipient", - "text" + "qualified_id" ], "type": "object" }, - "OutlookCalIntegrationConfig.Feature": { + "MembersJoin_LTg0MDc1NjQ3": { "properties": { - "status": { - "$ref": "#/components/schemas/FeatureStatus" + "add_type": { + "$ref": "#/components/schemas/JoinType_LTY4MDg2MzA5" }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "user_ids": { + "deprecated": true, + "description": "deprecated", + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + }, + "users": { + "items": { + "$ref": "#/components/schemas/SimpleMember_NTY5MTcxMzcx" + }, + "type": "array" } }, "required": [ - "status" + "users", + "add_type" ], "type": "object" }, - "OutlookCalIntegrationConfig.LockableFeature": { + "MessageSendingStatus_ODg0NDgyNDk4": { + "description": "The Proteus message sending status. It has these fields:\n- `time`: Time of sending message.\n- `missing`: Clients that the message /should/ have been encrypted for, but wasn't.\n- `redundant`: Clients that the message /should not/ have been encrypted for, but was.\n- `deleted`: Clients that were deleted.\n- `failed_to_send`: When message sending fails for some clients but succeeds for others, e.g., because a remote backend is unreachable, this field will contain the list of clients for which the message sending failed. This list should be empty when message sending is not even tried, like when some clients are missing.", "properties": { - "lockStatus": { - "$ref": "#/components/schemas/LockStatus" + "deleted": { + "$ref": "#/components/schemas/QualifiedUserClients" }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" + "failed_to_confirm_clients": { + "$ref": "#/components/schemas/QualifiedUserClients" }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "failed_to_send": { + "$ref": "#/components/schemas/QualifiedUserClients" + }, + "missing": { + "$ref": "#/components/schemas/QualifiedUserClients" + }, + "redundant": { + "$ref": "#/components/schemas/QualifiedUserClients" + }, + "time": { + "$ref": "#/components/schemas/UTCTimeMillis" } }, "required": [ - "status", - "lockStatus" + "time", + "missing", + "redundant", + "deleted", + "failed_to_send", + "failed_to_confirm_clients" ], "type": "object" }, - "OwnKeyPackages": { + "MlsE2EIdConfigB_Covered_Identity_NDQ0NjEwNzA3": { + "description": "When a client first tries to fetch or renew a certificate, they may need to login to an identity provider (IdP) depending on their IdP domain authentication policy. The user may have a grace period during which they can \"snooze\" this login. The duration of this grace period (in seconds) is set in the `verificationDuration` parameter, which is enforced separately by each client. After the grace period has expired, the client will not allow the user to use the application until they have logged to refresh the certificate. The default value is 1 day (86400s). The client enrolls using the Automatic Certificate Management Environment (ACME) protocol. The `acmeDiscoveryUrl` parameter must be set to the HTTPS URL of the ACME server discovery endpoint for this team. It is of the form \"https://acme.{backendDomain}/acme/{provisionerName}/discovery\". For example: `https://acme.example.com/acme/provisioner1/discovery`.", "properties": { - "count": { + "acmeDiscoveryUrl": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "crlProxy": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "useProxyOnMobile": { + "type": "boolean" + }, + "verificationExpiration": { "maximum": 9223372036854775807, "minimum": -9223372036854775808, "type": "integer" } }, "required": [ - "count" + "verificationExpiration" ], "type": "object" }, - "PagingState": { - "description": "Paging state that should be supplied to retrieve the next page of results", - "type": "string" - }, - "PasswordChange": { + "MlsMigrationConfigB_Covered_Identity_LTM3NDQ4Mzg4": { "properties": { - "new_password": { - "maxLength": 1024, - "minLength": 6, + "allowManualMigration": { + "type": "boolean" + }, + "finaliseRegardlessAfter": { + "example": "2021-05-12T10:52:02Z", + "format": "yyyy-mm-ddThh:MM:ssZ", "type": "string" }, - "old_password": { - "maxLength": 1024, - "minLength": 6, + "startTime": { + "example": "2021-05-12T10:52:02Z", + "format": "yyyy-mm-ddThh:MM:ssZ", "type": "string" } }, - "required": [ - "old_password", - "new_password" - ], "type": "object" }, - "PasswordReqBody": { + "MultiTabePg_ConcsLOrRmU_MTgwMzU4OTU5": { "properties": { - "password": { - "maxLength": 1024, - "minLength": 6, - "type": "string" + "connections": { + "items": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + }, + "type": "array" + }, + "has_more": { + "type": "boolean" + }, + "paging_state": { + "$ref": "#/components/schemas/Connections_PagingState" } }, + "required": [ + "connections", + "has_more", + "paging_state" + ], "type": "object" }, - "PasswordReset": { + "MultiTabePg_ConvrsIdqf_cLORm_Q_Mzg0MjYzNzM0": { "properties": { - "email": { - "$ref": "#/components/schemas/Email" + "has_more": { + "type": "boolean" + }, + "paging_state": { + "$ref": "#/components/schemas/ConversationIds_PagingState" + }, + "qualified_conversations": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "type": "array" } }, "required": [ - "email" + "qualified_conversations", + "has_more", + "paging_state" ], "type": "object" }, - "Permissions": { - "description": "This is just a complicated way of representing a team role. self and copy always have to contain the same integer, and only the following integers are allowed: 1025 (partner), 1587 (member), 5951 (admin), 8191 (owner). Unit tests of the galley-types package in wire-server contain an authoritative list.", + "NP_LockableFtur_ghdCnfiSOVsyAvIRqExmDpB_MGwUT2Q_LTM1Mzc0ODgy": { "properties": { - "copy": { - "format": "int64", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "allowedGlobalOperations": { + "$ref": "#/components/schemas/LockableFeature_AllowedGlobalOperationsConfig_NjQ1MjA5MDYw" }, - "self": { - "format": "int64", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "appLock": { + "$ref": "#/components/schemas/LockableFeature_AppLockConfigB_Bare_Identity_ODgzNDI0OTU5" + }, + "apps": { + "$ref": "#/components/schemas/LockableFeature_AppsConfig_MzQyNTMxNTk5" + }, + "assetAuditLog": { + "$ref": "#/components/schemas/LockableFeature_AssetAuditLogConfig_NDQ3MzcyMzk2" + }, + "backgroundEffects": { + "$ref": "#/components/schemas/LockableFeature_BackgroundEffectsConfig_MTg1MTk3NTM5" + }, + "cells": { + "$ref": "#/components/schemas/LockableFeature_CellsConfigB_Bare_Identity_LTgzMDA1NjI3" + }, + "cellsInternal": { + "$ref": "#/components/schemas/LockableFtur_CsInfigBdy_LTQ3MTU3Mjg0" + }, + "channels": { + "$ref": "#/components/schemas/LockableFeature_ChannelsConfigB_Bare_Identity_NzA2NDEyMDEw" + }, + "chatBubbles": { + "$ref": "#/components/schemas/LockableFeature_ChatBubblesConfig_NDgwMTQzNjI2" + }, + "classifiedDomains": { + "$ref": "#/components/schemas/LockableFeature_ClassifiedDomainsConfig_LTY1ODQwODg1" + }, + "conferenceCalling": { + "$ref": "#/components/schemas/LockableFtur_CnfigBIdy_NzY1NDU5MDAy" + }, + "consumableNotifications": { + "$ref": "#/components/schemas/LockableFeature_ConsumableNotificationsConfig_MjUxMjczMjM0" + }, + "conversationGuestLinks": { + "$ref": "#/components/schemas/LockableFeature_GuestLinksConfig_LTcwNjU0NDMw" + }, + "digitalSignatures": { + "$ref": "#/components/schemas/LockableFeature_DigitalSignaturesConfig_ODM2MDA2NDU4" + }, + "domainRegistration": { + "$ref": "#/components/schemas/LockableFeature_DomainRegistrationConfig_NzU0NjczNTE0" + }, + "enforceFileDownloadLocation": { + "$ref": "#/components/schemas/LockableFtur_EnfiDwdCgBIy_ODA5OTA5MTQ4" + }, + "exposeInvitationURLsToTeamAdmin": { + "$ref": "#/components/schemas/LockableFtur_ExpsInviURTmAdCfg_LTQzMzU2OTY1" + }, + "fileSharing": { + "$ref": "#/components/schemas/LockableFeature_FileSharingConfig_MjgwNjIzODEz" + }, + "legalhold": { + "$ref": "#/components/schemas/LockableFeature_LegalholdConfig_LTc5MTk5OTIw" + }, + "limitedEventFanout": { + "$ref": "#/components/schemas/LockableFeature_LimitedEventFanoutConfig_MTg3ODM0NzU0" + }, + "meetings": { + "$ref": "#/components/schemas/LockableFeature_MeetingsConfig_LTE0OTQ5Nzcw" + }, + "meetingsPremium": { + "$ref": "#/components/schemas/LockableFeature_MeetingsPremiumConfig_NDg1ODEyNTA1" + }, + "mls": { + "$ref": "#/components/schemas/LockableFeature_MLSConfigB_Bare_Identity_MTg1MTc0NTEw" + }, + "mlsE2EId": { + "$ref": "#/components/schemas/LockableFeature_MlsE2EIdConfigB_Bare_Identity_MTU2ODkyMDc4" + }, + "mlsMigration": { + "$ref": "#/components/schemas/LockableFtur_MsignCfBIdy_LTE1NjAxNjU2" + }, + "outlookCalIntegration": { + "$ref": "#/components/schemas/LockableFeature_OutlookCalIntegrationConfig_NjQ0MzMyMzY0" + }, + "preventAdminlessGroups": { + "$ref": "#/components/schemas/LockableFtur_PvnAdmisGpCfgBIy_MTQxOTU4Mzgw" + }, + "searchVisibility": { + "$ref": "#/components/schemas/LockableFeature_SearchVisibilityAvailableConfig_LTkxMTA5ODk5" + }, + "searchVisibilityInbound": { + "$ref": "#/components/schemas/LockableFeature_SearchVisibilityInboundConfig_NzA5NzczNTgy" + }, + "selfDeletingMessages": { + "$ref": "#/components/schemas/LockableFtur_SfDingMsCBIdy_LTg5MTEwNTA2" + }, + "simplifiedUserConnectionRequestQRCode": { + "$ref": "#/components/schemas/LockableFtur_SimpfdUsCnRqQg_Njk5NjU4OTgy" + }, + "sndFactorPasswordChallenge": { + "$ref": "#/components/schemas/LockableFeature_SndFactorPasswordChallengeConfig_MjQ3NzQ2ODgx" + }, + "sso": { + "$ref": "#/components/schemas/LockableFeature_SSOConfig_NjcyMjU4MDY2" + }, + "stealthUsers": { + "$ref": "#/components/schemas/LockableFeature_StealthUsersConfig_LTE1MTk2NzIz" + }, + "validateSAMLemails": { + "$ref": "#/components/schemas/LockableFtur_RqiExnmVfCg_NjUyMzgzNzY5" } }, "required": [ - "self", - "copy" + "legalhold", + "sso", + "searchVisibility", + "searchVisibilityInbound", + "validateSAMLemails", + "digitalSignatures", + "appLock", + "fileSharing", + "classifiedDomains", + "conferenceCalling", + "selfDeletingMessages", + "conversationGuestLinks", + "sndFactorPasswordChallenge", + "mls", + "exposeInvitationURLsToTeamAdmin", + "outlookCalIntegration", + "mlsE2EId", + "mlsMigration", + "enforceFileDownloadLocation", + "limitedEventFanout", + "domainRegistration", + "channels", + "preventAdminlessGroups", + "cells", + "allowedGlobalOperations", + "consumableNotifications", + "chatBubbles", + "apps", + "simplifiedUserConnectionRequestQRCode", + "assetAuditLog", + "stealthUsers", + "cellsInternal", + "meetings", + "meetingsPremium", + "backgroundEffects" ], "type": "object" }, - "PhoneNumber": { - "description": "A known phone number with a pending password reset.", + "NameIDFormat": { + "enum": [ + "NameIDFUnspecified", + "NameIDFEmail", + "NameIDFX509", + "NameIDFWindows", + "NameIDFKerberos", + "NameIDFEntity", + "NameIDFPersistent", + "NameIDFTransient" + ], "type": "string" }, - "Pict": { - "items": { - "type": "object" - }, - "maxItems": 10, - "minItems": 0, - "type": "array" - }, - "Prekey": { + "NameIdPolicy": { "properties": { - "id": { - "maximum": 65535, - "minimum": 0, - "type": "integer" + "allowCreate": { + "type": "boolean" }, - "key": { + "format": { + "$ref": "#/components/schemas/NameIDFormat" + }, + "spNameQualifier": { "type": "string" } }, "required": [ - "id", - "key" + "format", + "allowCreate" ], "type": "object" }, - "PrekeyBundle": { + "NewApp_LTQwODMwMzQ4": { "properties": { - "clients": { + "accent_id": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "assets": { "items": { - "$ref": "#/components/schemas/ClientPrekey" + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" }, "type": "array" }, - "user": { - "$ref": "#/components/schemas/UUID" + "category": { + "description": "Category name (if uncertain, pick \"other\")", + "type": "string" + }, + "description": { + "maxLength": 300, + "minLength": 0, + "type": "string" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" } }, "required": [ - "user", - "clients" - ], - "type": "object" - }, - "Priority": { - "enum": [ - "low", - "high" + "name", + "category", + "description", + "password" ], - "type": "string" - }, - "PropertyKeysAndValues": { "type": "object" }, - "PropertyValue": { - "description": "An arbitrary JSON value for a property" - }, - "Protocol": { - "enum": [ - "proteus", - "mls", - "mixed" - ], - "type": "string" - }, - "ProtocolUpdate": { + "NewAssetToken_NTAwMDQwODYy": { "properties": { - "protocol": { - "$ref": "#/components/schemas/Protocol" + "token": { + "$ref": "#/components/schemas/ASCII" } }, + "required": [ + "token" + ], "type": "object" }, - "Provider": { + "NewClient_ODg1NjY4Njgy": { "properties": { - "description": { - "type": "string" + "capabilities": { + "$ref": "#/components/schemas/ClientCapabilityList" }, - "email": { - "$ref": "#/components/schemas/Email" + "class": { + "$ref": "#/components/schemas/ClientClass_NjE3MDgwNzcx" }, - "id": { - "$ref": "#/components/schemas/UUID" + "cookie": { + "description": "The cookie label, i.e. the label used when logging in.", + "type": "string" }, - "name": { - "maxLength": 128, - "minLength": 1, + "label": { "type": "string" }, - "url": { - "$ref": "#/components/schemas/HttpsUrl" - } - }, - "required": [ - "id", - "name", - "email", - "url", - "description" - ], - "type": "object" - }, - "ProviderActivationResponse": { - "properties": { - "email": { - "$ref": "#/components/schemas/Email" - } - }, - "required": [ - "email" - ], - "type": "object" - }, - "ProviderLogin": { - "properties": { - "email": { - "$ref": "#/components/schemas/Email" + "lastkey": { + "$ref": "#/components/schemas/UncheckedPrekeyBundle_LTU1MzQzOTgy" + }, + "mls_public_keys": { + "$ref": "#/components/schemas/MLSPublicKeys" + }, + "model": { + "type": "string" }, "password": { + "description": "The password of the authenticated user for verification. Note: Required for registration of the 2nd, 3rd, ... client.", "maxLength": 1024, "minLength": 6, "type": "string" - } - }, - "required": [ - "email", - "password" - ], - "type": "object" - }, - "PubClient": { - "properties": { - "class": { - "$ref": "#/components/schemas/ClientClass" }, - "id": { - "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", - "type": "string" + "prekeys": { + "description": "Prekeys for other clients to establish OTR sessions.", + "items": { + "$ref": "#/components/schemas/UncheckedPrekeyBundle_LTU1MzQzOTgy" + }, + "type": "array" + }, + "type": { + "$ref": "#/components/schemas/ClientType_MjQ0OTQwMzcw" + }, + "verification_code": { + "$ref": "#/components/schemas/ASCII" } }, "required": [ - "id" + "prekeys", + "lastkey", + "type" ], "type": "object" }, - "PublicSubConversation": { - "description": "An MLS subconversation", + "NewConv_LTgzNTk1NDQx": { + "description": "JSON object to create a new conversation. When using 'qualified_users' (preferred), you can omit 'users'", "properties": { - "cipher_suite": { - "$ref": "#/components/schemas/CipherSuiteTag" + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" }, - "epoch": { - "description": "The epoch number of the corresponding MLS group", + "access_role": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "cells": { + "type": "boolean" + }, + "conversation_role": { + "$ref": "#/components/schemas/RoleName" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" + }, + "history": { + "$ref": "#/components/schemas/History" + }, + "message_timer": { + "description": "Per-conversation message timer", "format": "int64", - "maximum": 18446744073709551615, - "minimum": 0, + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, "type": "integer" }, - "epoch_timestamp": { - "$ref": "#/components/schemas/UTCTime" + "name": { + "maxLength": 256, + "minLength": 1, + "type": "string" }, - "group_id": { - "$ref": "#/components/schemas/GroupId" + "parent": { + "$ref": "#/components/schemas/UUID" }, - "members": { + "protocol": { + "$ref": "#/components/schemas/BaseProtocolTag_LTM0MDE1NTEx" + }, + "qualified_users": { + "description": "List of qualified user IDs (excluding the requestor) to be part of this conversation", "items": { - "$ref": "#/components/schemas/ClientIdentity" + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" }, "type": "array" }, - "parent_qualified_id": { - "$ref": "#/components/schemas/Qualified_ConvId" + "receipt_mode": { + "description": "Conversation receipt mode", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" }, - "subconv_id": { - "type": "string" + "skip_creator": { + "description": "Don't add creator to the conversation, only works for team admins not wanting to be part of the channels they create.", + "type": "boolean" + }, + "team": { + "$ref": "#/components/schemas/ConvTeamInfo_Mzc5NjcyNjAz" + }, + "users": { + "deprecated": true, + "description": "List of user IDs (excluding the requestor) to be part of this conversation (deprecated)", + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" } }, - "required": [ - "parent_qualified_id", - "subconv_id", - "group_id", - "epoch", - "members" - ], "type": "object" }, - "PushToken": { - "description": "Native Push Token", + "NewLegalHoldService_Mzg0ODQ5NDU1": { "properties": { - "app": { - "description": "Application", - "type": "string" - }, - "client": { - "description": "Client ID", - "type": "string" + "auth_token": { + "$ref": "#/components/schemas/ASCII" }, - "token": { - "description": "Access Token", - "type": "string" + "base_url": { + "$ref": "#/components/schemas/HttpsUrl" }, - "transport": { - "$ref": "#/components/schemas/Transport" + "public_key": { + "$ref": "#/components/schemas/ServiceKeyPEM" } }, "required": [ - "transport", - "app", - "token", - "client" + "base_url", + "public_key", + "auth_token" ], "type": "object" }, - "PushTokenList": { - "description": "List of Native Push Tokens", + "NewMeeting_LTI1NTMzOTU5": { + "description": "Request to create a new meeting", "properties": { - "tokens": { - "description": "Push tokens", + "end_time": { + "$ref": "#/components/schemas/UTCTime" + }, + "invited_emails": { "items": { - "$ref": "#/components/schemas/PushToken" + "$ref": "#/components/schemas/Email" }, "type": "array" + }, + "recurrence": { + "$ref": "#/components/schemas/Recurrence_LTQ0OTc0ODE2" + }, + "start_time": { + "$ref": "#/components/schemas/UTCTime" + }, + "title": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "tzid": { + "$ref": "#/components/schemas/TimeZone" } }, "required": [ - "tokens" + "start_time", + "end_time", + "tzid", + "title" ], "type": "object" }, - "QualifiedNewOtrMessage": { - "description": "This object can only be parsed from Protobuf.\nThe specification for the protobuf types is here: \nhttps://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto." - }, - "QualifiedUserClientPrekeyMapV4": { + "NewOne2OneConv_LTI3OTc4NDAz": { + "description": "JSON object to create a new 1:1 conversation. When using 'qualified_users' (preferred), you can omit 'users'", "properties": { - "failed_to_list": { + "name": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "qualified_users": { + "description": "List of qualified user IDs (excluding the requestor) to be part of this conversation", "items": { - "$ref": "#/components/schemas/Qualified_UserId" + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" }, "type": "array" }, - "qualified_user_client_prekeys": { - "additionalProperties": { - "$ref": "#/components/schemas/UserClientPrekeyMap" - }, - "type": "object" - } - }, - "required": [ - "qualified_user_client_prekeys" - ], - "type": "object" - }, - "QualifiedUserClients": { - "additionalProperties": { - "additionalProperties": { + "team": { + "$ref": "#/components/schemas/ConvTeamInfo_Mzc5NjcyNjAz" + }, + "users": { + "deprecated": true, + "description": "List of user IDs (excluding the requestor) to be part of this conversation (deprecated)", "items": { - "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", - "type": "string" + "$ref": "#/components/schemas/UUID" }, "type": "array" - }, - "type": "object" - }, - "description": "Map of Domain to UserClients", - "example": { - "domain1.example.com": { - "1d51e2d6-9c70-605f-efc8-ff85c3dabdc7": [ - "60f85e4b15ad3786", - "6e323ab31554353b" - ] } }, "type": "object" }, - "QualifiedUserIdList with EdMemberLeftReason": { + "NewOtrMessage_LTUyMTE5MTMw": { "properties": { - "qualified_user_ids": { - "items": { - "$ref": "#/components/schemas/Qualified_UserId" - }, - "type": "array" + "data": { + "type": "string" }, - "reason": { - "$ref": "#/components/schemas/EdMemberLeftReason" + "native_priority": { + "$ref": "#/components/schemas/Priority_ODA3NDM3MDYy" }, - "user_ids": { - "deprecated": true, - "description": "Deprecated, use qualified_user_ids", + "native_push": { + "type": "boolean" + }, + "recipients": { + "$ref": "#/components/schemas/UserClientMap" + }, + "report_missing": { "items": { "$ref": "#/components/schemas/UUID" }, "type": "array" + }, + "sender": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" + }, + "transient": { + "type": "boolean" } }, "required": [ - "reason", - "qualified_user_ids", - "user_ids" + "sender", + "recipients" ], "type": "object" }, - "QualifiedUserMap_Set_PubClient": { - "additionalProperties": { - "$ref": "#/components/schemas/UserMap_Set_PubClient" - }, - "description": "Map of Domain to (UserMap (Set_PubClient)).", - "example": { - "domain1.example.com": { - "1d51e2d6-9c70-605f-efc8-ff85c3dabdc7": [ - { - "class": "legalhold", - "id": "d0" - } - ] + "NewPasswordReset_LTEyNzAxMTcy": { + "description": "Data to initiate a password reset", + "properties": { + "email": { + "$ref": "#/components/schemas/Email" + }, + "phone": { + "description": "Email", + "type": "string" } }, "type": "object" }, - "Qualified_ConvId": { + "NewProviderResponse_OTE0ODI2NjU0": { "properties": { - "domain": { - "$ref": "#/components/schemas/Domain" - }, "id": { "$ref": "#/components/schemas/UUID" + }, + "password": { + "maxLength": 1024, + "minLength": 8, + "type": "string" } }, "required": [ - "domain", "id" ], "type": "object" }, - "Qualified_Handle": { + "NewProvider_LTEyMTY5MjYy": { "properties": { - "domain": { - "$ref": "#/components/schemas/Domain" + "description": { + "maxLength": 1024, + "minLength": 1, + "type": "string" }, - "handle": { - "$ref": "#/components/schemas/Handle" + "email": { + "$ref": "#/components/schemas/Email" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + }, + "url": { + "$ref": "#/components/schemas/HttpsUrl" } }, "required": [ - "domain", - "handle" + "name", + "email", + "url", + "description" ], "type": "object" }, - "Qualified_UserId": { + "NewServiceResponse_LTExMzcwMjg5": { "properties": { - "domain": { - "$ref": "#/components/schemas/Domain" + "auth_token": { + "$ref": "#/components/schemas/ASCII" }, "id": { "$ref": "#/components/schemas/UUID" } }, "required": [ - "domain", "id" ], "type": "object" }, - "QueuedNotification": { - "description": "A single notification", + "NewService_LTYwOTU1MDQ3": { "properties": { - "id": { - "$ref": "#/components/schemas/UUID" - }, - "payload": { - "description": "List of events", + "assets": { "items": { - "$ref": "#/components/schemas/Object" + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" }, - "minItems": 1, "type": "array" - } - }, - "required": [ - "id", - "payload" - ], - "type": "object" - }, - "QueuedNotificationList": { - "description": "Zero or more notifications", - "properties": { - "has_more": { - "description": "Whether there are still more notifications.", - "type": "boolean" }, - "notifications": { - "description": "Notifications", - "items": { - "$ref": "#/components/schemas/QueuedNotification" - }, - "type": "array" + "auth_token": { + "$ref": "#/components/schemas/ASCII" }, - "time": { - "$ref": "#/components/schemas/UTCTime" - } - }, - "required": [ - "notifications" - ], - "type": "object" - }, - "RTCConfiguration": { - "description": "A subset of the WebRTC 'RTCConfiguration' dictionary", - "properties": { - "ice_servers": { - "description": "Array of 'RTCIceServer' objects", - "items": { - "$ref": "#/components/schemas/RTCIceServer" - }, - "minItems": 1, - "type": "array" + "base_url": { + "$ref": "#/components/schemas/HttpsUrl" }, - "is_federating": { - "description": "True if the client should connect to an SFT in the sft_servers_all and request it to federate", - "type": "boolean" + "description": { + "maxLength": 1024, + "minLength": 1, + "type": "string" }, - "sft_servers": { - "description": "Array of 'SFTServer' objects (optional)", - "items": { - "$ref": "#/components/schemas/SftServer" - }, - "minItems": 1, - "type": "array" + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" }, - "sft_servers_all": { - "description": "Array of all SFT servers", + "public_key": { + "$ref": "#/components/schemas/ServiceKeyPEM" + }, + "summary": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "tags": { "items": { - "$ref": "#/components/schemas/SftServer" + "$ref": "#/components/schemas/ServiceTag_LTMyNTEzNjYy" }, + "maxItems": 3, + "minItems": 1, "type": "array" - }, - "ttl": { - "description": "Number of seconds after which the configuration should be refreshed (advisory)", - "format": "int32", - "maximum": 4294967295, - "minimum": 0, - "type": "integer" } }, "required": [ - "ice_servers", - "ttl" + "name", + "summary", + "description", + "base_url", + "public_key", + "assets", + "tags" ], "type": "object" }, - "RTCIceServer": { - "description": "A subset of the WebRTC 'RTCIceServer' object", + "NewTeamCollaborator_LTIxNjEzMTYw": { "properties": { - "credential": { - "$ref": "#/components/schemas/ASCII" - }, - "urls": { - "description": "Array of TURN server addresses of the form 'turn::'", + "permissions": { "items": { - "$ref": "#/components/schemas/TurnURI" + "$ref": "#/components/schemas/CollaboratorPermission_NDg5NTg2ODgy" }, - "minItems": 1, "type": "array" }, - "username": { - "$ref": "#/components/schemas/" + "user": { + "$ref": "#/components/schemas/UUID" } }, "required": [ - "urls", - "username", - "credential" + "user", + "permissions" ], "type": "object" }, - "RedirectUrl": { - "description": "The URL must match the URL that was used to generate the authorization code.", - "type": "string" - }, - "Relation": { - "enum": [ - "accepted", - "blocked", - "pending", - "ignored", - "sent", - "cancelled", - "missing-legalhold-consent" - ], - "type": "string" - }, - "RemoveBotResponse": { + "NewTeamMember_Required_LTg2NjU5OTI2": { + "description": "Required data when creating new team members", "properties": { - "event": { - "$ref": "#/components/schemas/Event" + "member": { + "description": "the team member to add (the legalhold_status field must be null or missing!)", + "properties": { + "created_at": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "created_by": { + "$ref": "#/components/schemas/UUID" + }, + "permissions": { + "$ref": "#/components/schemas/Permissions_NDE0ODM5NDUx" + }, + "user": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "user", + "permissions" + ], + "type": "object" } }, "required": [ - "event" + "member" ], "type": "object" }, - "RemoveCookies": { - "description": "Data required to remove cookies", + "NewUserGroup_MzYxODU0OTU1": { "properties": { - "ids": { - "description": "A list of cookie IDs to revoke", - "items": { - "format": "int32", - "maximum": 4294967295, - "minimum": 0, - "type": "integer" - }, - "type": "array" - }, - "labels": { - "description": "A list of cookie labels for which to revoke the cookies", + "members": { "items": { - "type": "string" + "$ref": "#/components/schemas/UUID" }, "type": "array" }, - "password": { - "description": "The user's password", - "maxLength": 1024, - "minLength": 6, + "name": { + "maxLength": 4000, + "minLength": 1, "type": "string" } }, "required": [ - "password" + "name", + "members" ], "type": "object" }, - "RemoveLegalHoldSettingsRequest": { - "properties": { - "password": { - "maxLength": 1024, - "minLength": 6, - "type": "string" - } - }, - "type": "object" - }, - "RichField": { + "NewUser_PlainTextPassword_8_LTI4MzI5NzQx": { "properties": { - "type": { - "type": "string" + "accent_id": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" }, - "value": { - "type": "string" - } - }, - "required": [ - "type", - "value" - ], - "type": "object" - }, - "RichInfoAssocList": { - "description": "json object with case-insensitive fields.", - "properties": { - "fields": { + "assets": { "items": { - "$ref": "#/components/schemas/RichField" + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" }, "type": "array" }, - "version": { - "maximum": 9223372036854775807, - "minimum": -9223372036854775808, + "email": { + "$ref": "#/components/schemas/Email" + }, + "email_code": { + "$ref": "#/components/schemas/ASCII" + }, + "expires_in": { + "maximum": 604800, + "minimum": 1, "type": "integer" + }, + "invitation_code": { + "$ref": "#/components/schemas/ASCII" + }, + "label": { + "type": "string" + }, + "locale": { + "$ref": "#/components/schemas/Locale" + }, + "managed_by": { + "$ref": "#/components/schemas/ManagedBy_NTI0ODc0NTQx" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "password": { + "maxLength": 1024, + "minLength": 8, + "type": "string" + }, + "picture": { + "$ref": "#/components/schemas/Pict_DEPRECATED_USE_ASSETS_INSTEAD" + }, + "sso_id": { + "$ref": "#/components/schemas/UserSSOId" + }, + "supported_protocols": { + "items": { + "$ref": "#/components/schemas/BaseProtocolTag_LTM0MDE1NTEx" + }, + "type": "array" + }, + "team": { + "$ref": "#/components/schemas/BindingNewTeamUser_LTY0MDQxMDEw" + }, + "team_code": { + "$ref": "#/components/schemas/ASCII" + }, + "team_id": { + "$ref": "#/components/schemas/UUID" + }, + "uuid": { + "$ref": "#/components/schemas/UUID" } }, "required": [ - "version", - "fields" + "name" ], "type": "object" }, - "Role": { - "description": "Role of the invited user", - "enum": [ - "owner", - "admin", - "member", - "partner" - ], - "type": "string" - }, - "RoleName": { - "description": "Role name, between 2 and 128 chars, 'wire_' prefix is reserved for roles designed by Wire (i.e., no custom roles can have the same prefix)", - "type": "string" - }, - "SSOConfig.LockableFeature": { + "OAuthAccessTokenRequest_LTYyNTcyMzI4": { "properties": { - "lockStatus": { - "$ref": "#/components/schemas/LockStatus" + "client_id": { + "$ref": "#/components/schemas/UUID" }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" + "code": { + "$ref": "#/components/schemas/OAuthAuthorizationCode" }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "code_verifier": { + "description": "The code verifier to complete the code challenge", + "maxLength": 128, + "minLength": 43, + "type": "string" + }, + "grant_type": { + "$ref": "#/components/schemas/OAuthGrantType_LTIxODA5NDIw" + }, + "redirect_uri": { + "$ref": "#/components/schemas/RedirectUrl" } }, "required": [ - "status", - "lockStatus" + "grant_type", + "client_id", + "code_verifier", + "code", + "redirect_uri" ], "type": "object" }, - "ScimTokenInfo": { + "OAuthAccessTokenResponse_NzEwOTI4NjQ0": { "properties": { - "created_at": { - "$ref": "#/components/schemas/UTCTime" - }, - "description": { + "access_token": { + "description": "The access token, which has a relatively short lifetime", "type": "string" }, - "id": { - "$ref": "#/components/schemas/UUID" + "expires_in": { + "description": "The lifetime of the access token in seconds", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" }, - "idp": { - "$ref": "#/components/schemas/UUID" + "refresh_token": { + "description": "The refresh token, which has a relatively long lifetime, and can be used to obtain a new access token", + "type": "string" }, - "team": { - "$ref": "#/components/schemas/UUID" + "token_type": { + "$ref": "#/components/schemas/OAuthAccessTokenType_MjU3ODI0NDIw" } }, "required": [ - "team", - "id", - "created_at", - "description" + "access_token", + "token_type", + "expires_in", + "refresh_token" ], "type": "object" }, - "ScimTokenList": { + "OAuthAccessTokenType_MjU3ODI0NDIw": { + "description": "The type of the access token. Currently only `Bearer` is supported.", + "enum": [ + "Bearer" + ], + "type": "string" + }, + "OAuthApplication_Mjk5NTUxNjA1": { "properties": { - "tokens": { + "id": { + "$ref": "#/components/schemas/UUID" + }, + "name": { + "description": "The OAuth client's name", + "maxLength": 256, + "minLength": 6, + "type": "string" + }, + "sessions": { + "description": "The OAuth client's sessions", "items": { - "$ref": "#/components/schemas/ScimTokenInfo" + "$ref": "#/components/schemas/OAuthSession_LTQxOTIxNTMy" }, "type": "array" } }, "required": [ - "tokens" + "id", + "name", + "sessions" ], "type": "object" }, - "SearchResult": { + "OAuthAuthorizationCode": { + "description": "The authorization code", + "type": "string" + }, + "OAuthClient_NzExMTI5NTIy": { "properties": { - "documents": { - "description": "List of contacts found", - "items": { - "$ref": "#/components/schemas/TeamContact" - }, - "type": "array" - }, - "found": { - "description": "Total number of hits", - "maximum": 9223372036854775807, - "minimum": -9223372036854775808, - "type": "integer" - }, - "has_more": { - "description": "Indicates whether there are more results to be fetched", - "type": "boolean" - }, - "paging_state": { - "$ref": "#/components/schemas/PagingState" - }, - "returned": { - "description": "Total number of hits returned", - "maximum": 9223372036854775807, - "minimum": -9223372036854775808, - "type": "integer" + "application_name": { + "maxLength": 256, + "minLength": 6, + "type": "string" }, - "search_policy": { - "$ref": "#/components/schemas/FederatedUserSearchPolicy" + "client_id": { + "$ref": "#/components/schemas/UUID" }, - "took": { - "description": "Search time in ms", - "maximum": 9223372036854775807, - "minimum": -9223372036854775808, - "type": "integer" + "redirect_url": { + "$ref": "#/components/schemas/RedirectUrl" } }, "required": [ - "found", - "returned", - "took", - "documents", - "search_policy" + "client_id", + "application_name", + "redirect_url" ], "type": "object" }, - "SearchVisibilityAvailableConfig.Feature": { - "properties": { - "status": { - "$ref": "#/components/schemas/FeatureStatus" - }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" - } - }, - "required": [ - "status" + "OAuthCodeChallenge": { + "description": "Generated by the client from the code verifier (unpadded base64url-encoded SHA256 hash of the code verifier)", + "type": "string" + }, + "OAuthGrantType_LTIxODA5NDIw": { + "description": "Indicates which authorization flow to use. Use `authorization_code` for authorization code flow.", + "enum": [ + "authorization_code", + "refresh_token" ], - "type": "object" + "type": "string" }, - "SearchVisibilityAvailableConfig.LockableFeature": { + "OAuthRefreshAccessTokenRequest_LTUwNjA3OTI1": { "properties": { - "lockStatus": { - "$ref": "#/components/schemas/LockStatus" + "client_id": { + "$ref": "#/components/schemas/UUID" }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" + "grant_type": { + "$ref": "#/components/schemas/OAuthGrantType_LTIxODA5NDIw" }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "refresh_token": { + "description": "The refresh token", + "type": "string" } }, "required": [ - "status", - "lockStatus" + "grant_type", + "client_id", + "refresh_token" ], "type": "object" }, - "SearchVisibilityInboundConfig.Feature": { + "OAuthResponseType_ODI2Mjg3NzQx": { + "description": "Indicates which authorization flow to use. Use `code` for authorization code flow.", + "enum": [ + "code" + ], + "type": "string" + }, + "OAuthRevokeRefreshTokenRequest_MjA1MDg4MzQ4": { "properties": { - "status": { - "$ref": "#/components/schemas/FeatureStatus" + "client_id": { + "$ref": "#/components/schemas/UUID" }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "refresh_token": { + "description": "The refresh token", + "type": "string" } }, "required": [ - "status" + "client_id", + "refresh_token" ], "type": "object" }, - "SearchVisibilityInboundConfig.LockableFeature": { + "OAuthSession_LTQxOTIxNTMy": { "properties": { - "lockStatus": { - "$ref": "#/components/schemas/LockStatus" - }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" + "created_at": { + "$ref": "#/components/schemas/UTCTimeMillis" }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "refresh_token_id": { + "$ref": "#/components/schemas/UUID" } }, "required": [ - "status", - "lockStatus" + "refresh_token_id", + "created_at" ], "type": "object" }, - "SelfDeletingMessagesConfig": { + "Object": { + "additionalProperties": true, + "description": "A single notification event", "properties": { - "enforcedTimeoutSeconds": { - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer" + "type": { + "description": "Event type", + "type": "string" } }, - "required": [ - "enforcedTimeoutSeconds" - ], + "title": "Event", "type": "object" }, - "SelfDeletingMessagesConfig.Feature": { + "OtherMemberUpdate_LTM1MjYzOTU0": { + "description": "Update user properties of other members relative to a conversation", "properties": { - "config": { - "$ref": "#/components/schemas/SelfDeletingMessagesConfig" - }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" - }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "conversation_role": { + "$ref": "#/components/schemas/RoleName" } }, - "required": [ - "status", - "config" - ], "type": "object" }, - "SelfDeletingMessagesConfig.LockableFeature": { + "OtherMember_LTgzNzE2MTk4": { "properties": { - "config": { - "$ref": "#/components/schemas/SelfDeletingMessagesConfig" + "conversation_role": { + "$ref": "#/components/schemas/RoleName" }, - "lockStatus": { - "$ref": "#/components/schemas/LockStatus" + "id": { + "$ref": "#/components/schemas/UUID" }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, + "service": { + "$ref": "#/components/schemas/ServiceRef_LTgxMjY3NzAz" + }, + "status": { + "deprecated": true, + "description": "deprecated", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, "type": "integer" } }, "required": [ - "status", - "lockStatus", - "config" + "qualified_id" ], "type": "object" }, - "SendActivationCode": { - "description": "Data for requesting an email code to be sent. 'email' must be present.", + "OtrMessage_LTY4MTYzNzg3": { + "description": "Encrypted message of a conversation", "properties": { - "email": { - "$ref": "#/components/schemas/Email" + "data": { + "description": "Extra (symmetric) data (i.e. ciphertext, Base64 in JSON) that is common with all other recipients.", + "type": "string" }, - "locale": { - "$ref": "#/components/schemas/Locale" + "recipient": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" + }, + "sender": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" + }, + "text": { + "description": "The ciphertext for the recipient (Base64 in JSON)", + "type": "string" } }, "required": [ - "email" + "sender", + "recipient", + "text" ], "type": "object" }, - "SendVerificationCode": { + "OwnConvMembers_LTEwMzUzODMy": { + "description": "Users of a conversation", "properties": { - "action": { - "$ref": "#/components/schemas/VerificationAction" + "others": { + "description": "All other current users of this conversation", + "items": { + "$ref": "#/components/schemas/OtherMember_LTgzNzE2MTk4" + }, + "type": "array" }, - "email": { - "$ref": "#/components/schemas/Email" + "self": { + "$ref": "#/components/schemas/Member_OTA5OTgyNzcw" } }, "required": [ - "action", - "email" + "self", + "others" ], "type": "object" }, - "Service": { + "OwnConversation_GroupConvType_LTU2MzYxNTg0": { + "description": "A conversation object as returned from the server", "properties": { - "assets": { + "access": { "items": { - "$ref": "#/components/schemas/UserAsset" + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" }, "type": "array" }, - "auth_tokens": { - "$ref": "#/components/schemas/List1" + "access_role": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" }, - "base_url": { - "$ref": "#/components/schemas/HttpsUrl" + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" }, - "description": { - "type": "string" + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" }, - "enabled": { - "type": "boolean" + "cipher_suite": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "creator": { + "$ref": "#/components/schemas/UUID" + }, + "epoch": { + "description": "The epoch number of the corresponding MLS group", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "epoch_timestamp": { + "$ref": "#/components/schemas/UTCTime" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "history": { + "$ref": "#/components/schemas/History" }, "id": { "$ref": "#/components/schemas/UUID" }, - "name": { - "maxLength": 128, - "minLength": 1, + "last_event": { "type": "string" }, - "public_keys": { - "$ref": "#/components/schemas/List1" + "last_event_time": { + "type": "string" }, - "summary": { + "members": { + "$ref": "#/components/schemas/OwnConvMembers_LTEwMzUzODMy" + }, + "message_timer": { + "description": "Per-conversation message timer (can be null)", + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { "type": "string" }, - "tags": { - "items": { - "$ref": "#/components/schemas/" - }, - "type": "array" - } - }, - "required": [ - "id", - "name", - "summary", - "description", - "base_url", - "auth_tokens", - "public_keys", - "assets", - "tags", - "enabled" - ], - "type": "object" - }, - "ServiceKey": { - "properties": { - "pem": { - "$ref": "#/components/schemas/ServiceKeyPEM" + "parent": { + "$ref": "#/components/schemas/UUID" }, - "size": { + "protocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "receipt_mode": { + "description": "Conversation receipt mode", "format": "int32", "maximum": 2147483647, "minimum": -2147483648, "type": "integer" }, + "team": { + "$ref": "#/components/schemas/UUID" + }, "type": { - "$ref": "#/components/schemas/ServiceKeyType" + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" } }, "required": [ + "qualified_id", "type", - "size", - "pem" + "access", + "access_role", + "members", + "group_id", + "epoch" ], "type": "object" }, - "ServiceKeyPEM": { - "example": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+Kg/PHHU3atXrUbKnw0\nG06FliXcNt3lMwl2os5twEDcPPFw/feGiAKymxp+7JqZDrseS5D9THGrW+OQRIPH\nWvUBdiLfGrZqJO223DB6D8K2Su/odmnjZJ2z23rhXoEArTplu+Dg9K+c2LVeXTKV\nVPOaOzgtAB21XKRiQ4ermqgi3/njr03rXyq/qNkuNd6tNcg+HAfGxfGvvCSYBfiS\nbUKr/BeArYRcjzr/h5m1In6fG/if9GEI6m8dxHT9JbY53wiksowy6ajCuqskIFg8\n7X883H+LA/d6X5CTiPv1VMxXdBUiGPuC9IT/6CNQ1/LFt0P37ax58+LGYlaFo7la\nnQIDAQAB\n-----END PUBLIC KEY-----\n", - "type": "string" - }, - "ServiceKeyType": { - "enum": [ - "rsa" - ], + "PagingState": { + "description": "Paging state that should be supplied to retrieve the next page of results", "type": "string" }, - "ServiceProfile": { + "PasswordChange_MTgzMDM2NTY2": { + "description": "Data to change a password. The old password is required if a password already exists.", "properties": { - "has_more": { - "type": "boolean" + "new_password": { + "maxLength": 1024, + "minLength": 8, + "type": "string" }, - "services": { - "items": { - "$ref": "#/components/schemas/ServiceProfile" - }, - "type": "array" + "old_password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" } }, "required": [ - "has_more", - "services" + "new_password" ], "type": "object" }, - "ServiceRef": { + "PasswordChange_NDI0ODgwNDU0": { "properties": { - "id": { - "$ref": "#/components/schemas/UUID" + "new_password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" }, - "provider": { - "$ref": "#/components/schemas/UUID" + "old_password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" } }, "required": [ - "id", - "provider" + "old_password", + "new_password" ], "type": "object" }, - "ServiceTagList": { - "items": { - "$ref": "#/components/schemas/" + "PasswordReqBody_LTcxMzE3ODE3": { + "properties": { + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + } }, - "type": "array" + "type": "object" }, - "SftServer": { - "description": "Inspired by WebRTC 'RTCIceServer' object, contains details of SFT servers", + "PasswordReset_LTYzNDYxNTQ3": { "properties": { - "urls": { - "description": "Array containing exactly one SFT server address of the form 'https://:'", - "items": { - "$ref": "#/components/schemas/HttpsUrl" - }, - "type": "array" + "email": { + "$ref": "#/components/schemas/Email" } }, "required": [ - "urls" + "email" ], "type": "object" }, - "SimpleMember": { + "Permissions_NDE0ODM5NDUx": { + "description": "This is just a complicated way of representing a team role. self and copy always have to contain the same integer, and only the following integers are allowed: 1025 (partner), 1587 (member), 5951 (admin), 8191 (owner). Unit tests of the galley-types package in wire-server contain an authoritative list.", "properties": { - "conversation_role": { - "$ref": "#/components/schemas/RoleName" - }, - "id": { - "$ref": "#/components/schemas/UUID" + "copy": { + "description": "Permissions that this user is able to grant others", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" }, - "qualified_id": { - "$ref": "#/components/schemas/Qualified_UserId" + "self": { + "description": "Permissions that the user has", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" } }, "required": [ - "qualified_id" + "self", + "copy" ], "type": "object" }, - "SimpleMembers": { + "PhoneNumber": { + "description": "A known phone number with a pending password reset.", + "type": "string" + }, + "Pict_DEPRECATED_USE_ASSETS_INSTEAD": { + "items": { + "type": "object" + }, + "maxItems": 10, + "minItems": 0, + "type": "array" + }, + "PrekeyBundle_MzgzOTk4MjYz": { "properties": { - "user_ids": { - "deprecated": true, - "description": "deprecated", + "clients": { "items": { - "$ref": "#/components/schemas/UUID" + "$ref": "#/components/schemas/ClientPrekey_LTcyODUzMTcw" }, "type": "array" }, - "users": { - "items": { - "$ref": "#/components/schemas/SimpleMember" - }, - "type": "array" + "user": { + "$ref": "#/components/schemas/UUID" } }, "required": [ - "users" + "user", + "clients" ], "type": "object" }, - "SndFactorPasswordChallengeConfig.Feature": { + "PreventAdminlessGroupsConfigB_Covered_Identity_MjQ2NDYwMTk2": { "properties": { - "status": { - "$ref": "#/components/schemas/FeatureStatus" - }, - "ttl": { - "example": "unlimited", + "deletionTimeout": { "maximum": 18446744073709551615, "minimum": 0, "type": "integer" + }, + "deletionTimeoutDuration": { + "type": "string" + }, + "promotionStrategy": { + "$ref": "#/components/schemas/PreventAdminlessGroupsPromotionStrategy_Mjc1ODA2MDU1" + }, + "reminderTimeoutDurations": { + "items": { + "type": "string" + }, + "type": "array" + }, + "reminderTimeouts": { + "items": { + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "type": "array" } }, "required": [ - "status" + "promotionStrategy" + ], + "type": "object" + }, + "PreventAdminlessGroupsPromotionStrategy_Mjc1ODA2MDU1": { + "enum": [ + "alphabetical", + "random", + "all" + ], + "type": "string" + }, + "Priority_ODA3NDM3MDYy": { + "enum": [ + "low", + "high" ], + "type": "string" + }, + "PropertyKeysAndValues": { "type": "object" }, - "SndFactorPasswordChallengeConfig.LockableFeature": { + "PropertyValue": { + "description": "An arbitrary JSON value for a property" + }, + "ProtocolTag_ODg1MTE5NjEw": { + "enum": [ + "proteus", + "mls", + "mixed" + ], + "type": "string" + }, + "ProtocolUpdate_NzY1ODgxNDQy": { "properties": { - "lockStatus": { - "$ref": "#/components/schemas/LockStatus" - }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" - }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "protocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + } + }, + "type": "object" + }, + "ProviderActivationResponse_LTgzNTU3MzA5": { + "properties": { + "email": { + "$ref": "#/components/schemas/Email" } }, "required": [ - "status", - "lockStatus" + "email" ], "type": "object" }, - "SomeKey": {}, - "Sso": { + "ProviderLogin_LTE2MTk2NTM5": { "properties": { - "issuer": { - "type": "string" + "email": { + "$ref": "#/components/schemas/Email" }, - "nameid": { + "password": { + "maxLength": 1024, + "minLength": 6, "type": "string" } }, "required": [ - "issuer", - "nameid" + "email", + "password" ], "type": "object" }, - "SsoSettings": { + "Provider_NDIyMzQ3ODIy": { "properties": { - "default_sso_code": { + "description": { + "type": "string" + }, + "email": { + "$ref": "#/components/schemas/Email" + }, + "id": { "$ref": "#/components/schemas/UUID" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "url": { + "$ref": "#/components/schemas/HttpsUrl" } }, + "required": [ + "id", + "name", + "email", + "url", + "description" + ], "type": "object" }, - "SupportedProtocolUpdate": { + "PubClient": { "properties": { - "supported_protocols": { - "items": { - "$ref": "#/components/schemas/BaseProtocol" - }, - "type": "array" + "class": { + "$ref": "#/components/schemas/ClientClass_NjE3MDgwNzcx" + }, + "id": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" } }, "required": [ - "supported_protocols" + "id" ], "type": "object" }, - "SystemSettings": { + "PublicSubConversation_MjI2NTIxMzU4": { + "description": "An MLS subconversation", "properties": { - "setEnableMls": { - "description": "Whether MLS is enabled or not", - "type": "boolean" + "cipher_suite": { + "$ref": "#/components/schemas/CipherSuiteTag" }, - "setRestrictUserCreation": { - "description": "Do not allow certain user creation flows", - "type": "boolean" + "epoch": { + "description": "The epoch number of the corresponding MLS group", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "epoch_timestamp": { + "$ref": "#/components/schemas/UTCTime" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "members": { + "items": { + "$ref": "#/components/schemas/ClientIdentity_MjAxMjI3NTUw" + }, + "type": "array" + }, + "parent_qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "subconv_id": { + "type": "string" } }, "required": [ - "setRestrictUserCreation", - "setEnableMls" + "parent_qualified_id", + "subconv_id", + "group_id", + "epoch", + "members" ], "type": "object" }, - "SystemSettingsPublic": { + "PushTokenList_NDI0Mjc3MzY3": { + "description": "List of Native Push Tokens", "properties": { - "setRestrictUserCreation": { - "description": "Do not allow certain user creation flows", - "type": "boolean" + "tokens": { + "description": "Push tokens", + "items": { + "$ref": "#/components/schemas/PushToken_ODYzMDYzOTA4" + }, + "type": "array" } }, "required": [ - "setRestrictUserCreation" + "tokens" ], "type": "object" }, - "Team": { - "description": "`binding` is deprecated, and should be ignored. The non-binding teams API is not used (and will not be supported from API version V4 onwards), and `binding` will always be `true`.", + "PushToken_ODYzMDYzOTA4": { + "description": "Native Push Token", "properties": { - "binding": { - "$ref": "#/components/schemas/TeamBinding" - }, - "creator": { - "$ref": "#/components/schemas/UUID" - }, - "icon": { - "$ref": "#/components/schemas/Icon" - }, - "icon_key": { + "app": { + "description": "Application", "type": "string" }, - "id": { - "$ref": "#/components/schemas/UUID" + "client": { + "description": "Client ID", + "type": "string" }, - "name": { + "token": { + "description": "Access Token", "type": "string" }, - "splash_screen": { - "$ref": "#/components/schemas/Icon" + "transport": { + "$ref": "#/components/schemas/Transport_NDk2NzU5NDIy" } }, "required": [ - "id", - "creator", - "name", - "icon" + "transport", + "app", + "token", + "client" ], "type": "object" }, - "TeamBinding": { - "deprecated": true, - "description": "Deprecated, please ignore.", - "enum": [ - true, - false - ], - "type": "boolean" - }, - "TeamContact": { + "PutApp_LTE4MDc1OTM4": { "properties": { "accent_id": { - "maximum": 9223372036854775807, - "minimum": -9223372036854775808, + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, "type": "integer" }, - "created_at": { - "$ref": "#/components/schemas/UTCTimeMillis" - }, - "email": { - "$ref": "#/components/schemas/Email" - }, - "email_unvalidated": { - "$ref": "#/components/schemas/Email" - }, - "handle": { - "type": "string" - }, - "id": { - "$ref": "#/components/schemas/UUID" - }, - "managed_by": { - "$ref": "#/components/schemas/ManagedBy" + "assets": { + "items": { + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" + }, + "type": "array" }, - "name": { + "category": { + "description": "Category name (if uncertain, pick \"other\")", "type": "string" }, - "role": { - "$ref": "#/components/schemas/Role" - }, - "saml_idp": { + "description": { + "maxLength": 300, + "minLength": 0, "type": "string" }, - "scim_external_id": { + "name": { + "maxLength": 128, + "minLength": 1, "type": "string" - }, - "sso": { - "$ref": "#/components/schemas/Sso" - }, - "team": { - "$ref": "#/components/schemas/UUID" } }, - "required": [ - "id", - "name" - ], "type": "object" }, - "TeamConversation": { - "description": "Team conversation data", + "QualifiedNewOtrMessage": { + "description": "This object can only be parsed from Protobuf.\nThe specification for the protobuf types is here: \nhttps://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto." + }, + "QualifiedUserClientPrekeyMapV4_MzcxOTAxMTYy": { "properties": { - "conversation": { - "$ref": "#/components/schemas/UUID" + "failed_to_list": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "type": "array" }, - "managed": { - "description": "This field MUST NOT be used by clients. It is here only for backwards compatibility of the interface." + "qualified_user_client_prekeys": { + "additionalProperties": { + "$ref": "#/components/schemas/UserClientPrekeyMap" + }, + "type": "object" } }, "required": [ - "conversation", - "managed" + "qualified_user_client_prekeys" ], "type": "object" }, - "TeamConversationList": { - "description": "Team conversation list", - "properties": { - "conversations": { + "QualifiedUserClients": { + "additionalProperties": { + "additionalProperties": { "items": { - "$ref": "#/components/schemas/TeamConversation" + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" }, "type": "array" + }, + "type": "object" + }, + "description": "Map of Domain to UserClients", + "example": { + "domain1.example.com": { + "1d51e2d6-9c70-605f-efc8-ff85c3dabdc7": [ + "60f85e4b15ad3786", + "6e323ab31554353b" + ] } }, - "required": [ - "conversations" - ], "type": "object" }, - "TeamDeleteData": { + "QualifiedUserMap_Set_PubClient": { + "additionalProperties": { + "$ref": "#/components/schemas/UserMap_Set_PubClient" + }, + "description": "Map of Domain to (UserMap (Set_PubClient)).", + "example": { + "domain1.example.com": { + "1d51e2d6-9c70-605f-efc8-ff85c3dabdc7": [ + { + "class": "legalhold", + "id": "d0" + } + ] + } + }, + "type": "object" + }, + "Qualified_Handle_Nzg0MDE3Nzk4": { "properties": { - "password": { - "maxLength": 1024, - "minLength": 6, - "type": "string" + "domain": { + "$ref": "#/components/schemas/Domain" }, - "verification_code": { - "$ref": "#/components/schemas/ASCII" + "handle": { + "$ref": "#/components/schemas/Handle" } }, + "required": [ + "domain", + "handle" + ], "type": "object" }, - "TeamMember": { - "description": "team member data", + "Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5": { "properties": { - "created_at": { - "$ref": "#/components/schemas/UTCTimeMillis" - }, - "created_by": { - "$ref": "#/components/schemas/UUID" - }, - "legalhold_status": { - "$ref": "#/components/schemas/UserLegalHoldStatus" - }, - "permissions": { - "$ref": "#/components/schemas/Permissions" + "domain": { + "$ref": "#/components/schemas/Domain" }, - "user": { + "id": { "$ref": "#/components/schemas/UUID" } }, "required": [ - "user" + "domain", + "id" ], "type": "object" }, - "TeamMemberDeleteData": { - "description": "Data for a team member deletion request in case of binding teams.", + "Qualified_Id_IdTag_Meeting_MjgxMDUyNjc3": { "properties": { - "password": { - "description": "The account password to authorise the deletion.", - "maxLength": 1024, - "minLength": 6, - "type": "string" + "domain": { + "$ref": "#/components/schemas/Domain" + }, + "id": { + "$ref": "#/components/schemas/UUID" } }, + "required": [ + "domain", + "id" + ], "type": "object" }, - "TeamMemberList": { - "description": "list of team member", + "Qualified_Id_IdTag_User_LTQ1NTIwNDM1": { "properties": { - "hasMore": { - "$ref": "#/components/schemas/ListType" + "domain": { + "$ref": "#/components/schemas/Domain" }, - "members": { - "description": "the array of team members", - "items": { - "$ref": "#/components/schemas/TeamMember" - }, - "type": "array" + "id": { + "$ref": "#/components/schemas/UUID" } }, "required": [ - "members", - "hasMore" + "domain", + "id" ], "type": "object" }, - "TeamMembersPage": { + "QueuedNotificationList_MTU0ODEyNTQ2": { + "description": "Zero or more notifications", "properties": { - "hasMore": { + "has_more": { + "description": "Whether there are still more notifications.", "type": "boolean" }, - "members": { + "notifications": { + "description": "Notifications", "items": { - "$ref": "#/components/schemas/TeamMember" + "$ref": "#/components/schemas/QueuedNotification_NTY2NzY2MTU2" }, "type": "array" }, - "pagingState": { - "$ref": "#/components/schemas/TeamMembers_PagingState" + "time": { + "$ref": "#/components/schemas/UTCTime" } }, "required": [ - "members", - "hasMore", - "pagingState" + "notifications" ], "type": "object" }, - "TeamMembers_PagingState": { - "type": "string" - }, - "TeamSearchVisibility": { - "description": "value of visibility", - "enum": [ - "standard", - "no-name-outside-team" - ], - "type": "string" - }, - "TeamSearchVisibilityView": { - "description": "Search visibility value for the team", + "QueuedNotification_NTY2NzY2MTU2": { + "description": "A single notification", "properties": { - "search_visibility": { - "$ref": "#/components/schemas/TeamSearchVisibility" + "id": { + "$ref": "#/components/schemas/UUID" + }, + "payload": { + "description": "List of events", + "items": { + "$ref": "#/components/schemas/Object" + }, + "minItems": 1, + "type": "array" } }, "required": [ - "search_visibility" + "id", + "payload" ], "type": "object" }, - "TeamSize": { - "description": "A simple object with a total number of team members.", + "RTCConfiguration_LTIwOTc4OTk0": { + "description": "A subset of the WebRTC 'RTCConfiguration' dictionary", "properties": { - "teamSize": { - "description": "Team size.", - "exclusiveMinimum": false, + "ice_servers": { + "description": "Array of 'RTCIceServer' objects", + "items": { + "$ref": "#/components/schemas/RTCIceServer_LTY1NzExODA0" + }, + "minItems": 1, + "type": "array" + }, + "is_federating": { + "description": "True if the client should connect to an SFT in the sft_servers_all and request it to federate", + "type": "boolean" + }, + "sft_servers": { + "description": "Array of 'SFTServer' objects (optional)", + "items": { + "$ref": "#/components/schemas/SFTServer_NDQ0NDkwNDE2" + }, + "minItems": 1, + "type": "array" + }, + "sft_servers_all": { + "description": "Array of all SFT servers", + "items": { + "$ref": "#/components/schemas/AuthSFTServer_LTY5MzcyOTE0" + }, + "type": "array" + }, + "ttl": { + "description": "Number of seconds after which the configuration should be refreshed (advisory)", + "format": "int32", + "maximum": 4294967295, "minimum": 0, "type": "integer" } }, "required": [ - "teamSize" + "ice_servers", + "ttl" ], "type": "object" }, - "TeamUpdateData": { + "RTCIceServer_LTY1NzExODA0": { + "description": "A subset of the WebRTC 'RTCIceServer' object", "properties": { - "icon": { - "$ref": "#/components/schemas/Icon" + "credential": { + "$ref": "#/components/schemas/ASCII" }, - "icon_key": { - "maxLength": 256, - "minLength": 1, - "type": "string" - }, - "name": { - "maxLength": 256, - "minLength": 1, - "type": "string" + "urls": { + "description": "Array of TURN server addresses of the form 'turn::'", + "items": { + "$ref": "#/components/schemas/TurnURI" + }, + "minItems": 1, + "type": "array" }, - "splash_screen": { - "$ref": "#/components/schemas/Icon" + "username": { + "$ref": "#/components/schemas/TurnUsername" } }, + "required": [ + "urls", + "username", + "credential" + ], "type": "object" }, - "Time": { + "Recurrence_LTQ0OTc0ODE2": { + "description": "Recurrence pattern for meetings", "properties": { - "time": { + "frequency": { + "$ref": "#/components/schemas/Frequency_Mzk0ODQwOTM3" + }, + "interval": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "until": { "$ref": "#/components/schemas/UTCTime" } }, "required": [ - "time" + "frequency" ], "type": "object" }, - "TokenType": { - "enum": [ - "Bearer" - ], + "RedirectUrl": { + "description": "The URL must match the URL that was used to generate the authorization code.", "type": "string" }, - "Transport": { - "description": "Transport", - "enum": [ - "GCM", - "APNS", - "APNS_SANDBOX", - "APNS_VOIP", - "APNS_VOIP_SANDBOX" - ], - "type": "string" + "RefreshAppCookieRequest_MjEyMDMyMTk5": { + "properties": { + "password": { + "description": "The password of the authenticated admin for verification. or if the user has only SAML credentials.", + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "type": "object" }, - "TurnURI": { - "type": "string" + "RefreshAppCookieResponse_LTQ0MjU1NTIw": { + "properties": { + "cookie": { + "$ref": "#/components/schemas/SomeUserToken" + } + }, + "required": [ + "cookie" + ], + "type": "object" }, - "TypingData": { + "RegisteredDomains_V10_NDYwNzYyMTMy": { "properties": { - "status": { - "$ref": "#/components/schemas/TypingStatus" + "registered_domains": { + "items": { + "$ref": "#/components/schemas/DomainRegistrationResponse_V10_MjE0NDkxODY4" + }, + "type": "array" } }, "required": [ - "status" + "registered_domains" ], "type": "object" }, - "TypingStatus": { + "Relation_LTE4OTU5MTk4": { "enum": [ - "started", - "stopped" + "accepted", + "blocked", + "pending", + "ignored", + "sent", + "cancelled", + "missing-legalhold-consent" ], "type": "string" }, - "URIRef Absolute": { - "description": "URL of the invitation link to be sent to the invitee", - "type": "string" - }, - "UTCTime": { - "example": "2021-05-12T10:52:02Z", - "format": "yyyy-mm-ddThh:MM:ssZ", - "type": "string" - }, - "UTCTimeMillis": { - "description": "The time when the session was created", - "example": "2021-05-12T10:52:02.671Z", - "format": "yyyy-mm-ddThh:MM:ss.qqqZ", - "type": "string" - }, - "UUID": { - "description": "The OAuth client's ID", - "example": "99db9768-04e3-4b5d-9268-831b6a25c4ab", - "format": "uuid", - "type": "string" + "RemoveBotResponse_LTUxNTQ4MDEy": { + "properties": { + "event": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "required": [ + "event" + ], + "type": "object" }, - "Unnamed": { + "RemoveCookies_OTYwMTI0NDMy": { + "description": "Data required to remove cookies", "properties": { - "created_at": { - "$ref": "#/components/schemas/UTCTimeMillis" + "ids": { + "description": "A list of cookie IDs to revoke", + "items": { + "format": "int32", + "maximum": 4294967295, + "minimum": 0, + "type": "integer" + }, + "type": "array" }, - "created_by": { - "$ref": "#/components/schemas/UUID" + "labels": { + "description": "A list of cookie labels for which to revoke the cookies", + "items": { + "type": "string" + }, + "type": "array" }, - "permissions": { - "$ref": "#/components/schemas/Permissions" + "password": { + "description": "The user's password", + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "required": [ + "password" + ], + "type": "object" + }, + "RemoveLegalHoldSettingsRequest_NzMzMzMyMDAz": { + "properties": { + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "type": "object" + }, + "RichField_LTgwMzc0MTg2": { + "properties": { + "type": { + "type": "string" }, - "user": { - "$ref": "#/components/schemas/UUID" + "value": { + "type": "string" } }, "required": [ - "user", - "permissions" + "type", + "value" ], "type": "object" }, - "UpdateBotPrekeys": { + "RichInfoAssocList": { + "description": "json object with case-insensitive fields.", "properties": { - "prekeys": { + "fields": { "items": { - "$ref": "#/components/schemas/Prekey" + "$ref": "#/components/schemas/RichField_LTgwMzc0MTg2" }, "type": "array" + }, + "version": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" } }, "required": [ - "prekeys" + "version", + "fields" ], "type": "object" }, - "UpdateClient": { + "RmClient_MTQ5OTI2MDY3": { "properties": { - "capabilities": { - "description": "Hints provided by the client for the backend so it can behave in a backwards-compatible way.", + "password": { + "description": "The password of the authenticated user for verification. The password is not required for deleting temporary clients. or if the user has only SAML credentials.", + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "type": "object" + }, + "RoleName": { + "description": "Role name, between 2 and 128 chars, 'wire_' prefix is reserved for roles designed by Wire (i.e., no custom roles can have the same prefix)", + "type": "string" + }, + "Role_LTIzMjAzMjky": { + "description": "Role of the invited user", + "enum": [ + "owner", + "admin", + "member", + "partner" + ], + "type": "string" + }, + "SFTServer_NDQ0NDkwNDE2": { + "description": "Inspired by WebRTC 'RTCIceServer' object, contains details of SFT servers", + "properties": { + "urls": { + "description": "Array containing exactly one SFT server address of the form 'https://:'", "items": { - "$ref": "#/components/schemas/ClientCapability" + "$ref": "#/components/schemas/HttpsUrl" }, "type": "array" + } + }, + "required": [ + "urls" + ], + "type": "object" + }, + "SFTUsername": { + "description": "String containing the SFT username", + "type": "string" + }, + "ScimTokenInfo_LTI5NjgwNzA1": { + "properties": { + "created_at": { + "$ref": "#/components/schemas/UTCTime" }, - "label": { - "description": "A new name for this client.", + "description": { "type": "string" }, - "lastkey": { - "$ref": "#/components/schemas/Prekey" + "id": { + "$ref": "#/components/schemas/UUID" }, - "mls_public_keys": { - "$ref": "#/components/schemas/MLSPublicKeys" + "idp": { + "$ref": "#/components/schemas/UUID" }, - "prekeys": { - "description": "New prekeys for other clients to establish OTR sessions.", + "name": { + "type": "string" + }, + "team": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "team", + "id", + "created_at", + "description", + "name" + ], + "type": "object" + }, + "ScimTokenList_NjQwNTYxOTAw": { + "properties": { + "tokens": { "items": { - "$ref": "#/components/schemas/Prekey" + "$ref": "#/components/schemas/ScimTokenInfo_LTI5NjgwNzA1" }, "type": "array" } }, + "required": [ + "tokens" + ], "type": "object" }, - "UpdateProvider": { + "ScimTokenName_LTgzOTM2OTI4": { "properties": { - "description": { - "type": "string" - }, "name": { - "maxLength": 128, - "minLength": 1, "type": "string" - }, - "url": { - "$ref": "#/components/schemas/HttpsUrl" } }, + "required": [ + "name" + ], "type": "object" }, - "UpdateService": { + "SearchResult_Contact_OTExNzg4MTE0": { "properties": { - "assets": { + "documents": { + "description": "List of contacts found", "items": { - "$ref": "#/components/schemas/UserAsset" + "$ref": "#/components/schemas/Contact_LTcwODE3Mjc5" }, "type": "array" }, - "description": { - "maxLength": 1024, - "minLength": 1, - "type": "string" + "found": { + "description": "Total number of hits", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" }, - "name": { - "maxLength": 128, - "minLength": 1, - "type": "string" + "has_more": { + "description": "Indicates whether there are more results to be fetched", + "type": "boolean" }, - "summary": { - "maxLength": 128, - "minLength": 1, - "type": "string" + "paging_state": { + "$ref": "#/components/schemas/PagingState" }, - "tags": { - "items": { - "$ref": "#/components/schemas/" - }, - "maxItems": 3, - "minItems": 1, - "type": "array" + "returned": { + "description": "Total number of hits returned", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "search_policy": { + "$ref": "#/components/schemas/FederatedUserSearchPolicy_MzkwODA4MTM3" + }, + "took": { + "description": "Search time in ms", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" } }, + "required": [ + "found", + "returned", + "took", + "documents", + "search_policy" + ], "type": "object" }, - "UpdateServiceConn": { + "SearchResult_TeamContact_LTE0NjQ0NzMw": { "properties": { - "auth_tokens": { + "documents": { + "description": "List of contacts found", "items": { - "$ref": "#/components/schemas/ASCII" + "$ref": "#/components/schemas/TeamContact_LTI5MTIxODc0" }, - "maxItems": 2, - "minItems": 1, "type": "array" }, - "base_url": { - "$ref": "#/components/schemas/HttpsUrl" + "found": { + "description": "Total number of hits", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" }, - "enabled": { + "has_more": { + "description": "Indicates whether there are more results to be fetched", "type": "boolean" }, - "password": { - "maxLength": 1024, - "minLength": 6, - "type": "string" + "paging_state": { + "$ref": "#/components/schemas/PagingState" }, - "public_keys": { - "items": { - "$ref": "#/components/schemas/ServiceKeyPEM" - }, - "maxItems": 2, - "minItems": 1, - "type": "array" + "returned": { + "description": "Total number of hits returned", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "search_policy": { + "$ref": "#/components/schemas/FederatedUserSearchPolicy_MzkwODA4MTM3" + }, + "took": { + "description": "Search time in ms", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" } }, "required": [ - "password" + "found", + "returned", + "took", + "documents", + "search_policy" ], "type": "object" }, - "UpdateServiceWhitelist": { + "SelfDeletingMessagesConfigB_Covered_Identity_LTY0NzQ4MzU1": { "properties": { - "id": { - "$ref": "#/components/schemas/UUID" + "enforcedTimeoutSeconds": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + } + }, + "required": [ + "enforcedTimeoutSeconds" + ], + "type": "object" + }, + "SendActivationCode_LTgyNDAxNzEy": { + "description": "Data for requesting an email code to be sent. 'email' must be present.", + "properties": { + "email": { + "$ref": "#/components/schemas/Email" }, - "provider": { - "$ref": "#/components/schemas/UUID" + "locale": { + "$ref": "#/components/schemas/Locale" + } + }, + "required": [ + "email" + ], + "type": "object" + }, + "SendVerificationCode_MjgxNDgxODE2": { + "properties": { + "action": { + "$ref": "#/components/schemas/VerificationAction_LTU0MzYxNzUz" }, - "whitelisted": { - "type": "boolean" + "email": { + "$ref": "#/components/schemas/Email" } }, "required": [ - "provider", - "id", - "whitelisted" + "action", + "email" ], "type": "object" }, - "User": { + "ServerTime_LTM4NTI3MzIx": { + "description": "The current server time", "properties": { - "accent_id": { + "time": { + "$ref": "#/components/schemas/UTCTime" + } + }, + "required": [ + "time" + ], + "type": "object" + }, + "ServiceKeyPEM": { + "example": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+Kg/PHHU3atXrUbKnw0\nG06FliXcNt3lMwl2os5twEDcPPFw/feGiAKymxp+7JqZDrseS5D9THGrW+OQRIPH\nWvUBdiLfGrZqJO223DB6D8K2Su/odmnjZJ2z23rhXoEArTplu+Dg9K+c2LVeXTKV\nVPOaOzgtAB21XKRiQ4ermqgi3/njr03rXyq/qNkuNd6tNcg+HAfGxfGvvCSYBfiS\nbUKr/BeArYRcjzr/h5m1In6fG/if9GEI6m8dxHT9JbY53wiksowy6ajCuqskIFg8\n7X883H+LA/d6X5CTiPv1VMxXdBUiGPuC9IT/6CNQ1/LFt0P37ax58+LGYlaFo7la\nnQIDAQAB\n-----END PUBLIC KEY-----\n", + "type": "string" + }, + "ServiceKeyType_NTEzNzI4NTA2": { + "enum": [ + "rsa" + ], + "type": "string" + }, + "ServiceKey_NzY5NTY5NzYy": { + "properties": { + "pem": { + "$ref": "#/components/schemas/ServiceKeyPEM" + }, + "size": { "format": "int32", "maximum": 2147483647, "minimum": -2147483648, "type": "integer" }, + "type": { + "$ref": "#/components/schemas/ServiceKeyType_NTEzNzI4NTA2" + } + }, + "required": [ + "type", + "size", + "pem" + ], + "type": "object" + }, + "ServiceProfilePage_Njg1NDQ5Njc4": { + "properties": { + "has_more": { + "type": "boolean" + }, + "services": { + "items": { + "$ref": "#/components/schemas/ServiceProfile_LTc2MDQzNTk3" + }, + "type": "array" + } + }, + "required": [ + "has_more", + "services" + ], + "type": "object" + }, + "ServiceProfile_LTc2MDQzNTk3": { + "properties": { "assets": { "items": { - "$ref": "#/components/schemas/UserAsset" + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" }, "type": "array" }, - "deleted": { - "type": "boolean" - }, - "email": { - "$ref": "#/components/schemas/Email" - }, - "expires_at": { - "$ref": "#/components/schemas/UTCTimeMillis" + "description": { + "type": "string" }, - "handle": { - "$ref": "#/components/schemas/Handle" + "enabled": { + "type": "boolean" }, "id": { "$ref": "#/components/schemas/UUID" }, - "locale": { - "$ref": "#/components/schemas/Locale" - }, - "managed_by": { - "$ref": "#/components/schemas/ManagedBy" - }, "name": { "maxLength": 128, "minLength": 1, "type": "string" }, - "picture": { - "$ref": "#/components/schemas/Pict" - }, - "qualified_id": { - "$ref": "#/components/schemas/Qualified_UserId" - }, - "service": { - "$ref": "#/components/schemas/ServiceRef" + "provider": { + "$ref": "#/components/schemas/UUID" }, - "sso_id": { - "$ref": "#/components/schemas/UserSSOId" + "summary": { + "type": "string" }, - "supported_protocols": { + "tags": { "items": { - "$ref": "#/components/schemas/BaseProtocol" + "$ref": "#/components/schemas/ServiceTag_LTMyNTEzNjYy" }, "type": "array" - }, - "team": { - "$ref": "#/components/schemas/UUID" - }, - "text_status": { - "maxLength": 256, - "minLength": 1, - "type": "string" } }, "required": [ - "qualified_id", + "id", + "provider", "name", - "accent_id", - "locale" + "summary", + "description", + "assets", + "tags", + "enabled" ], "type": "object" }, - "UserAsset": { + "ServiceRef_LTgxMjY3NzAz": { "properties": { - "key": { - "$ref": "#/components/schemas/AssetKey" - }, - "size": { - "$ref": "#/components/schemas/AssetSize" + "id": { + "$ref": "#/components/schemas/UUID" }, - "type": { - "$ref": "#/components/schemas/AssetType" + "provider": { + "$ref": "#/components/schemas/UUID" } }, "required": [ - "key", - "type" + "id", + "provider" ], "type": "object" }, - "UserClientMap": { - "additionalProperties": { - "additionalProperties": { - "type": "string" - }, - "type": "object" + "ServiceTagList": { + "items": { + "$ref": "#/components/schemas/ServiceTag_LTMyNTEzNjYy" }, - "type": "object" + "type": "array" }, - "UserClientPrekeyMap": { - "additionalProperties": { - "additionalProperties": { - "properties": { - "id": { - "maximum": 65535, - "minimum": 0, - "type": "integer" - }, - "key": { - "type": "string" - } + "ServiceTag_LTMyNTEzNjYy": { + "enum": [ + "audio", + "books", + "business", + "design", + "education", + "entertainment", + "finance", + "fitness", + "food-drink", + "games", + "graphics", + "health", + "integration", + "lifestyle", + "media", + "medical", + "movies", + "music", + "news", + "photography", + "poll", + "productivity", + "quiz", + "rating", + "shopping", + "social", + "sports", + "travel", + "tutorial", + "video", + "weather" + ], + "type": "string" + }, + "Service_MjcyOTA5NjQx": { + "properties": { + "assets": { + "items": { + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" }, - "required": [ - "id", - "key" - ], - "type": "object" + "type": "array" }, - "type": "object" - }, - "example": { - "1d51e2d6-9c70-605f-efc8-ff85c3dabdc7": { - "44901fb0712e588f": { - "id": 1, - "key": "pQABAQECoQBYIOjl7hw0D8YRNq..." - } + "auth_tokens": { + "items": { + "$ref": "#/components/schemas/ASCII" + }, + "minItems": 1, + "type": "array" + }, + "base_url": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "public_keys": { + "items": { + "$ref": "#/components/schemas/ServiceKey_NzY5NTY5NzYy" + }, + "minItems": 1, + "type": "array" + }, + "summary": { + "type": "string" + }, + "tags": { + "items": { + "$ref": "#/components/schemas/ServiceTag_LTMyNTEzNjYy" + }, + "type": "array" } }, + "required": [ + "id", + "name", + "summary", + "description", + "base_url", + "auth_tokens", + "public_keys", + "assets", + "tags", + "enabled" + ], "type": "object" }, - "UserClients": { - "additionalProperties": { - "items": { - "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", - "type": "string" - }, - "type": "array" - }, - "description": "Map of user id to list of client ids.", - "example": { - "1d51e2d6-9c70-605f-efc8-ff85c3dabdc7": [ - "60f85e4b15ad3786", - "6e323ab31554353b" - ] + "SetSearchable_NDAxODAxODI5": { + "properties": { + "set_searchable": { + "type": "boolean" + } }, + "required": [ + "set_searchable" + ], "type": "object" }, - "UserConnection": { + "SignedCertificate": { + "type": "string" + }, + "SimpleMember_NTY5MTcxMzcx": { "properties": { - "conversation": { - "$ref": "#/components/schemas/UUID" + "conversation_role": { + "$ref": "#/components/schemas/RoleName" }, - "from": { + "id": { "$ref": "#/components/schemas/UUID" }, - "last_update": { - "$ref": "#/components/schemas/UTCTimeMillis" - }, - "qualified_conversation": { - "$ref": "#/components/schemas/Qualified_ConvId" - }, - "qualified_to": { - "$ref": "#/components/schemas/Qualified_UserId" - }, - "status": { - "$ref": "#/components/schemas/Relation" + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + } + }, + "required": [ + "qualified_id" + ], + "type": "object" + }, + "SomeKey": {}, + "SomeUserToken": { + "type": "string" + }, + "SsoSettings": { + "properties": { + "default_sso_code": { + "$ref": "#/components/schemas/URI" + } + }, + "type": "object" + }, + "Sso_LTg1MDM5ODQ3": { + "properties": { + "issuer": { + "type": "string" }, - "to": { - "$ref": "#/components/schemas/UUID" + "nameid": { + "type": "string" } }, "required": [ - "from", - "qualified_to", - "status", - "last_update" + "issuer", + "nameid" ], "type": "object" }, - "UserIdList": { + "SupportedProtocolUpdate_LTE3Njk3MDM4": { "properties": { - "user_ids": { + "supported_protocols": { "items": { - "$ref": "#/components/schemas/UUID" + "$ref": "#/components/schemas/BaseProtocolTag_LTM0MDE1NTEx" }, "type": "array" } }, "required": [ - "user_ids" + "supported_protocols" ], "type": "object" }, - "UserLegalHoldStatus": { - "description": "The state of Legal Hold compliance for the member", - "enum": [ - "enabled", - "pending", - "disabled", - "no_consent" + "SystemSettingsPublic_LTgwNTMxNjU2": { + "properties": { + "nomadProfiles": { + "description": "Whether Nomad client profiles are enabled; null or absence means not enabled.", + "type": "boolean" + }, + "setRestrictUserCreation": { + "description": "Do not allow certain user creation flows", + "type": "boolean" + } + }, + "required": [ + "setRestrictUserCreation" ], - "type": "string" + "type": "object" }, - "UserLegalHoldStatusResponse": { + "SystemSettings_ODU3MDk5MTA3": { "properties": { - "client": { - "$ref": "#/components/schemas/Id" + "nomadProfiles": { + "description": "Whether Nomad client profiles are enabled; null or absence means not enabled.", + "type": "boolean" }, - "last_prekey": { - "$ref": "#/components/schemas/Prekey" + "setEnableMls": { + "description": "Whether MLS is enabled or not", + "type": "boolean" }, - "status": { - "$ref": "#/components/schemas/UserLegalHoldStatus" + "setRestrictUserCreation": { + "description": "Do not allow certain user creation flows", + "type": "boolean" } }, "required": [ - "status" + "setRestrictUserCreation", + "setEnableMls" ], "type": "object" }, - "UserMap_Set_PubClient": { - "additionalProperties": { - "items": { - "$ref": "#/components/schemas/PubClient" + "TeamBinding_LTE4NTM5MTc0": { + "deprecated": true, + "description": "Deprecated, please ignore.", + "enum": [ + true, + false + ], + "type": "boolean" + }, + "TeamCollaborator_LTI3MzM1MTYz": { + "properties": { + "permissions": { + "items": { + "$ref": "#/components/schemas/CollaboratorPermission_NDg5NTg2ODgy" + }, + "type": "array" }, - "type": "array", - "uniqueItems": true - }, - "description": "Map of UserId to (Set PubClient)", - "example": { - "1d51e2d6-9c70-605f-efc8-ff85c3dabdc7": [ - { - "class": "legalhold", - "id": "d0" - } - ] + "team": { + "$ref": "#/components/schemas/UUID" + }, + "user": { + "$ref": "#/components/schemas/UUID" + } }, + "required": [ + "user", + "team", + "permissions" + ], "type": "object" }, - "UserProfile": { + "TeamContact_LTI5MTIxODc0": { "properties": { "accent_id": { - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, "type": "integer" }, - "assets": { - "items": { - "$ref": "#/components/schemas/UserAsset" - }, - "type": "array" - }, - "deleted": { - "type": "boolean" + "created_at": { + "$ref": "#/components/schemas/UTCTimeMillis" }, "email": { "$ref": "#/components/schemas/Email" }, - "expires_at": { - "$ref": "#/components/schemas/UTCTimeMillis" + "email_unvalidated": { + "$ref": "#/components/schemas/Email" }, "handle": { - "$ref": "#/components/schemas/Handle" + "type": "string" }, "id": { "$ref": "#/components/schemas/UUID" }, - "legalhold_status": { - "$ref": "#/components/schemas/UserLegalHoldStatus" + "managed_by": { + "$ref": "#/components/schemas/ManagedBy_NTI0ODc0NTQx" }, "name": { - "maxLength": 128, - "minLength": 1, "type": "string" }, - "picture": { - "$ref": "#/components/schemas/Pict" + "role": { + "$ref": "#/components/schemas/Role_LTIzMjAzMjky" }, - "qualified_id": { - "$ref": "#/components/schemas/Qualified_UserId" + "saml_idp": { + "type": "string" }, - "service": { - "$ref": "#/components/schemas/ServiceRef" + "scim_external_id": { + "type": "string" }, - "supported_protocols": { - "items": { - "$ref": "#/components/schemas/BaseProtocol" - }, - "type": "array" + "searchable": { + "type": "boolean" + }, + "sso": { + "$ref": "#/components/schemas/Sso_LTg1MDM5ODQ3" }, "team": { "$ref": "#/components/schemas/UUID" }, - "text_status": { - "maxLength": 256, - "minLength": 1, - "type": "string" + "type": { + "$ref": "#/components/schemas/UserType_LTU1OTU4OTM5" + }, + "user_groups": { + "description": "List of user group ids the user is a member of", + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" } }, "required": [ - "qualified_id", + "id", + "type", "name", - "accent_id", - "legalhold_status" + "user_groups", + "searchable" ], "type": "object" }, - "UserSSOId": { - "properties": { - "scim_external_id": { - "type": "string" - }, - "subject": { - "type": "string" - }, - "tenant": { - "type": "string" - } - }, - "type": "object" - }, - "UserUpdate": { + "TeamConversationList_OTI3MzY3NzY0": { + "description": "Team conversation list", "properties": { - "accent_id": { - "format": "int32", - "maximum": 2147483647, - "minimum": -2147483648, - "type": "integer" - }, - "assets": { + "conversations": { "items": { - "$ref": "#/components/schemas/UserAsset" + "$ref": "#/components/schemas/TeamConversation_LTIwNzgyNTEz" }, "type": "array" - }, - "name": { - "maxLength": 128, - "minLength": 1, - "type": "string" - }, - "picture": { - "$ref": "#/components/schemas/Pict" - }, - "text_status": { - "maxLength": 256, - "minLength": 1, - "type": "string" } }, + "required": [ + "conversations" + ], "type": "object" }, - "ValidateSAMLEmailsConfig.LockableFeature": { + "TeamConversation_LTIwNzgyNTEz": { + "description": "Team conversation data", "properties": { - "lockStatus": { - "$ref": "#/components/schemas/LockStatus" - }, - "status": { - "$ref": "#/components/schemas/FeatureStatus" + "conversation": { + "$ref": "#/components/schemas/UUID" }, - "ttl": { - "example": "unlimited", - "maximum": 18446744073709551615, - "minimum": 0, - "type": "integer" + "managed": { + "description": "This field MUST NOT be used by clients. It is here only for backwards compatibility of the interface." } }, "required": [ - "status", - "lockStatus" + "conversation", + "managed" ], "type": "object" }, - "VerificationAction": { - "enum": [ - "create_scim_token", - "login", - "delete_team" - ], - "type": "string" - }, - "VerifyDeleteUser": { - "description": "Data for verifying an account deletion.", + "TeamDeleteData_ODI5NTU0ODE5": { "properties": { - "code": { - "$ref": "#/components/schemas/ASCII" + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" }, - "key": { + "verification_code": { "$ref": "#/components/schemas/ASCII" } }, - "required": [ - "key", - "code" - ], "type": "object" }, - "VersionInfo": { - "example": { - "development": [ - 7 - ], - "domain": "example.com", - "federation": false, - "supported": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7 - ] - }, + "TeamDomainRedirectTag_MjQwMjc1Mjk3": { + "enum": [ + "no-registration", + "none" + ], + "type": "string" + }, + "TeamInviteConfig_MTg4Nzk4NzMz": { "properties": { - "development": { - "items": { - "$ref": "#/components/schemas/VersionNumber" - }, - "type": "array" + "domain_redirect": { + "$ref": "#/components/schemas/TeamDomainRedirectTag_MjQwMjc1Mjk3" }, - "domain": { - "$ref": "#/components/schemas/Domain" + "sso": { + "example": "99db9768-04e3-4b5d-9268-831b6a25c4ab", + "format": "uuid", + "type": "string" }, - "federation": { - "type": "boolean" + "team": { + "$ref": "#/components/schemas/UUID" }, - "supported": { - "items": { - "$ref": "#/components/schemas/VersionNumber" - }, - "type": "array" + "team_invite": { + "$ref": "#/components/schemas/TeamInviteTag_LTQyNTMyNzA0" } }, "required": [ - "supported", - "development", - "federation", - "domain" + "team_invite", + "team" ], "type": "object" }, - "VersionNumber": { + "TeamInviteTag_LTQyNTMyNzA0": { "enum": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7 + "allowed", + "not-allowed", + "team" ], - "type": "integer" + "type": "string" + }, + "TeamMemberDeleteData_LTg2OTEyOTI4": { + "description": "Data for a team member deletion request in case of binding teams.", + "properties": { + "password": { + "description": "The account password to authorise the deletion.", + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "type": "object" }, - "ViewLegalHoldService": { + "TeamMemberList_Optional_LTM1ODE2MzM0": { + "description": "list of team member", "properties": { - "settings": { - "$ref": "#/components/schemas/ViewLegalHoldServiceInfo" + "hasMore": { + "$ref": "#/components/schemas/ListType_LTkyMDM4MzA1" }, - "status": { - "$ref": "#/components/schemas/LHServiceStatus" + "members": { + "description": "the array of team members", + "items": { + "$ref": "#/components/schemas/TeamMember_Optional_NTU0MDcyNzI1" + }, + "type": "array" } }, "required": [ - "status" + "members", + "hasMore" ], "type": "object" }, - "ViewLegalHoldServiceInfo": { + "TeamMember_Optional_NTU0MDcyNzI1": { + "description": "team member data", "properties": { - "auth_token": { - "$ref": "#/components/schemas/ASCII" + "created_at": { + "$ref": "#/components/schemas/UTCTimeMillis" }, - "base_url": { - "$ref": "#/components/schemas/HttpsUrl" + "created_by": { + "$ref": "#/components/schemas/UUID" }, - "fingerprint": { - "$ref": "#/components/schemas/Fingerprint" + "legalhold_status": { + "$ref": "#/components/schemas/UserLegalHoldStatus_LTQ2ODA2NTU5" }, - "public_key": { - "$ref": "#/components/schemas/ServiceKeyPEM" + "permissions": { + "$ref": "#/components/schemas/Permissions_NDE0ODM5NDUx" }, - "team_id": { + "user": { "$ref": "#/components/schemas/UUID" } }, "required": [ - "team_id", - "base_url", - "fingerprint", - "auth_token", - "public_key" + "user" ], "type": "object" }, - "WireIdP": { + "TeamMembersPage_NzYwNDIxODgx": { "properties": { - "apiVersion": { - "$ref": "#/components/schemas/WireIdPAPIVersion" - }, - "handle": { - "type": "string" + "hasMore": { + "type": "boolean" }, - "oldIssuers": { + "members": { "items": { - "type": "string" + "$ref": "#/components/schemas/TeamMember_Optional_NTU0MDcyNzI1" }, "type": "array" }, - "replacedBy": { - "$ref": "#/components/schemas/UUID" - }, - "team": { - "$ref": "#/components/schemas/UUID" + "pagingState": { + "$ref": "#/components/schemas/TeamMembers_PagingState" } }, "required": [ - "team", - "oldIssuers", - "handle" + "members", + "hasMore", + "pagingState" ], "type": "object" }, - "WireIdPAPIVersion": { - "enum": [ - "WireIdPAPIV1", - "WireIdPAPIV2" - ], + "TeamMembers_PagingState": { "type": "string" }, - "XmlText": { + "TeamSearchVisibilityView_Mzg3MzMzMTk3": { + "description": "Search visibility value for the team", "properties": { - "fromXmlText": { - "type": "string" + "search_visibility": { + "$ref": "#/components/schemas/TeamSearchVisibility_LTIzODE2Njk3" } }, "required": [ - "fromXmlText" + "search_visibility" ], "type": "object" }, - "new-otr-message": { - "properties": { - "data": { - "type": "string" - }, - "native_priority": { - "$ref": "#/components/schemas/Priority" + "TeamSearchVisibility_LTIzODE2Njk3": { + "description": "value of visibility", + "enum": [ + "standard", + "no-name-outside-team" + ], + "type": "string" + }, + "TeamSize_LTMzMzk2MTk1": { + "description": "Team member counts broken down by user type.", + "properties": { + "teamSize": { + "description": "Total team members (teamSizeRegulars + teamSizeApps).", + "exclusiveMinimum": false, + "minimum": 0, + "type": "integer" }, - "native_push": { + "teamSizeApps": { + "description": "Number of apps in team.", + "exclusiveMinimum": false, + "minimum": 0, + "type": "integer" + }, + "teamSizeRegulars": { + "description": "Number of regular users in team.", + "exclusiveMinimum": false, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "teamSizeRegulars", + "teamSizeApps" + ], + "type": "object" + }, + "TeamUpdateData_LTE0NTM2NTU5": { + "properties": { + "icon": { + "$ref": "#/components/schemas/Icon" + }, + "icon_key": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "name": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "splash_screen": { + "$ref": "#/components/schemas/Icon" + } + }, + "type": "object" + }, + "Team_NDg4MjQwOTIw": { + "description": "`binding` is deprecated, and should be ignored. The non-binding teams API is not used (and will not be supported from API version V4 onwards), and `binding` will always be `true`.", + "properties": { + "binding": { + "$ref": "#/components/schemas/TeamBinding_LTE4NTM5MTc0" + }, + "creator": { + "$ref": "#/components/schemas/UUID" + }, + "icon": { + "$ref": "#/components/schemas/Icon" + }, + "icon_key": { + "type": "string" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "name": { + "type": "string" + }, + "splash_screen": { + "$ref": "#/components/schemas/Icon" + } + }, + "required": [ + "id", + "creator", + "name", + "icon" + ], + "type": "object" + }, + "Time": { + "properties": { + "time": { + "$ref": "#/components/schemas/UTCTime" + } + }, + "required": [ + "time" + ], + "type": "object" + }, + "TimeZone": { + "type": "string" + }, + "Token": { + "example": "ZXhhbXBsZQo=", + "type": "string" + }, + "TokenType_NTkyMzk4MjIz": { + "enum": [ + "Bearer" + ], + "type": "string" + }, + "Transport_NDk2NzU5NDIy": { + "description": "Transport", + "enum": [ + "GCM", + "APNS", + "APNS_SANDBOX", + "APNS_VOIP", + "APNS_VOIP_SANDBOX" + ], + "type": "string" + }, + "TurnURI": { + "type": "string" + }, + "TurnUsername": { + "description": "Username to use for authenticating against the given TURN servers", + "type": "string" + }, + "TypingStatus_LTg5MzcyNDMy": { + "enum": [ + "started", + "stopped" + ], + "type": "string" + }, + "URI": { + "type": "string" + }, + "URIRef_Absolute": { + "description": "URL of the invitation link to be sent to the invitee", + "type": "string" + }, + "UTCTime": { + "example": "2021-05-12T10:52:02Z", + "format": "yyyy-mm-ddThh:MM:ssZ", + "type": "string" + }, + "UTCTimeMillis": { + "description": "The time when the session was created", + "example": "2021-05-12T10:52:02.671Z", + "format": "yyyy-mm-ddThh:MM:ss.qqqZ", + "type": "string" + }, + "UUID": { + "description": "The OAuth client's ID", + "example": "99db9768-04e3-4b5d-9268-831b6a25c4ab", + "format": "uuid", + "type": "string" + }, + "UncheckedPrekeyBundle_LTU1MzQzOTgy": { + "properties": { + "id": { + "maximum": 65535, + "minimum": 0, + "type": "integer" + }, + "key": { + "type": "string" + } + }, + "required": [ + "id", + "key" + ], + "type": "object" + }, + "UpdateBotPrekeys_LTg3NzYxODg0": { + "properties": { + "prekeys": { + "items": { + "$ref": "#/components/schemas/UncheckedPrekeyBundle_LTU1MzQzOTgy" + }, + "type": "array" + } + }, + "required": [ + "prekeys" + ], + "type": "object" + }, + "UpdateClient_NzU5MjA4MzI1": { + "properties": { + "capabilities": { + "$ref": "#/components/schemas/ClientCapabilityList" + }, + "label": { + "description": "A new name for this client.", + "type": "string" + }, + "lastkey": { + "$ref": "#/components/schemas/UncheckedPrekeyBundle_LTU1MzQzOTgy" + }, + "mls_public_keys": { + "$ref": "#/components/schemas/MLSPublicKeys" + }, + "prekeys": { + "description": "New prekeys for other clients to establish OTR sessions.", + "items": { + "$ref": "#/components/schemas/UncheckedPrekeyBundle_LTU1MzQzOTgy" + }, + "type": "array" + } + }, + "type": "object" + }, + "UpdateMeeting_NTExNzYxMTcz": { + "description": "Request to update a meeting", + "properties": { + "end_time": { + "$ref": "#/components/schemas/UTCTime" + }, + "recurrence": { + "$ref": "#/components/schemas/Recurrence_LTQ0OTc0ODE2" + }, + "start_time": { + "$ref": "#/components/schemas/UTCTime" + }, + "title": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "tzid": { + "$ref": "#/components/schemas/TimeZone" + } + }, + "type": "object" + }, + "UpdateProvider_LTQwMjY4MDgy": { + "properties": { + "description": { + "type": "string" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "url": { + "$ref": "#/components/schemas/HttpsUrl" + } + }, + "type": "object" + }, + "UpdateServiceConn_LTQ1OTYwNjIz": { + "properties": { + "auth_tokens": { + "items": { + "$ref": "#/components/schemas/ASCII" + }, + "maxItems": 2, + "minItems": 1, + "type": "array" + }, + "base_url": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "enabled": { "type": "boolean" }, - "recipients": { - "$ref": "#/components/schemas/UserClientMap" + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" }, - "report_missing": { + "public_keys": { + "items": { + "$ref": "#/components/schemas/ServiceKeyPEM" + }, + "maxItems": 2, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "password" + ], + "type": "object" + }, + "UpdateServiceWhitelist_LTU5MDAwMTIw": { + "properties": { + "id": { + "$ref": "#/components/schemas/UUID" + }, + "provider": { + "$ref": "#/components/schemas/UUID" + }, + "whitelisted": { + "type": "boolean" + } + }, + "required": [ + "provider", + "id", + "whitelisted" + ], + "type": "object" + }, + "UpdateService_MjAxNzQ2Njkz": { + "properties": { + "assets": { + "items": { + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" + }, + "type": "array" + }, + "description": { + "maxLength": 1024, + "minLength": 1, + "type": "string" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "summary": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "tags": { + "items": { + "$ref": "#/components/schemas/ServiceTag_LTMyNTEzNjYy" + }, + "maxItems": 3, + "minItems": 1, + "type": "array" + } + }, + "type": "object" + }, + "UpdateUserGroupChannels_LTIyMjcwMTMx": { + "properties": { + "channels": { + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + } + }, + "required": [ + "channels" + ], + "type": "object" + }, + "UpdateUserGroupMembers_LTg1MzQ2NDY3": { + "properties": { + "members": { "items": { "$ref": "#/components/schemas/UUID" }, "type": "array" + } + }, + "required": [ + "members" + ], + "type": "object" + }, + "UserClientMap": { + "additionalProperties": { + "additionalProperties": { + "type": "string" }, - "sender": { + "type": "object" + }, + "type": "object" + }, + "UserClientPrekeyMap": { + "additionalProperties": { + "additionalProperties": { + "properties": { + "id": { + "maximum": 65535, + "minimum": 0, + "type": "integer" + }, + "key": { + "type": "string" + } + }, + "required": [ + "id", + "key" + ], + "type": "object" + }, + "type": "object" + }, + "example": { + "1d51e2d6-9c70-605f-efc8-ff85c3dabdc7": { + "44901fb0712e588f": { + "id": 1, + "key": "pQABAQECoQBYIOjl7hw0D8YRNq..." + } + } + }, + "type": "object" + }, + "UserClients": { + "additionalProperties": { + "items": { "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", "type": "string" }, - "transient": { + "type": "array" + }, + "description": "Map of user id to list of client ids.", + "example": { + "1d51e2d6-9c70-605f-efc8-ff85c3dabdc7": [ + "60f85e4b15ad3786", + "6e323ab31554353b" + ] + }, + "type": "object" + }, + "UserConnection_LTY3NzU1ODg0": { + "properties": { + "conversation": { + "$ref": "#/components/schemas/UUID" + }, + "from": { + "$ref": "#/components/schemas/UUID" + }, + "last_update": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "qualified_conversation": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "qualified_to": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "status": { + "$ref": "#/components/schemas/Relation_LTE4OTU5MTk4" + }, + "to": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "from", + "qualified_to", + "status", + "last_update" + ], + "type": "object" + }, + "UserGroupAddUsers_LTgzOTYzNzk0": { + "properties": { + "members": { + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + } + }, + "required": [ + "members" + ], + "type": "object" + }, + "UserGroupNameAvailability_LTYzMDE1NTk4": { + "properties": { + "name_available": { "type": "boolean" } }, "required": [ - "sender", - "recipients" + "name_available" ], "type": "object" - } - }, - "securitySchemes": { - "ZAuth": { - "description": "Must be a token retrieved by calling 'POST /login' or 'POST /access'. It must be presented in this format: 'Bearer \\'.", - "in": "header", - "name": "Authorization", - "type": "apiKey" - } - } - }, - "info": { - "description": "## Authentication / Authorization\n\nThe end-points in this API support differing authorization protocols:\nsome are unauthenticated (`/api-version`, `/login`), some require\n[zauth](), and some support both [zauth]() and [oauth]().\n\nThe end-points that require zauth are labelled so in the description\nbelow. The end-points that support oauth as an alternative to zauth\nhave the required oauth scopes listed in the same description.\n\nFuther reading:\n- https://docs.wire.com/developer/reference/oauth.html\n- https://github.com/wireapp/wire-server/blob/develop/libs/wire-api/src/Wire/API/Routes/Public.hs (search for HasSwagger instances)\n- `curl https://staging-nginz-https.zinfra.io/v4/api/swagger.json | jq '.security, .securityDefinitions`\n\n### SSO Endpoints\n\n#### Overview\n\n`/sso/metadata` will be requested by the IdPs to learn how to talk to wire.\n\n`/sso/initiate-login`, `/sso/finalize-login` are for the SAML authentication handshake performed by a user in order to log into wire. They are not exactly standard in their details: they may return HTML or XML; redirect to error URLs instead of throwing errors, etc.\n\n`/identity-providers` end-points are for use in the team settings page when IdPs are registered. They talk json.\n\n\n#### Configuring IdPs\n\nIdPs usually allow you to copy the metadata into your clipboard. That should contain all the details you need to post the idp in your team under `/identity-providers`. (Team id is derived from the authorization credentials of the request.)\n\n##### okta.com\n\nOkta will ask you to provide two URLs when you set it up for talking to wireapp:\n\n1. The `Single sign on URL`. This is the end-point that accepts the user's credentials after successful authentication against the IdP. Choose `/sso/finalize-login` with schema and hostname of the wire server you are configuring.\n\n2. The `Audience URI`. You can find this in the metadata returned by the `/sso/metadata` end-point. It is the contents of the `md:OrganizationURL` element.\n\n##### centrify.com\n\nCentrify allows you to upload the metadata xml document that you get from the `/sso/metadata` end-point. You can also enter the metadata url and have centrify retrieve the xml, but to guarantee integrity of the setup, the metadata should be copied from the team settings page and pasted into the centrify setup page without any URL indirections.\n\n## Federation errors\n\nEndpoints involving federated calls to other domains can return some extra failure responses, common to all endpoints. Instead of listing them as possible responses for each endpoint, we document them here.\n\nFor errors that are more likely to be transient, we suggest clients to retry whatever request resulted in the error. Transient errors are indicated explicitly below.\n\n**Note**: when a failure occurs as a result of making a federated RPC to another backend, the error response contains the following extra fields:\n\n - `type`: \"federation\" (just the literal string in quotes, which can be used as an error type identifier when parsing errors)\n - `domain`: the target backend of the RPC that failed;\n - `path`: the path of the RPC that failed.\n\n### Domain errors\n\nErrors in this category result from trying to communicate with a backend that is considered non-existent or invalid. They can result from invalid user input or client issues, but they can also be a symptom of misconfiguration in one or multiple backends. These errors have a 4xx status code.\n\n - **Remote backend not found** (status: 422, label: `invalid-domain`): This backend attempted to contact a backend which does not exist or is not properly configured. For the most part, clients can consider this error equivalent to a domain not existing, although it should be noted that certain mistakes in the DNS configuration on a remote backend can lead to the backend not being recognized, and hence to this error. It is therefore not advisable to take any destructive action upon encountering this error, such as deleting remote users from conversations.\n - **Federation denied locally** (status: 400, label: `federation-denied`): This backend attempted an RPC to a non-whitelisted backend. Similar considerations as for the previous error apply.\n - **Federation not enabled** (status: 400, label: `federation-not-enabled`): Federation has not been configured for this backend. This will happen if a federation-aware client tries to talk to a backend for which federation is disabled, or if federation was disabled on the backend after reaching a federation-specific state (e.g. conversations with remote users). There is no way to cleanly recover from these errors at this point.\n\n### Local federation errors\n\nAn error in this category likely indicates an issue with the configuration of federation on the local backend. Possibly transient errors are indicated explicitly below. All these errors have a 500 status code.\n\n - **Federation unavailable** (status: 500, label: `federation-not-available`): Federation is configured for this backend, but the local federator cannot be reached. This can be transient, so clients should retry the request.\n - **Federation not implemented** (status: 500, label: `federation-not-implemented`): Federated behaviour for a certain endpoint is not yet implemented.\n - **Federator discovery failed** (status: 400, label: `discovery-failure`): A DNS error occurred during discovery of a remote backend. This can be transient, so clients should retry the request.\n - **Local federation error** (status: 500, label: `federation-local-error`): An error occurred in the communication between this backend and its local federator. These errors are most likely caused by bugs in the backend, and should be reported as such.\n\n### Remote federation errors\n\nErrors in this category are returned in case of communication issues between the local backend and a remote one, or if the remote side encountered an error while processing an RPC. Some errors in this category might be caused by incorrect client behaviour, wrong user input, or incorrect certificate configuration. Possibly transient errors are indicated explicitly. We use non-standard 5xx status codes for these errors.\n\n - **HTTP2 error** (status: 533, label: `federation-http2-error`): The current federator encountered an error when making an HTTP2 request to a remote one. Check the error message for more details.\n - **Connection refused** (status: 521, label: `federation-connection-refused`): The local federator could not connect to a remote one. This could be transient, so clients should retry the request.\n - **TLS failure**: (status: 525, label: `federation-tls-error`): An error occurred during the TLS handshake between the local federator and a remote one. This is most likely due to an issue with the certificate on the remote end.\n - **Remote federation error** (status: 533, label: `federation-remote-error`): The remote backend could not process a request coming from this backend. Check the error message for more details.\n - **Version negotiation error** (status: 533, label: `federation-version-error`): The remote backend returned invalid version information.\n\n### Backend compatibility errors\n\nAn error in this category will be returned when this backend makes an invalid or unsupported RPC to another backend. This can indicate some incompatibility between backends or a backend bug. These errors are unlikely to be transient, so retrying requests is *not* advised.\n\n - **Version mismatch** (status: 531, label: `federation-version-mismatch`): A remote backend is running an unsupported version of the federator.\n - **Invalid content type** (status: 533, label: `federation-invalid-content-type`): An RPC to another backend returned with an invalid content type.\n - **Unsupported content type** (status: 533, label: `federation-unsupported-content-type`): An RPC to another backend returned with an unsupported content type.\n", - "title": "Wire-Server API", - "version": "" - }, - "openapi": "3.0.0", - "paths": { - "/": { - "get": { - "description": " [internal route ID: \"get-services-tags\"]\n\n", + }, + "UserGroupPage_UserGroup_Const_LTMxNDg5MDAy": { + "description": "This is the last page if it contains fewer rows than requested. There may be 0 rows on a page.", + "properties": { + "page": { + "items": { + "$ref": "#/components/schemas/UserGroup_Const_NTMzOTAzMzA1" + }, + "type": "array" + }, + "total": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + } + }, + "required": [ + "page", + "total" + ], + "type": "object" + }, + "UserGroupUpdate_MjUyNTA3Mjgy": { + "properties": { + "name": { + "maxLength": 4000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "UserGroup_Const_NTMzOTAzMzA1": { + "properties": { + "channels": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "type": "array" + }, + "channelsCount": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "createdAt": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "managedBy": { + "$ref": "#/components/schemas/ManagedBy_NTI0ODc0NTQx" + }, + "membersCount": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "maxLength": 4000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "id", + "name", + "managedBy", + "createdAt" + ], + "type": "object" + }, + "UserGroup_Identity_NTg4MTY1MjEx": { + "properties": { + "channels": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "type": "array" + }, + "channelsCount": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "createdAt": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "managedBy": { + "$ref": "#/components/schemas/ManagedBy_NTI0ODc0NTQx" + }, + "members": { + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + }, + "membersCount": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "maxLength": 4000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "id", + "name", + "members", + "managedBy", + "createdAt" + ], + "type": "object" + }, + "UserIdList_MzA1MTI1Njgx": { + "properties": { + "user_ids": { + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + } + }, + "required": [ + "user_ids" + ], + "type": "object" + }, + "UserLegalHoldStatusResponse_LTQ1MzUxMTE3": { + "properties": { + "client": { + "$ref": "#/components/schemas/IdObject_ClientId_LTM3NjQyODM5" + }, + "last_prekey": { + "$ref": "#/components/schemas/UncheckedPrekeyBundle_LTU1MzQzOTgy" + }, + "status": { + "$ref": "#/components/schemas/UserLegalHoldStatus_LTQ2ODA2NTU5" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "UserLegalHoldStatus_LTQ2ODA2NTU5": { + "description": "The state of Legal Hold compliance for the member", + "enum": [ + "enabled", + "pending", + "disabled", + "no_consent" + ], + "type": "string" + }, + "UserMap_Set_PubClient": { + "additionalProperties": { + "items": { + "$ref": "#/components/schemas/PubClient" + }, + "type": "array", + "uniqueItems": true + }, + "description": "Map of UserId to (Set PubClient)", + "example": { + "1d51e2d6-9c70-605f-efc8-ff85c3dabdc7": [ + { + "class": "legalhold", + "id": "d0" + } + ] + }, + "type": "object" + }, + "UserProfile_LTQzMTQxMTE1": { + "properties": { + "accent_id": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "app": { + "$ref": "#/components/schemas/AppInfo_MjgwNTkwOTUz" + }, + "assets": { + "items": { + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" + }, + "type": "array" + }, + "contact_status": { + "$ref": "#/components/schemas/ContactStatus_LTUzNzk1MzM4" + }, + "deleted": { + "type": "boolean" + }, + "email": { + "$ref": "#/components/schemas/Email" + }, + "expires_at": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "handle": { + "$ref": "#/components/schemas/Handle" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "legalhold_status": { + "$ref": "#/components/schemas/UserLegalHoldStatus_LTQ2ODA2NTU5" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "picture": { + "$ref": "#/components/schemas/Pict_DEPRECATED_USE_ASSETS_INSTEAD" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "searchable": { + "type": "boolean" + }, + "service": { + "$ref": "#/components/schemas/ServiceRef_LTgxMjY3NzAz" + }, + "supported_protocols": { + "items": { + "$ref": "#/components/schemas/BaseProtocolTag_LTM0MDE1NTEx" + }, + "type": "array" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "text_status": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "type": { + "$ref": "#/components/schemas/UserType_LTU1OTU4OTM5" + } + }, + "required": [ + "qualified_id", + "name", + "accent_id", + "legalhold_status" + ], + "type": "object" + }, + "UserSSOId": { + "properties": { + "scim_external_id": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "tenant": { + "type": "string" + } + }, + "type": "object" + }, + "UserType_LTU1OTU4OTM5": { + "enum": [ + "regular", + "app", + "bot" + ], + "type": "string" + }, + "UserUpdate_MjQ4NTEwOTQz": { + "properties": { + "accent_id": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "assets": { + "items": { + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" + }, + "type": "array" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "picture": { + "$ref": "#/components/schemas/Pict_DEPRECATED_USE_ASSETS_INSTEAD" + }, + "text_status": { + "maxLength": 256, + "minLength": 1, + "type": "string" + } + }, + "type": "object" + }, + "User_NjA4OTQwMTQ4": { + "properties": { + "accent_id": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "assets": { + "items": { + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" + }, + "type": "array" + }, + "deleted": { + "type": "boolean" + }, + "email": { + "$ref": "#/components/schemas/Email" + }, + "email_unvalidated": { + "$ref": "#/components/schemas/Email" + }, + "expires_at": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "handle": { + "$ref": "#/components/schemas/Handle" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "locale": { + "$ref": "#/components/schemas/Locale" + }, + "managed_by": { + "$ref": "#/components/schemas/ManagedBy_NTI0ODc0NTQx" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "picture": { + "$ref": "#/components/schemas/Pict_DEPRECATED_USE_ASSETS_INSTEAD" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "searchable": { + "type": "boolean" + }, + "service": { + "$ref": "#/components/schemas/ServiceRef_LTgxMjY3NzAz" + }, + "sso_id": { + "$ref": "#/components/schemas/UserSSOId" + }, + "status": { + "$ref": "#/components/schemas/AccountStatus_NzkzNDU1ODU5" + }, + "supported_protocols": { + "items": { + "$ref": "#/components/schemas/BaseProtocolTag_LTM0MDE1NTEx" + }, + "type": "array" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "text_status": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "type": { + "$ref": "#/components/schemas/UserType_LTU1OTU4OTM5" + } + }, + "required": [ + "qualified_id", + "type", + "name", + "accent_id", + "status", + "locale" + ], + "type": "object" + }, + "VerificationAction_LTU0MzYxNzUz": { + "enum": [ + "create_scim_token", + "login", + "delete_team" + ], + "type": "string" + }, + "VerifyDeleteUser_Njc1NDQ1MDIy": { + "description": "Data for verifying an account deletion.", + "properties": { + "code": { + "$ref": "#/components/schemas/ASCII" + }, + "key": { + "$ref": "#/components/schemas/ASCII" + } + }, + "required": [ + "key", + "code" + ], + "type": "object" + }, + "VersionInfo_NTEzMTgzNDQ0": { + "example": { + "development": [ + 18 + ], + "domain": "example.com", + "federation": false, + "supported": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18 + ] + }, + "properties": { + "development": { + "items": { + "$ref": "#/components/schemas/VersionNumber_Njk2NzI5Njk1" + }, + "type": "array" + }, + "domain": { + "$ref": "#/components/schemas/Domain" + }, + "federation": { + "type": "boolean" + }, + "supported": { + "items": { + "$ref": "#/components/schemas/VersionNumber_Njk2NzI5Njk1" + }, + "type": "array" + } + }, + "required": [ + "supported", + "development", + "federation", + "domain" + ], + "type": "object" + }, + "VersionNumber_Njk2NzI5Njk1": { + "enum": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18 + ], + "type": "integer" + }, + "Versiond_16_PvtAmlGupCfgBaIy_NDc4OTU0NTE3": { + "properties": { + "deletionTimeout": { + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "promotionStrategy": { + "$ref": "#/components/schemas/PreventAdminlessGroupsPromotionStrategy_Mjc1ODA2MDU1" + }, + "reminderTimeouts": { + "items": { + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "type": "array" + } + }, + "required": [ + "promotionStrategy", + "deletionTimeout", + "reminderTimeouts" + ], + "type": "object" + }, + "ViewLegalHoldServiceInfo_LTc3NjI2MzQ3": { + "properties": { + "auth_token": { + "$ref": "#/components/schemas/ASCII" + }, + "base_url": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "fingerprint": { + "$ref": "#/components/schemas/Fingerprint" + }, + "public_key": { + "$ref": "#/components/schemas/ServiceKeyPEM" + }, + "team_id": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "team_id", + "base_url", + "fingerprint", + "auth_token", + "public_key" + ], + "type": "object" + }, + "ViewLegalHoldService_LTE3MzQzNDkw": { + "properties": { + "settings": { + "$ref": "#/components/schemas/ViewLegalHoldServiceInfo_LTc3NjI2MzQ3" + }, + "status": { + "$ref": "#/components/schemas/LHServiceStatus_ODc3NzE0Mjg3" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "WireIdPAPIVersion_NTEyMzIwNTU3": { + "enum": [ + "WireIdPAPIV1", + "WireIdPAPIV2" + ], + "type": "string" + }, + "WireIdP_ODMzOTExMzYw": { + "properties": { + "apiVersion": { + "enum": [ + "WireIdPAPIV1", + "WireIdPAPIV2" + ], + "type": "string" + }, + "domain": { + "example": "example.com", + "type": "string" + }, + "handle": { + "type": "string" + }, + "oldIssuers": { + "items": { + "$ref": "#/components/schemas/URI" + }, + "type": "array" + }, + "replacedBy": { + "type": "string" + }, + "team": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "team", + "apiVersion", + "oldIssuers", + "replacedBy", + "handle", + "domain" + ], + "type": "object" + }, + "v2_ConversationAccessData_MjMxMTI5ODc3": { + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "$ref": "#/components/schemas/AccessRoleLegacy_LTYwOTAxMDI1" + }, + "access_role_v2": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + } + }, + "required": [ + "access" + ], + "type": "object" + }, + "v2_OwnConversation_GroupConvTypeLegacy_MjQ0OTcyNjQ3": { + "description": "A conversation object as returned from the server", + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "$ref": "#/components/schemas/AccessRoleLegacy_LTYwOTAxMDI1" + }, + "access_role_v2": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" + }, + "cipher_suite": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "creator": { + "$ref": "#/components/schemas/UUID" + }, + "epoch": { + "description": "The epoch number of the corresponding MLS group", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "epoch_timestamp": { + "$ref": "#/components/schemas/EpochTimestamp" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvTypeLegacy_NTUxMDI2Mzkw" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "history": { + "$ref": "#/components/schemas/History" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "last_event": { + "type": "string" + }, + "last_event_time": { + "type": "string" + }, + "members": { + "$ref": "#/components/schemas/OwnConvMembers_LTEwMzUzODMy" + }, + "message_timer": { + "description": "Per-conversation message timer (can be null)", + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "type": "string" + }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, + "protocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "receipt_mode": { + "description": "Conversation receipt mode", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "type": { + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" + } + }, + "required": [ + "qualified_id", + "type", + "access", + "members", + "group_id", + "epoch", + "epoch_timestamp", + "cipher_suite" + ], + "type": "object" + }, + "v2_OwnConversation_GroupConvType_LTU2MzYxNTg0": { + "description": "A conversation object as returned from the server", + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "$ref": "#/components/schemas/AccessRoleLegacy_LTYwOTAxMDI1" + }, + "access_role_v2": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" + }, + "cipher_suite": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "creator": { + "$ref": "#/components/schemas/UUID" + }, + "epoch": { + "description": "The epoch number of the corresponding MLS group", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "epoch_timestamp": { + "$ref": "#/components/schemas/EpochTimestamp" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "history": { + "$ref": "#/components/schemas/History" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "last_event": { + "type": "string" + }, + "last_event_time": { + "type": "string" + }, + "members": { + "$ref": "#/components/schemas/OwnConvMembers_LTEwMzUzODMy" + }, + "message_timer": { + "description": "Per-conversation message timer (can be null)", + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "type": "string" + }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, + "protocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "receipt_mode": { + "description": "Conversation receipt mode", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "type": { + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" + } + }, + "required": [ + "qualified_id", + "type", + "access", + "members", + "group_id", + "epoch", + "epoch_timestamp", + "cipher_suite" + ], + "type": "object" + }, + "v3_OwnConversation_GroupConvType_LTU2MzYxNTg0V3": { + "description": "A conversation object as returned from the server", + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" + }, + "cipher_suite": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "creator": { + "$ref": "#/components/schemas/UUID" + }, + "epoch": { + "description": "The epoch number of the corresponding MLS group", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "epoch_timestamp": { + "$ref": "#/components/schemas/EpochTimestamp" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "history": { + "$ref": "#/components/schemas/History" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "last_event": { + "type": "string" + }, + "last_event_time": { + "type": "string" + }, + "members": { + "$ref": "#/components/schemas/OwnConvMembers_LTEwMzUzODMy" + }, + "message_timer": { + "description": "Per-conversation message timer (can be null)", + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "type": "string" + }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, + "protocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "receipt_mode": { + "description": "Conversation receipt mode", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "type": { + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" + } + }, + "required": [ + "qualified_id", + "type", + "access", + "access_role", + "members", + "group_id", + "epoch", + "epoch_timestamp", + "cipher_suite" + ], + "type": "object" + }, + "v6_OwnConversation_GroupConvType_LTU2MzYxNTg0V6": { + "description": "A conversation object as returned from the server", + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" + }, + "cipher_suite": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "creator": { + "$ref": "#/components/schemas/UUID" + }, + "epoch": { + "description": "The epoch number of the corresponding MLS group", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "epoch_timestamp": { + "$ref": "#/components/schemas/UTCTime" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "history": { + "$ref": "#/components/schemas/History" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "last_event": { + "type": "string" + }, + "last_event_time": { + "type": "string" + }, + "members": { + "$ref": "#/components/schemas/OwnConvMembers_LTEwMzUzODMy" + }, + "message_timer": { + "description": "Per-conversation message timer (can be null)", + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "type": "string" + }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, + "protocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "receipt_mode": { + "description": "Conversation receipt mode", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "type": { + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" + } + }, + "required": [ + "qualified_id", + "type", + "access", + "access_role", + "members", + "group_id", + "epoch" + ], + "type": "object" + }, + "v9_OwnConversation_GroupConvType_LTU2MzYxNTg0": { + "description": "A conversation object as returned from the server", + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" + }, + "cipher_suite": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "creator": { + "$ref": "#/components/schemas/UUID" + }, + "epoch": { + "description": "The epoch number of the corresponding MLS group", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "epoch_timestamp": { + "$ref": "#/components/schemas/UTCTime" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "history": { + "$ref": "#/components/schemas/History" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "last_event": { + "type": "string" + }, + "last_event_time": { + "type": "string" + }, + "members": { + "$ref": "#/components/schemas/OwnConvMembers_LTEwMzUzODMy" + }, + "message_timer": { + "description": "Per-conversation message timer (can be null)", + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "type": "string" + }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, + "protocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "receipt_mode": { + "description": "Conversation receipt mode", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "type": { + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" + } + }, + "required": [ + "qualified_id", + "type", + "access", + "access_role", + "members", + "group_id", + "epoch" + ], + "type": "object" + } + }, + "securitySchemes": { + "ZAuth": { + "description": "Must be a token retrieved by calling 'POST /login' or 'POST /access'. It must be presented in this format: 'Bearer \\'.", + "in": "header", + "name": "Authorization", + "type": "apiKey" + } + } + }, + "info": { + "description": "## Authentication / Authorization\n\nThe end-points in this API support differing authorization protocols:\nsome are unauthenticated (`/api-version`, `/login`), some require\n[zauth](), and some support both [zauth]() and [oauth]().\n\nThe end-points that require zauth are labelled so in the description\nbelow. The end-points that support oauth as an alternative to zauth\nhave the required oauth scopes listed in the same description.\n\nFuther reading:\n- https://docs.wire.com/developer/reference/oauth.html\n- https://github.com/wireapp/wire-server/blob/develop/libs/wire-api/src/Wire/API/Routes/Public.hs (search for HasSwagger instances)\n- `curl https://staging-nginz-https.zinfra.io/v4/api/swagger.json | jq '.security, .securityDefinitions`\n\n### SSO Endpoints\n\n#### Overview\n\n`/sso/metadata` will be requested by the IdPs to learn how to talk to wire.\n\n`/sso/initiate-login`, `/sso/finalize-login` are for the SAML authentication handshake performed by a user in order to log into wire. They are not exactly standard in their details: they may return HTML or XML; redirect to error URLs instead of throwing errors, etc.\n\n`/identity-providers` end-points are for use in the team settings page when IdPs are registered. They talk json.\n\n\n#### Configuring IdPs\n\nIdPs usually allow you to copy the metadata into your clipboard. That should contain all the details you need to post the idp in your team under `/identity-providers`. (Team id is derived from the authorization credentials of the request.)\n\n##### okta.com\n\nOkta will ask you to provide two URLs when you set it up for talking to wireapp:\n\n1. The `Single sign on URL`. This is the end-point that accepts the user's credentials after successful authentication against the IdP. Choose `/sso/finalize-login` with schema and hostname of the wire server you are configuring.\n\n2. The `Audience URI`. You can find this in the metadata returned by the `/sso/metadata` end-point. It is the contents of the `md:OrganizationURL` element.\n\n##### centrify.com\n\nCentrify allows you to upload the metadata xml document that you get from the `/sso/metadata` end-point. You can also enter the metadata url and have centrify retrieve the xml, but to guarantee integrity of the setup, the metadata should be copied from the team settings page and pasted into the centrify setup page without any URL indirections.\n\n## Federation errors\n\nEndpoints involving federated calls to other domains can return some extra failure responses, common to all endpoints. Instead of listing them as possible responses for each endpoint, we document them here.\n\nFor errors that are more likely to be transient, we suggest clients to retry whatever request resulted in the error. Transient errors are indicated explicitly below.\n\n**Note**: when a failure occurs as a result of making a federated RPC to another backend, the error response contains the following extra fields:\n\n - `type`: \"federation\" (just the literal string in quotes, which can be used as an error type identifier when parsing errors)\n - `domain`: the target backend of the RPC that failed;\n - `path`: the path of the RPC that failed.\n\n### Domain errors\n\nErrors in this category result from trying to communicate with a backend that is considered non-existent or invalid. They can result from invalid user input or client issues, but they can also be a symptom of misconfiguration in one or multiple backends. These errors have a 4xx status code.\n\n - **Remote backend not found** (status: 422, label: `invalid-domain`): This backend attempted to contact a backend which does not exist or is not properly configured. For the most part, clients can consider this error equivalent to a domain not existing, although it should be noted that certain mistakes in the DNS configuration on a remote backend can lead to the backend not being recognized, and hence to this error. It is therefore not advisable to take any destructive action upon encountering this error, such as deleting remote users from conversations.\n - **Federation denied locally** (status: 400, label: `federation-denied`): This backend attempted an RPC to a non-whitelisted backend. Similar considerations as for the previous error apply.\n - **Federation not enabled** (status: 400, label: `federation-not-enabled`): Federation has not been configured for this backend. This will happen if a federation-aware client tries to talk to a backend for which federation is disabled, or if federation was disabled on the backend after reaching a federation-specific state (e.g. conversations with remote users). There is no way to cleanly recover from these errors at this point.\n\n### Local federation errors\n\nAn error in this category likely indicates an issue with the configuration of federation on the local backend. Possibly transient errors are indicated explicitly below. All these errors have a 500 status code.\n\n - **Federation unavailable** (status: 500, label: `federation-not-available`): Federation is configured for this backend, but the local federator cannot be reached. This can be transient, so clients should retry the request.\n - **Federation not implemented** (status: 422, label: `federation-not-implemented`): Federated behaviour for a certain endpoint is not yet implemented.\n - **Federator discovery failed** (status: 400, label: `discovery-failure`): A DNS error occurred during discovery of a remote backend. This can be transient, so clients should retry the request.\n - **Local federation error** (status: 500, label: `federation-local-error`): An error occurred in the communication between this backend and its local federator. These errors are most likely caused by bugs in the backend, and should be reported as such.\n\n### Remote federation errors\n\nErrors in this category are returned in case of communication issues between the local backend and a remote one, or if the remote side encountered an error while processing an RPC. Some errors in this category might be caused by incorrect client behaviour, wrong user input, or incorrect certificate configuration. Possibly transient errors are indicated explicitly. We use non-standard 5xx status codes for these errors.\n\n - **HTTP2 error** (status: 533, label: `federation-http2-error`): The current federator encountered an error when making an HTTP2 request to a remote one. Check the error message for more details.\n - **Connection refused** (status: 521, label: `federation-connection-refused`): The local federator could not connect to a remote one. This could be transient, so clients should retry the request.\n - **TLS failure**: (status: 525, label: `federation-tls-error`): An error occurred during the TLS handshake between the local federator and a remote one. This is most likely due to an issue with the certificate on the remote end.\n - **Remote federation error** (status: 533, label: `federation-remote-error`): The remote backend could not process a request coming from this backend. Check the error message for more details.\n - **Version negotiation error** (status: 533, label: `federation-version-error`): The remote backend returned invalid version information.\n\n### Backend compatibility errors\n\nAn error in this category will be returned when this backend makes an invalid or unsupported RPC to another backend. This can indicate some incompatibility between backends or a backend bug. These errors are unlikely to be transient, so retrying requests is *not* advised.\n\n - **Version mismatch** (status: 531, label: `federation-version-mismatch`): A remote backend is running an unsupported version of the federator.\n - **Invalid content type** (status: 533, label: `federation-invalid-content-type`): An RPC to another backend returned with an invalid content type.\n - **Unsupported content type** (status: 533, label: `federation-unsupported-content-type`): An RPC to another backend returned with an unsupported content type.\n", + "title": "Wire-Server API", + "version": "" + }, + "openapi": "3.0.0", + "paths": { + "/access": { + "post": { + "description": " [internal route ID: \"access\"]\n\nYou can provide only a cookie or a cookie and token. Every other combination is invalid. Access tokens can be given as query parameter or authorisation header, with the latter being preferred.", + "operationId": "access", + "parameters": [ + { + "in": "query", + "name": "client_id", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccessToken_ODIyMTczMjMw" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/AccessToken_ODIyMTczMjMw" + } + } + }, + "description": "OK", + "headers": { + "Set-Cookie": { + "schema": { + "type": "string" + } + } + } + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Authentication failed (label: `invalid-credentials`)" + } + }, + "summary": "Obtain an access tokens for a cookie" + } + }, + "/access/logout": { + "post": { + "description": " [internal route ID: \"logout\"]\n\nCalling this endpoint will effectively revoke the given cookie and subsequent calls to /access with the same cookie will result in a 403.", + "operationId": "logout", + "responses": { + "200": { + "description": "Logout" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Authentication failed (label: `invalid-credentials`)" + } + }, + "summary": "Log out in order to remove a cookie from the server" + } + }, + "/access/self/email": { + "put": { + "description": " [internal route ID: \"change-self-email\"]\n\n", + "operationId": "change-self-email", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/EmailUpdate_NjQ5MDg1OTY0" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + } + }, + "description": "Update accepted and pending activation of the new email" + }, + "204": { + "content": { + "application/json": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + } + }, + "description": "No update, current and new email address are the same\n\nEmail address activated" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-email", + "message": "Invalid e-mail address." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-email" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid e-mail address. (label: `invalid-email`) or `body`" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials", + "blacklisted-email" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Authentication failed (label: `invalid-credentials`)\n\nThe given e-mail address has been blacklisted due to a permanent bounce or a complaint. (label: `blacklisted-email`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "key-exists", + "message": "The given e-mail address is in use." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "key-exists" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The given e-mail address is in use. (label: `key-exists`)" + } + }, + "summary": "Change your email address" + } + }, + "/activate": { + "get": { + "description": " [internal route ID: \"get-activate\"]\n\nSee also 'POST /activate' which has a larger feature set.", + "operationId": "get-activate", + "parameters": [ + { + "description": "Activation key", + "in": "query", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Activation code", + "in": "query", + "name": "code", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActivationResponse_LTIyOTY5NDE3" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ActivationResponse_LTIyOTY5NDE3" + } + } + }, + "description": "Activation successful.\n\nActivation successful. (Dry run)\n\nActivation successful." + }, + "204": { + "description": "A recent activation was already successful." + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-phone", + "message": "Invalid mobile phone number" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-phone", + "invalid-email" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `code` or `key`\n\nInvalid mobile phone number (label: `invalid-phone`)\n\nInvalid e-mail address. (label: `invalid-email`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "invalid-code", + "message": "Invalid activation code" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid activation code (label: `invalid-code`)\n\nUser does not exist (label: `invalid-code`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "key-exists", + "message": "The given e-mail address is in use." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "key-exists" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The given e-mail address is in use. (label: `key-exists`)" + } + }, + "summary": "Activate (i.e. confirm) an email address." + }, + "post": { + "description": " [internal route ID: \"post-activate\"]\n\nActivation only succeeds once and the number of failed attempts for a valid key is limited.", + "operationId": "post-activate", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Activate_MzUzNzIxODUw" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActivationResponse_LTIyOTY5NDE3" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ActivationResponse_LTIyOTY5NDE3" + } + } + }, + "description": "Activation successful.\n\nActivation successful. (Dry run)\n\nActivation successful." + }, + "204": { + "description": "A recent activation was already successful." + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-phone", + "message": "Invalid mobile phone number" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-phone", + "invalid-email" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid mobile phone number (label: `invalid-phone`)\n\nInvalid e-mail address. (label: `invalid-email`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "invalid-code", + "message": "Invalid activation code" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid activation code (label: `invalid-code`)\n\nUser does not exist (label: `invalid-code`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "key-exists", + "message": "The given e-mail address is in use." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "key-exists" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The given e-mail address is in use. (label: `key-exists`)" + } + }, + "summary": "Activate (i.e. confirm) an email address." + } + }, + "/activate/send": { + "post": { + "description": " [internal route ID: \"post-activate-send\"]\n\n", + "operationId": "post-activate-send", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/SendActivationCode_LTgyNDAxNzEy" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Activation code sent." + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-email", + "message": "Invalid e-mail address." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-email" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid e-mail address. (label: `invalid-email`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "blacklisted-email", + "message": "The given e-mail address has been blacklisted due to a permanent bounce or a complaint." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "blacklisted-email" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The given e-mail address has been blacklisted due to a permanent bounce or a complaint. (label: `blacklisted-email`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "key-exists", + "message": "The given e-mail address is in use." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "key-exists" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The given e-mail address is in use. (label: `key-exists`)" + }, + "451": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 451, + "label": "domain-blocked-for-registration", + "message": "[Customer extension] The email domain has been blocked for Wire users. Please contact your IT department." + }, + "properties": { + "code": { + "enum": [ + 451 + ], + "type": "integer" + }, + "label": { + "enum": [ + "domain-blocked-for-registration" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "[Customer extension] The email domain has been blocked for Wire users. Please contact your IT department. (label: `domain-blocked-for-registration`)" + } + }, + "summary": "Send (or resend) an email activation code." + } + }, + "/api-version": { + "get": { + "description": " [internal route ID: \"get-version\"]\n\n", + "operationId": "get-version", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/VersionInfo_NTEzMTgzNDQ0" + } + } + }, + "description": "" + } + } + } + }, + "/assets": { + "post": { + "description": " [internal route ID: \"assets-upload\"]\n\n

Construct the request as multipart/mixed; set header Content-Type: multipart/mixed; boundary=<boundary>.

Use exactly two parts in this order:

  1. application/json metadata (AssetSettings)
  2. application/octet-stream asset bytes

Each part must include Content-Type and Content-Length; the second part may include Content-MD5. Use CRLF between headers and bodies.

When asset audit logging is enabled, the JSON metadata must include:

  • convId: object { id: UUID, domain: String } (qualified conversation ID)
  • filename: String
  • filetype: String MIME type (e.g. image/png, application/pdf)

Optional metadata: public (Bool, default false), retention (one of eternal, persistent, volatile, eternal-infrequent_access, expiring).

For profile pictures or team icons without a conversation, set convId.id to 00000000-0000-0000-0000-000000000000 and convId.domain to the tenant’s domain; use any reasonable filename.

Note: the server treats the asset bytes as application/octet-stream; filetype is used for auditing only.

Example body (boundary=frontier):

Content-Type: multipart/mixed; boundary=frontier

--frontier
Content-Type: application/json
Content-Length: 191

{\"public\":false,\"retention\":\"volatile\",\"convId\":{\"id\":\"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\",\"domain\":\"example.com\"},\"filename\":\"report.pdf\",\"filetype\":\"application/pdf\"}
--frontier
Content-Type: application/octet-stream
Content-Length: 11

Hello Audit
--frontier--
", + "operationId": "assets-upload", + "requestBody": { + "content": { + "multipart/mixed": { + "schema": { + "$ref": "#/components/schemas/AssetSource" + } + } + }, + "description": "A body with content type `multipart/mixed body`. The first section's content type should be `application/json`. The second section's content type should be always be `application/octet-stream`. Other content types will be ignored by the server." + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Asset_Qualified_AssetKey_MzU1MjMxNTA5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Asset_Qualified_AssetKey_MzU1MjMxNTA5" + } + } + }, + "description": "Asset posted", + "headers": { + "Location": { + "description": "Asset location", + "schema": { + "format": "url", + "type": "string" + } + } + } + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "incomplete-body", + "message": "HTTP content-length header does not match body size" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "incomplete-body", + "invalid-length" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nHTTP content-length header does not match body size (label: `incomplete-body`)\n\nInvalid content length (label: `invalid-length`)" + }, + "413": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 413, + "label": "client-error", + "message": "Asset too large" + }, + "properties": { + "code": { + "enum": [ + 413 + ], + "type": "integer" + }, + "label": { + "enum": [ + "client-error" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Asset too large (label: `client-error`)" + } + }, + "summary": "Upload an asset" + } + }, + "/assets/{key_domain}/{key}": { + "delete": { + "description": " [internal route ID: \"assets-delete\"]\n\n**Note**: only local assets can be deleted.", + "operationId": "assets-delete", + "parameters": [ + { + "in": "path", + "name": "key_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Asset deleted" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "unauthorised", + "message": "Unauthorised operation" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unauthorised" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unauthorised operation (label: `unauthorised`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Asset not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`key_domain` or `key` not found\n\nAsset not found (label: `not-found`)" + } + }, + "summary": "Delete an asset" + }, + "get": { + "description": " [internal route ID: \"assets-download\"]\n\n**Note**: local assets result in a redirect, while remote assets are streamed directly.", + "operationId": "assets-download", + "parameters": [ + { + "in": "path", + "name": "key_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "header", + "name": "Asset-Token", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "asset_token", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Asset returned directly with content type `application/octet-stream`" + }, + "302": { + "description": "Asset found", + "headers": { + "Location": { + "description": "Asset location", + "schema": { + "format": "url", + "type": "string" + } + } + } + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Asset not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`key_domain` or `key` or Asset not found (label: `not-found`)\n\nAsset not found (label: `not-found`)" + } + }, + "summary": "Download an asset" + } + }, + "/assets/{key}/token": { + "delete": { + "description": " [internal route ID: \"tokens-delete\"]\n\n**Note**: deleting the token makes the asset public.", + "operationId": "tokens-delete", + "parameters": [ + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Asset token deleted" + } + }, + "summary": "Delete an asset token" + }, + "post": { + "description": " [internal route ID: \"tokens-renew\"]\n\n", + "operationId": "tokens-renew", + "parameters": [ + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewAssetToken_NTAwMDQwODYy" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "unauthorised", + "message": "Unauthorised operation" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unauthorised" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unauthorised operation (label: `unauthorised`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Asset not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`key` not found\n\nAsset not found (label: `not-found`)" + } + }, + "summary": "Renew an asset token" + } + }, + "/await": { + "get": { + "description": " [internal route ID: \"await-notifications\"]\n\n", + "externalDocs": { + "description": "RFC 6455", + "url": "https://datatracker.ietf.org/doc/html/rfc6455" + }, + "operationId": "await-notifications", + "parameters": [ + { + "description": "Client ID", + "in": "query", + "name": "client", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "101": { + "description": "Connection upgraded." + }, + "426": { + "description": "Upgrade required." + } + }, + "summary": "Establish websocket connection" + } + }, + "/bot/assets": { + "post": { + "description": " [internal route ID: (\"assets-upload-v3\", bot)]\n\n

Construct the request as multipart/mixed; set header Content-Type: multipart/mixed; boundary=<boundary>.

Use exactly two parts in this order:

  1. application/json metadata (AssetSettings)
  2. application/octet-stream asset bytes

Each part must include Content-Type and Content-Length; the second part may include Content-MD5. Use CRLF between headers and bodies.

When asset audit logging is enabled, the JSON metadata must include:

  • convId: object { id: UUID, domain: String } (qualified conversation ID)
  • filename: String
  • filetype: String MIME type (e.g. image/png, application/pdf)

Optional metadata: public (Bool, default false), retention (one of eternal, persistent, volatile, eternal-infrequent_access, expiring).

For profile pictures or team icons without a conversation, set convId.id to 00000000-0000-0000-0000-000000000000 and convId.domain to the tenant’s domain; use any reasonable filename.

Note: the server treats the asset bytes as application/octet-stream; filetype is used for auditing only.

Example body (boundary=frontier):

Content-Type: multipart/mixed; boundary=frontier

--frontier
Content-Type: application/json
Content-Length: 191

{\"public\":false,\"retention\":\"volatile\",\"convId\":{\"id\":\"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\",\"domain\":\"example.com\"},\"filename\":\"report.pdf\",\"filetype\":\"application/pdf\"}
--frontier
Content-Type: application/octet-stream
Content-Length: 11

Hello Audit
--frontier--
", + "operationId": "assets-upload-v3_bot", + "requestBody": { + "content": { + "multipart/mixed": { + "schema": { + "$ref": "#/components/schemas/AssetSource" + } + } + }, + "description": "A body with content type `multipart/mixed body`. The first section's content type should be `application/json`. The second section's content type should be always be `application/octet-stream`. Other content types will be ignored by the server." + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Asset_Qualified_AssetKey_MzU1MjMxNTA5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Asset_Qualified_AssetKey_MzU1MjMxNTA5" + } + } + }, + "description": "Asset posted", + "headers": { + "Location": { + "description": "Asset location", + "schema": { + "format": "url", + "type": "string" + } + } + } + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "incomplete-body", + "message": "HTTP content-length header does not match body size" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "incomplete-body", + "invalid-length" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nHTTP content-length header does not match body size (label: `incomplete-body`)\n\nInvalid content length (label: `invalid-length`)" + }, + "413": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 413, + "label": "client-error", + "message": "Asset too large" + }, + "properties": { + "code": { + "enum": [ + 413 + ], + "type": "integer" + }, + "label": { + "enum": [ + "client-error" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Asset too large (label: `client-error`)" + } + }, + "summary": "Upload an asset" + } + }, + "/bot/assets/{key}": { + "delete": { + "description": " [internal route ID: (\"assets-delete-v3\", bot)]\n\n", + "operationId": "assets-delete-v3_bot", + "parameters": [ + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Asset deleted" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "unauthorised", + "message": "Unauthorised operation" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unauthorised" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unauthorised operation (label: `unauthorised`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Asset not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`key` not found\n\nAsset not found (label: `not-found`)" + } + }, + "summary": "Delete an asset" + }, + "get": { + "description": " [internal route ID: (\"assets-download-v3\", bot)]\n\n", + "operationId": "assets-download-v3_bot", + "parameters": [ + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "header", + "name": "Asset-Token", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "asset_token", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "302": { + "description": "Asset found", + "headers": { + "Location": { + "description": "Asset location", + "schema": { + "format": "url", + "type": "string" + } + } + } + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Asset not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Asset not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`key` or Asset not found (label: `not-found`)" + } + }, + "summary": "Download an asset" + } + }, + "/bot/client": { + "get": { + "description": " [internal route ID: \"bot-get-client\"]\n\n", + "operationId": "bot-get-client", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Client_MTM1OTcwOTQ1" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Client_MTM1OTcwOTQ1" + } + } + }, + "description": "Client found" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "client-not-found", + "message": "Client not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "client-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "client-not-found", + "message": "Client not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "client-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Client not found (label: `client-not-found`)\n\nClient not found (label: `client-not-found`)" + } + }, + "summary": "Get client for bot" + } + }, + "/bot/client/prekeys": { + "get": { + "description": " [internal route ID: \"bot-list-prekeys\"]\n\n", + "operationId": "bot-list-prekeys", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "items": { + "maximum": 65535, + "minimum": 0, + "type": "integer" + }, + "type": "array" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + } + }, + "summary": "List prekeys for bot" + }, + "post": { + "description": " [internal route ID: \"bot-update-prekeys\"]\n\n", + "operationId": "bot-update-prekeys", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UpdateBotPrekeys_LTg3NzYxODg0" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "client-not-found", + "message": "Client not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "client-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Client not found (label: `client-not-found`)" + } + }, + "summary": "Update prekeys for bot" + } + }, + "/bot/conversation": { + "get": { + "description": " [internal route ID: \"get-bot-conversation\"]\n\n", + "operationId": "get-bot-conversation", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/BotConvView_LTYzMjIzMjQz" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)\n\nYou do not have permission to access this resource (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team", + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Team not found (label: `no-team`)\n\nConversation not found (label: `no-conversation`)" + } + } + } + }, + "/bot/conversations/{conv}": { + "post": { + "description": " [internal route ID: \"add-bot\"]\n\n", + "operationId": "add-bot", + "parameters": [ + { + "in": "path", + "name": "conv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/AddBot_NjI0ODkyODk3" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddBotResponse_ODA5MzA2NTA1" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/AddBotResponse_ODA5MzA2NTA1" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "service-disabled", + "message": "The desired service is currently disabled." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "service-disabled", + "too-many-members", + "invalid-conversation", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The desired service is currently disabled. (label: `service-disabled`)\n\nMaximum number of members per conversation reached. (label: `too-many-members`)\n\nThe operation is not allowed in this conversation. (label: `invalid-conversation`)\n\nAccess denied. (label: `access-denied`)" + } + }, + "summary": "Add bot" + } + }, + "/bot/conversations/{conv}/{bot}": { + "delete": { + "description": " [internal route ID: \"remove-bot\"]\n\n", + "operationId": "remove-bot", + "parameters": [ + { + "in": "path", + "name": "conv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "bot", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoveBotResponse_LTUxNTQ4MDEy" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/RemoveBotResponse_LTUxNTQ4MDEy" + } + } + }, + "description": "User found" + }, + "204": { + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-conversation", + "message": "The operation is not allowed in this conversation." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-conversation", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The operation is not allowed in this conversation. (label: `invalid-conversation`)\n\nAccess denied. (label: `access-denied`)" + } + }, + "summary": "Remove bot" + } + }, + "/bot/messages": { + "post": { + "description": " [internal route ID: \"post-bot-message-unqualified\"]\n\n", + "operationId": "post-bot-message-unqualified", + "parameters": [ + { + "in": "query", + "name": "ignore_missing", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "report_missing", + "required": false, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewOtrMessage_LTUyMTE5MTMw" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + } + }, + "description": "Message sent" + }, + "403": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unknown Client (label: `unknown-client`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation not found (label: `no-conversation`)\n\nConversation not found (label: `no-conversation`)" + }, + "412": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + } + }, + "description": "Missing clients" + } + } + } + }, + "/bot/self": { + "delete": { + "description": " [internal route ID: \"bot-delete-self\"]\n\n", + "operationId": "bot-delete-self", + "responses": { + "200": { + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-bot", + "message": "The targeted user is not a bot." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-bot", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The targeted user is not a bot. (label: `invalid-bot`)\n\nAccess denied. (label: `access-denied`)" + } + }, + "summary": "Delete self" + }, + "get": { + "description": " [internal route ID: \"bot-get-self\"]\n\n", + "operationId": "bot-get-self", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserProfile_LTQzMTQxMTE1" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "User not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "User not found (label: `not-found`)" + } + }, + "summary": "Get self" + } + }, + "/bot/users": { + "get": { + "description": " [internal route ID: \"bot-list-users\"]\n\n", + "operationId": "bot-list-users", + "parameters": [ + { + "in": "query", + "name": "ids", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/BotUserView_LTE2MTkwMTcw" + }, + "type": "array" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + } + }, + "summary": "List users" + } + }, + "/bot/users/prekeys": { + "post": { + "description": " [internal route ID: \"bot-claim-users-prekeys\"]\n\n", + "operationId": "bot-claim-users-prekeys", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserClients" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserClientPrekeyMap" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "missing-legalhold-consent", + "message": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "missing-legalhold-consent", + "missing-legalhold-consent-old-clients", + "too-many-clients", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)\n\nToo many clients (label: `too-many-clients`)\n\nAccess denied. (label: `access-denied`)" + } + }, + "summary": "Claim users prekeys" + } + }, + "/bot/users/{user}/clients": { + "get": { + "description": " [internal route ID: \"bot-get-user-clients\"]\n\n", + "operationId": "bot-get-user-clients", + "parameters": [ + { + "in": "path", + "name": "user", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/PubClient" + }, + "type": "array" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + } + }, + "summary": "Get user clients" + } + }, + "/broadcast/otr/messages": { + "post": { + "description": " [internal route ID: \"post-otr-broadcast-unqualified\"]\n\nThis endpoint ensures that the list of clients is correct and only sends the message if the list is correct.\nTo override this, the endpoint accepts two query params:\n- `ignore_missing`: Can be 'true' 'false' or a comma separated list of user IDs.\n - When 'true' all missing clients are ignored.\n - When 'false' all missing clients are reported.\n - When comma separated list of user-ids, only clients for listed users are ignored.\n- `report_missing`: Can be 'true' 'false' or a comma separated list of user IDs.\n - When 'true' all missing clients are reported.\n - When 'false' all missing clients are ignored.\n - When comma separated list of user-ids, only clients for listed users are reported.\n\nApart from these, the request body also accepts `report_missing` which can only be a list of user ids and behaves the same way as the query parameter.\n\nAll three of these should be considered mutually exclusive. The server however does not error if more than one is specified, it reads them in this order of precedence:\n- `report_missing` in the request body has highest precedence.\n- `ignore_missing` in the query param is the next.\n- `report_missing` in the query param has the lowest precedence.\n\nThis endpoint can lead to OtrMessageAdd event being sent to the recipients.\n\n**NOTE:** The protobuf definitions of the request body can be found at https://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto.", + "operationId": "post-otr-broadcast-unqualified", + "parameters": [ + { + "in": "query", + "name": "ignore_missing", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "report_missing", + "required": false, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewOtrMessage_LTUyMTE5MTMw" + } + }, + "application/x-protobuf": { + "schema": { + "$ref": "#/components/schemas/NewOtrMessage_LTUyMTE5MTMw" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + } + }, + "description": "Message sent" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "too-many-users-to-broadcast", + "message": "Too many users to fan out the broadcast event to" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "too-many-users-to-broadcast" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body` or `report_missing` or `ignore_missing`\n\nToo many users to fan out the broadcast event to (label: `too-many-users-to-broadcast`)" + }, + "403": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unknown Client (label: `unknown-client`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation", + "non-binding-team", + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation not found (label: `no-conversation`)\n\nNot a member of a binding team (label: `non-binding-team`)\n\nTeam not found (label: `no-team`)" + }, + "412": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + } + }, + "description": "Missing clients" + } + }, + "summary": "Broadcast an encrypted message to all team members and all contacts (accepts JSON or Protobuf)" + } + }, + "/broadcast/proteus/messages": { + "post": { + "description": " [internal route ID: \"post-proteus-broadcast\"]\n\nThis endpoint ensures that the list of clients is correct and only sends the message if the list is correct.\nTo override this, the endpoint accepts `client_mismatch_strategy` in the body. It can have these values:\n- `report_all`: When set, the message is not sent if any clients are missing. The missing clients are reported in the response.\n- `ignore_all`: When set, no checks about missing clients are carried out.\n- `report_only`: Takes a list of qualified UserIDs. If any clients of the listed users are missing, the message is not sent. The missing clients are reported in the response.\n- `ignore_only`: Takes a list of qualified UserIDs. If any clients of the non-listed users are missing, the message is not sent. The missing clients are reported in the response.\n\nThe sending of messages in a federated conversation could theoretically fail partially. To make this case unlikely, the backend first gets a list of clients from all the involved backends and then tries to send a message. So, if any backend is down, the message is not propagated to anyone. But the actual message fan out to multiple backends could still fail partially. This type of failure is reported as a 201, the clients for which the message sending failed are part of the response body.\n\nThis endpoint can lead to OtrMessageAdd event being sent to the recipients.\n\n**NOTE:** The protobuf definitions of the request body can be found at https://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto.", + "operationId": "post-proteus-broadcast", + "requestBody": { + "content": { + "application/x-protobuf": { + "schema": { + "$ref": "#/components/schemas/QualifiedNewOtrMessage" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageSendingStatus_ODg0NDgyNDk4" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MessageSendingStatus_ODg0NDgyNDk4" + } + } + }, + "description": "Message sent" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "too-many-users-to-broadcast", + "message": "Too many users to fan out the broadcast event to" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "too-many-users-to-broadcast" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nToo many users to fan out the broadcast event to (label: `too-many-users-to-broadcast`)" + }, + "403": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unknown Client (label: `unknown-client`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation", + "non-binding-team", + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation not found (label: `no-conversation`)\n\nNot a member of a binding team (label: `non-binding-team`)\n\nTeam not found (label: `no-team`)" + }, + "412": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageSendingStatus_ODg0NDgyNDk4" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MessageSendingStatus_ODg0NDgyNDk4" + } + } + }, + "description": "Missing clients" + } + }, + "summary": "Post an encrypted message to all team members and all contacts (accepts only Protobuf)" + } + }, + "/calls/config/v2": { + "get": { + "description": " [internal route ID: \"get-calls-config-v2\"]\n\n", + "operationId": "get-calls-config-v2", + "parameters": [ + { + "description": "Limit resulting list. Allowed values [1..10]", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "maximum": 10, + "minimum": 1, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/RTCConfiguration_LTIwOTc4OTk0" + } + } + }, + "description": "" + } + }, + "summary": "Retrieve all TURN server addresses and credentials. Clients are expected to do a DNS lookup to resolve the IP addresses of the given hostnames " + } + }, + "/clients": { + "get": { + "description": " [internal route ID: \"list-clients\"]\n\n", + "operationId": "list-clients", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/Client_MTM1OTcwOTQ1" + }, + "type": "array" + } + }, + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/Client_MTM1OTcwOTQ1" + }, + "type": "array" + } + } + }, + "description": "List of clients" + } + }, + "summary": "List the registered clients" + }, + "post": { + "description": " [internal route ID: \"add-client\"]\n\n", + "operationId": "add-client", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewClient_ODg1NjY4Njgy" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Client_MTM1OTcwOTQ1" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Client_MTM1OTcwOTQ1" + } + } + }, + "description": "Client registered", + "headers": { + "Location": { + "description": "Client ID", + "schema": { + "type": "string" + } + } + } + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "bad-request", + "message": "Malformed prekeys uploaded" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "bad-request" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nMalformed prekeys uploaded (label: `bad-request`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "code-authentication-required", + "message": "Code authentication is required" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "code-authentication-required", + "code-authentication-failed", + "missing-auth", + "too-many-clients" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Code authentication is required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nRe-authentication via password required (label: `missing-auth`)\n\nToo many clients (label: `too-many-clients`)" + } + }, + "summary": "Register a new client" + } + }, + "/clients/{cid}/access-token": { + "post": { + "description": " [internal route ID: \"create-access-token\"]\n\nCreate an JWT DPoP access token for the client CSR, given a JWT DPoP proof, specified in the `DPoP` header. The access token will be returned in the JSON response body as a JWT DPoP token.", + "operationId": "create-access-token", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "cid", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "header", + "name": "DPoP", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DPoPAccessTokenResponse_LTgyODU5MDE3" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DPoPAccessTokenResponse_LTgyODU5MDE3" + } + } + }, + "description": "Access token created", + "headers": { + "Cache-Control": { + "schema": { + "type": "string" + } + } + } + } + }, + "summary": "Create a JWT DPoP access token" + } + }, + "/clients/{client}": { + "delete": { + "description": " [internal route ID: \"delete-client\"]\n\n", + "operationId": "delete-client", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/RmClient_MTQ5OTI2MDY3" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Client deleted" + } + }, + "summary": "Delete an existing client" + }, + "get": { + "description": " [internal route ID: \"get-client\"]\n\n", + "operationId": "get-client", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Client_MTM1OTcwOTQ1" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Client_MTM1OTcwOTQ1" + } + } + }, + "description": "Client found" + }, + "404": { + "description": "`client` or Client not found(**Note**: This error has an empty body for legacy reasons)" + } + }, + "summary": "Get a registered client by ID" + }, + "put": { + "description": " [internal route ID: \"update-client\"]\n\n", + "operationId": "update-client", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UpdateClient_NzU5MjA4MzI1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Client updated" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-duplicate-public-key", + "message": "MLS public key for the given signature scheme already exists" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-duplicate-public-key", + "bad-request" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nMLS public key for the given signature scheme already exists (label: `mls-duplicate-public-key`)\n\nMalformed prekeys uploaded (label: `bad-request`)" + } + }, + "summary": "Update a registered client" + } + }, + "/clients/{client}/capabilities": { + "get": { + "description": " [internal route ID: \"get-client-capabilities\"]\n\n", + "operationId": "get-client-capabilities", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ClientCapabilityList" + } + } + }, + "description": "" + } + }, + "summary": "Read back what the client has been posting about itself" + } + }, + "/clients/{client}/nonce": { + "get": { + "description": " [internal route ID: \"get-nonce\"]\n\nGet a new nonce for a client CSR, specified in the response header `Replay-Nonce` as a uuidv4 in base64url encoding.", + "operationId": "get-nonce", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "headers": { + "Cache-Control": { + "schema": { + "type": "string" + } + }, + "Replay-Nonce": { + "schema": { + "type": "string" + } + } + } + } + }, + "summary": "Get a new nonce for a client CSR" + }, + "head": { + "description": " [internal route ID: \"head-nonce\"]\n\nGet a new nonce for a client CSR, specified in the response header `Replay-Nonce` as a uuidv4 in base64url encoding.", + "operationId": "head-nonce", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "No Content", + "headers": { + "Cache-Control": { + "schema": { + "type": "string" + } + }, + "Replay-Nonce": { + "schema": { + "type": "string" + } + } + } + } + }, + "summary": "Get a new nonce for a client CSR" + } + }, + "/clients/{client}/prekeys": { + "get": { + "description": " [internal route ID: \"get-client-prekeys\"]\n\n", + "operationId": "get-client-prekeys", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "items": { + "maximum": 65535, + "minimum": 0, + "type": "integer" + }, + "type": "array" + } + } + }, + "description": "" + } + }, + "summary": "List the remaining prekey IDs of a client" + } + }, + "/connections/{uid_domain}/{uid}": { + "get": { + "description": " [internal route ID: \"get-connection\"]\n\n", + "operationId": "get-connection", + "parameters": [ + { + "in": "path", + "name": "uid_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User Id", + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + } + } + }, + "description": "Connection found" + }, + "404": { + "description": "`uid_domain` or `uid` or Connection not found(**Note**: This error has an empty body for legacy reasons)" + } + }, + "summary": "Get an existing connection to another user (local or remote)" + }, + "post": { + "description": " [internal route ID: \"create-connection\"]\n\nYou can have no more than 1000 connections in accepted or sent state", + "operationId": "create-connection", + "parameters": [ + { + "in": "path", + "name": "uid_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User Id", + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + } + } + }, + "description": "Connection existed" + }, + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + } + } + }, + "description": "Connection was created" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-user", + "message": "Invalid user" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-user" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid user (label: `invalid-user`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-identity", + "message": "The user has no verified email" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-identity", + "connection-limit", + "missing-legalhold-consent", + "missing-legalhold-consent-old-clients" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The user has no verified email (label: `no-identity`)\n\nToo many sent/accepted connections (label: `connection-limit`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)" + } + }, + "summary": "Create a connection to another user" + }, + "put": { + "description": " [internal route ID: \"update-connection\"]\n\n", + "operationId": "update-connection", + "parameters": [ + { + "in": "path", + "name": "uid_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User Id", + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConnectionUpdate_LTU3MTA1OTA5" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + } + } + }, + "description": "Connection updated" + }, + "204": { + "description": "Connection unchanged" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-user", + "message": "Invalid user" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-user" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid user (label: `invalid-user`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-identity", + "message": "The user has no verified email" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-identity", + "bad-conn-update", + "not-connected", + "connection-limit", + "missing-legalhold-consent", + "missing-legalhold-consent-old-clients" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The user has no verified email (label: `no-identity`)\n\nInvalid status transition (label: `bad-conn-update`)\n\nUsers are not connected (label: `not-connected`)\n\nToo many sent/accepted connections (label: `connection-limit`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)" + } + }, + "summary": "Update a connection to another user" + } + }, + "/conversations": { + "post": { + "description": " [internal route ID: \"create-group-conversation\"]\n\nThis returns 201 when a new conversation is created, and 200 when the conversation already existed\nOAuth scope: `write:conversations`", + "operationId": "create-group-conversation", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewConv_LTgzNTk1NDQx" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGroupConversation_GroupConvType_MTQ3OTc4NDk3" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CreateGroupConversation_GroupConvType_MTQ3OTc4NDk3" + } + } + }, + "description": "Conversation created", + "headers": { + "Location": { + "description": "Conversation ID", + "schema": { + "format": "uuid", + "type": "string" + } + } + } + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "history-not-supported", + "message": "Shared history is not supported on this conversation" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "history-not-supported", + "mls-not-enabled", + "non-empty-member-list" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nShared history is not supported on this conversation (label: `history-not-supported`)\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)\n\nAttempting to add group members outside MLS (label: `non-empty-member-list`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "channels-not-enabled", + "message": "The channels feature is not enabled for this team" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "channels-not-enabled", + "not-mls-conversation", + "missing-legalhold-consent", + "operation-denied", + "no-team-member", + "not-connected", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The channels feature is not enabled for this team (label: `channels-not-enabled`)\n\nThis operation requires an MLS conversation (label: `not-mls-conversation`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nInsufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nUsers are not connected (label: `not-connected`)\n\nConversation access denied (label: `access-denied`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "non_federating_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "non_federating_backends" + ], + "type": "object" + } + } + }, + "description": "Adding members to the conversation is not possible because the backends involved do not form a fully connected graph" + }, + "533": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "unreachable_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "unreachable_backends" + ], + "type": "object" + } + } + }, + "description": "Some domains are unreachable" + } + }, + "summary": "Create a new conversation" + } + }, + "/conversations/code-check": { + "post": { + "description": " [internal route ID: \"code-check\"]\n\nIf the guest links team feature is disabled, this will fail with 404 CodeNotFound.Note that this is currently inconsistent (for backwards compatibility reasons) with `POST /conversations/join` which responds with 409 GuestLinksDisabled if guest links are disabled.", + "operationId": "code-check", + "parameters": [ + { + "in": "header", + "name": "X-Forwarded-For", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationCode_Mjg3OTI1NTMx" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Valid" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-conversation-password", + "message": "Invalid conversation password" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-conversation-password" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid conversation password (label: `invalid-conversation-password`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation", + "no-conversation-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation not found (label: `no-conversation`)\n\nConversation code not found (label: `no-conversation-code`)" + } + }, + "summary": "Check validity of a conversation code." + } + }, + "/conversations/join": { + "get": { + "description": " [internal route ID: \"get-conversation-by-reusable-code\"]\n\n", + "operationId": "get-conversation-by-reusable-code", + "parameters": [ + { + "in": "query", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "code", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationCoverView_LTMwNDkxMTA1" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "access-denied", + "invalid-conversation-password" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nConversation access denied (label: `access-denied`)\n\nInvalid conversation password (label: `invalid-conversation-password`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation", + "no-conversation-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation not found (label: `no-conversation`)\n\nConversation code not found (label: `no-conversation-code`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "guest-links-disabled", + "message": "The guest link feature is disabled and all guest links have been revoked" + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "guest-links-disabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The guest link feature is disabled and all guest links have been revoked (label: `guest-links-disabled`)" + } + }, + "summary": "Get limited conversation information by key/code pair" + }, + "post": { + "description": " [internal route ID: \"join-conversation-by-code-unqualified\"]\n\nIf the guest links team feature is disabled, this will fail with 409 GuestLinksDisabled.Note that this is currently inconsistent (for backwards compatibility reasons) with `POST /conversations/code-check` which responds with 404 CodeNotFound if guest links are disabled.", + "operationId": "join-conversation-by-code-unqualified", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/JoinConversationByCode_NjgzMzM4Mjg5" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "Conversation joined" + }, + "204": { + "description": "Conversation unchanged" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "too-many-members", + "message": "Maximum number of members per conversation reached" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "too-many-members", + "no-team-member", + "invalid-op", + "access-denied", + "invalid-conversation-password" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Maximum number of members per conversation reached (label: `too-many-members`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInvalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)\n\nInvalid conversation password (label: `invalid-conversation-password`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation", + "no-conversation-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation not found (label: `no-conversation`)\n\nConversation code not found (label: `no-conversation-code`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "guest-links-disabled", + "message": "The guest link feature is disabled and all guest links have been revoked" + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "guest-links-disabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The guest link feature is disabled and all guest links have been revoked (label: `guest-links-disabled`)" + } + }, + "summary": "Join a conversation using a reusable code" + } + }, + "/conversations/list": { + "post": { + "description": " [internal route ID: \"list-conversations\"]\n\n", + "operationId": "list-conversations", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ListConversations_MjkxMTIwODMz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationsResponse_GroupConvType_ODkxMjM2ODM0" + } + } + }, + "description": "" + } + }, + "summary": "Get conversation metadata for a list of conversation ids" + } + }, + "/conversations/list-ids": { + "post": { + "description": " [internal route ID: \"list-conversation-ids\"]\n\nThe IDs returned by this endpoint are paginated. To get the first page, make a call with the `paging_state` field set to `null` (or omitted). Whenever the `has_more` field of the response is set to `true`, more results are available, and they can be obtained by calling the endpoint again, but this time passing the value of `paging_state` returned by the previous call. One can continue in this fashion until all results are returned, which is indicated by `has_more` being `false`. Note that `paging_state` should be considered an opaque token. It should not be inspected, or stored, or reused across multiple unrelated invocations of the endpoint.", + "operationId": "list-conversation-ids", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/GetMuliTabPgRqs_ConvrIdLcOm10_ODU0NjQ1NDMz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MultiTabePg_ConvrsIdqf_cLORm_Q_Mzg0MjYzNzM0" + } + } + }, + "description": "" + } + }, + "summary": "Get all conversation IDs." + } + }, + "/conversations/mls-self": { + "get": { + "description": " [internal route ID: \"get-mls-self-conversation\"]\n\n", + "operationId": "get-mls-self-conversation", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/v9_OwnConversation_GroupConvType_LTU2MzYxNTg0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/v9_OwnConversation_GroupConvType_LTU2MzYxNTg0" + } + } + }, + "description": "The MLS self-conversation" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-not-enabled", + "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-not-enabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" + } + }, + "summary": "Get the user's MLS self-conversation" + } + }, + "/conversations/self": { + "post": { + "description": " [internal route ID: \"create-self-conversation\"]\n\n", + "operationId": "create-self-conversation", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/v6_OwnConversation_GroupConvType_LTU2MzYxNTg0V6" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/v6_OwnConversation_GroupConvType_LTU2MzYxNTg0V6" + } + } + }, + "description": "Conversation existed", + "headers": { + "Location": { + "description": "Conversation ID", + "schema": { + "format": "uuid", + "type": "string" + } + } + } + }, + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/v6_OwnConversation_GroupConvType_LTU2MzYxNTg0V6" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/v6_OwnConversation_GroupConvType_LTU2MzYxNTg0V6" + } + } + }, + "description": "Conversation created", + "headers": { + "Location": { + "description": "Conversation ID", + "schema": { + "format": "uuid", + "type": "string" + } + } + } + } + }, + "summary": "Create a self-conversation" + } + }, + "/conversations/{cnv_domain}/{cnv}": { + "get": { + "description": " [internal route ID: \"get-conversation\"]\n\n", + "operationId": "get-conversation", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Conversation_GroupConvType_MzQzMTQ1OTg3" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Conversation access denied" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation access denied (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Get a conversation by ID" + } + }, + "/conversations/{cnv_domain}/{cnv}/access": { + "put": { + "description": " [internal route ID: \"update-conversation-access\"]\n\n", + "operationId": "update-conversation-access", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationAccessData_MjMxMTI5ODc3" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "Access updated" + }, + "204": { + "description": "Access unchanged" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-op", + "message": "Invalid target access" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-op", + "access-denied", + "action-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid target access (label: `invalid-op`)\n\nInvalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)\n\nInsufficient authorization (missing modify_conversation_access) (label: `action-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Update access modes for a conversation" + } + }, + "/conversations/{cnv_domain}/{cnv}/add-permission": { + "put": { + "description": " [internal route ID: \"update-channel-add-permission\"]\n\n", + "operationId": "update-channel-add-permission", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/AddPermissionUpdate_LTU3MzEwOTY4" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "Add permissions updated" + }, + "204": { + "description": "Add permissions unchanged" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-op", + "message": "Invalid target access" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-op", + "not-connected", + "operation-denied", + "no-team-member", + "access-denied", + "action-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid target access (label: `invalid-op`)\n\nUsers are not connected (label: `not-connected`)\n\nInsufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nConversation access denied (label: `access-denied`)\n\nInvalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing modify_add_permissions) (label: `action-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team", + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` not found\n\nTeam not found (label: `no-team`)\n\nConversation not found (label: `no-conversation`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "non_federating_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "non_federating_backends" + ], + "type": "object" + } + } + }, + "description": "Adding members to the conversation is not possible because the backends involved do not form a fully connected graph" + }, + "533": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "unreachable_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "unreachable_backends" + ], + "type": "object" + } + } + }, + "description": "Some domains are unreachable" + } + }, + "summary": "Update the permissions for adding members to a channel" + } + }, + "/conversations/{cnv_domain}/{cnv}/groupinfo": { + "get": { + "description": " [internal route ID: \"get-group-info\"]\n\n", + "operationId": "get-group-info", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], "responses": { "200": { + "content": { + "message/mls": { + "schema": { + "$ref": "#/components/schemas/GroupInfoData" + } + } + }, + "description": "The group information" + }, + "400": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ServiceTagList" + "example": { + "code": 400, + "label": "mls-not-enabled", + "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-not-enabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "" + "description": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "access-denied", - "message": "Access denied." + "code": 404, + "label": "mls-missing-group-info", + "message": "The conversation has no group information" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "access-denied" + "mls-missing-group-info", + "no-conversation" ], "type": "string" }, @@ -6795,47 +14778,101 @@ } } }, - "description": "Access denied. (label: `access-denied`)" + "description": "`cnv_domain` or `cnv` not found\n\nThe conversation has no group information (label: `mls-missing-group-info`)\n\nConversation not found (label: `no-conversation`)" } }, - "summary": "Get services tags" + "summary": "Get MLS group information" } }, - "/access": { - "post": { - "description": " [internal route ID: \"access\"]\n\nYou can provide only a cookie or a cookie and token. Every other combination is invalid. Access tokens can be given as query parameter or authorisation header, with the latter being preferred.Calls federation service brig on send-connection-action", + "/conversations/{cnv_domain}/{cnv}/history": { + "put": { + "description": " [internal route ID: \"update-conversation-history\"]\n\n", + "operationId": "update-conversation-history", "parameters": [ { - "in": "query", - "name": "client_id", - "required": false, + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, "schema": { + "format": "uuid", "type": "string" } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationHistoryUpdate_LTg5MDQ5Nzgx" + } + } + }, + "required": true + }, "responses": { "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AccessToken" + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/AccessToken" + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" } } }, - "description": "OK", - "headers": { - "Set-Cookie": { + "description": "History updated" + }, + "204": { + "description": "History unchanged" + }, + "400": { + "content": { + "application/json;charset=utf-8": { "schema": { - "type": "string" + "example": { + "code": 400, + "label": "history-not-supported", + "message": "Shared history is not supported on this conversation" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "history-not-supported" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } - } + }, + "description": "Invalid `body`\n\nShared history is not supported on this conversation (label: `history-not-supported`)" }, "403": { "content": { @@ -6843,8 +14880,8 @@ "schema": { "example": { "code": 403, - "label": "invalid-credentials", - "message": "Authentication failed" + "label": "action-denied", + "message": "Insufficient authorization (missing modify_conversation_access)" }, "properties": { "code": { @@ -6855,7 +14892,9 @@ }, "label": { "enum": [ - "invalid-credentials" + "action-denied", + "invalid-op", + "access-denied" ], "type": "string" }, @@ -6872,38 +14911,27 @@ } } }, - "description": "Authentication failed (label: `invalid-credentials`)" - } - }, - "summary": "Obtain an access tokens for a cookie" - } - }, - "/access/logout": { - "post": { - "description": " [internal route ID: \"logout\"]\n\nCalling this endpoint will effectively revoke the given cookie and subsequent calls to /access with the same cookie will result in a 403.", - "responses": { - "200": { - "description": "Logout" + "description": "Insufficient authorization (missing modify_conversation_access) (label: `action-denied`)\n\nInvalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "invalid-credentials", - "message": "Authentication failed" + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "invalid-credentials" + "no-conversation" ], "type": "string" }, @@ -6920,67 +14948,63 @@ } } }, - "description": "Authentication failed (label: `invalid-credentials`)" + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" } }, - "summary": "Log out in order to remove a cookie from the server" + "summary": "Update history settings of a conversation" } }, - "/access/self/email": { - "put": { - "description": " [internal route ID: \"change-self-email\"]\n\n", + "/conversations/{cnv_domain}/{cnv}/members": { + "post": { + "description": " [internal route ID: \"add-members-to-conversation\"]\n\n", + "operationId": "add-members-to-conversation", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/EmailUpdate" + "$ref": "#/components/schemas/InviteQualified_ODYyODIyNjYz" } } }, "required": true }, "responses": { - "202": { + "200": { "content": { "application/json": { "schema": { - "example": [], - "items": {}, - "maxItems": 0, - "type": "array" + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" } }, "application/json;charset=utf-8": { "schema": { - "example": [], - "items": {}, - "maxItems": 0, - "type": "array" + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" } } }, - "description": "Update accepted and pending activation of the new email" + "description": "Conversation updated" }, "204": { - "content": { - "application/json": { - "schema": { - "example": [], - "items": {}, - "maxItems": 0, - "type": "array" - } - }, - "application/json;charset=utf-8": { - "schema": { - "example": [], - "items": {}, - "maxItems": 0, - "type": "array" - } - } - }, - "description": "No update, current and new email address are the same" + "description": "Conversation unchanged" }, "400": { "content": { @@ -6988,8 +15012,8 @@ "schema": { "example": { "code": 400, - "label": "invalid-email", - "message": "Invalid e-mail address." + "label": "mls-group-id-not-supported", + "message": "The group ID version of the conversation is not supported by one of the federated backends" }, "properties": { "code": { @@ -7000,7 +15024,7 @@ }, "label": { "enum": [ - "invalid-email" + "mls-group-id-not-supported" ], "type": "string" }, @@ -7017,7 +15041,7 @@ } } }, - "description": "Invalid e-mail address. (label: `invalid-email`) or `body`" + "description": "Invalid `body`\n\nThe group ID version of the conversation is not supported by one of the federated backends (label: `mls-group-id-not-supported`)" }, "403": { "content": { @@ -7025,8 +15049,8 @@ "schema": { "example": { "code": 403, - "label": "invalid-credentials", - "message": "Authentication failed" + "label": "missing-legalhold-consent", + "message": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent" }, "properties": { "code": { @@ -7037,8 +15061,13 @@ }, "label": { "enum": [ - "invalid-credentials", - "blacklisted-email" + "missing-legalhold-consent", + "not-connected", + "no-team-member", + "access-denied", + "too-many-members", + "invalid-op", + "action-denied" ], "type": "string" }, @@ -7055,27 +15084,27 @@ } } }, - "description": "Authentication failed (label: `invalid-credentials`)\n\nThe given e-mail address has been blacklisted due to a permanent bounce or a complaint. (label: `blacklisted-email`)" + "description": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nUsers are not connected (label: `not-connected`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nConversation access denied (label: `access-denied`)\n\nMaximum number of members per conversation reached (label: `too-many-members`)\n\nInvalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing leave_conversation) (label: `action-denied`)\n\nInsufficient authorization (missing add_conversation_member) (label: `action-denied`)" }, - "409": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 409, - "label": "key-exists", - "message": "The given e-mail address is in use." + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { "enum": [ - 409 + 404 ], "type": "integer" }, "label": { "enum": [ - "key-exists" + "no-conversation" ], "type": "string" }, @@ -7092,74 +15121,151 @@ } } }, - "description": "The given e-mail address is in use. (label: `key-exists`)" + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "non_federating_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "non_federating_backends" + ], + "type": "object" + } + } + }, + "description": "Adding members to the conversation is not possible because the backends involved do not form a fully connected graph" + }, + "533": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "unreachable_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "unreachable_backends" + ], + "type": "object" + } + } + }, + "description": "Some domains are unreachable" } }, - "summary": "Change your email address" - } - }, - "/activate": { - "get": { - "description": " [internal route ID: \"get-activate\"]\n\nSee also 'POST /activate' which has a larger feature set.
Calls federation service brig on send-connection-action", + "summary": "Add qualified members to an existing conversation." + }, + "put": { + "description": " [internal route ID: \"replace-members-in-conversation@v16\"]\n\nThis will add any members not already in the conversation, and remove any members not in the provided list except users that are associated via a user group. The given role in the request body will be applied to all added members. The roles of already existing members will not be changed even if these members are included in the request body and their role differs from the role provided in this request.", + "operationId": "replace-members-in-conversation@v16", "parameters": [ { - "description": "Activation key", - "in": "query", - "name": "key", + "in": "path", + "name": "cnv_domain", "required": true, "schema": { "type": "string" } }, { - "description": "Activation code", - "in": "query", - "name": "code", + "in": "path", + "name": "cnv", "required": true, "schema": { + "format": "uuid", "type": "string" } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/InviteQualified_ODYyODIyNjYz" + } + } + }, + "required": true + }, "responses": { "200": { + "description": "Conversation members replaced" + }, + "400": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ActivationResponse" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ActivationResponse" + "example": { + "code": 400, + "label": "mls-group-id-not-supported", + "message": "The group ID version of the conversation is not supported by one of the federated backends" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-group-id-not-supported" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "Activation successful.\n\nActivation successful. (Dry run)\n\nActivation successful." - }, - "204": { - "description": "A recent activation was already successful." + "description": "Invalid `body`\n\nThe group ID version of the conversation is not supported by one of the federated backends (label: `mls-group-id-not-supported`)" }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "invalid-phone", - "message": "Invalid mobile phone number" + "code": 403, + "label": "missing-legalhold-consent", + "message": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "invalid-phone", - "invalid-email" + "missing-legalhold-consent", + "not-connected", + "no-team-member", + "access-denied", + "too-many-members", + "invalid-op", + "action-denied" ], "type": "string" }, @@ -7176,7 +15282,7 @@ } } }, - "description": "Invalid `code` or `key`\n\nInvalid mobile phone number (label: `invalid-phone`)\n\nInvalid e-mail address. (label: `invalid-email`)" + "description": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nUsers are not connected (label: `not-connected`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nConversation access denied (label: `access-denied`)\n\nMaximum number of members per conversation reached (label: `too-many-members`)\n\nInvalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing leave_conversation) (label: `action-denied`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)\n\nInsufficient authorization (missing add_conversation_member) (label: `action-denied`)" }, "404": { "content": { @@ -7184,8 +15290,8 @@ "schema": { "example": { "code": 404, - "label": "invalid-code", - "message": "Invalid activation code" + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { @@ -7196,7 +15302,7 @@ }, "label": { "enum": [ - "invalid-code" + "no-conversation" ], "type": "string" }, @@ -7213,27 +15319,155 @@ } } }, - "description": "Invalid activation code (label: `invalid-code`)\n\nUser does not exist (label: `invalid-code`)" + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" }, "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "non_federating_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "non_federating_backends" + ], + "type": "object" + } + } + }, + "description": "Adding members to the conversation is not possible because the backends involved do not form a fully connected graph" + }, + "533": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "unreachable_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "unreachable_backends" + ], + "type": "object" + } + } + }, + "description": "Some domains are unreachable" + } + }, + "summary": "Replace the members of a conversation." + } + }, + "/conversations/{cnv_domain}/{cnv}/members/{usr_domain}/{usr}": { + "delete": { + "description": " [internal route ID: \"remove-member\"]\n\n", + "operationId": "remove-member", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "usr_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Target User ID", + "in": "path", + "name": "usr", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "Member removed" + }, + "204": { + "description": "No change" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "eligible_members": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "type": "array" + } + }, + "required": [ + "eligible_members" + ], + "type": "object" + } + } + }, + "description": "The conversation would be left without an admin\n\nInvalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)" + }, + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 409, - "label": "key-exists", - "message": "The given e-mail address is in use." + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { "enum": [ - 409 + 404 ], "type": "integer" }, "label": { "enum": [ - "key-exists" + "no-conversation" ], "type": "string" }, @@ -7250,18 +15484,57 @@ } } }, - "description": "The given e-mail address is in use. (label: `key-exists`)" + "description": "`cnv_domain` or `cnv` or `usr_domain` or `usr` not found\n\nConversation not found (label: `no-conversation`)" } }, - "summary": "Activate (i.e. confirm) an email address." + "summary": "Remove a member from a conversation" }, - "post": { - "description": " [internal route ID: \"post-activate\"]\n\nActivation only succeeds once and the number of failed attempts for a valid key is limited.Calls federation service brig on send-connection-action", + "put": { + "description": " [internal route ID: \"update-other-member\"]\n\n**Note**: at least one field has to be provided.", + "operationId": "update-other-member", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "usr_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Target User ID", + "in": "path", + "name": "usr", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Activate" + "$ref": "#/components/schemas/OtherMemberUpdate_LTM1MjYzOTU0" } } }, @@ -7269,43 +15542,28 @@ }, "responses": { "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ActivationResponse" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ActivationResponse" - } - } - }, - "description": "Activation successful.\n\nActivation successful. (Dry run)\n\nActivation successful." - }, - "204": { - "description": "A recent activation was already successful." + "description": "Membership updated" }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "invalid-phone", - "message": "Invalid mobile phone number" + "code": 403, + "label": "invalid-op", + "message": "Invalid operation" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "invalid-phone", - "invalid-email" + "invalid-op", + "action-denied" ], "type": "string" }, @@ -7322,7 +15580,7 @@ } } }, - "description": "Invalid `body`\n\nInvalid mobile phone number (label: `invalid-phone`)\n\nInvalid e-mail address. (label: `invalid-email`)" + "description": "Invalid operation (label: `invalid-op`)\n\nInvalid target (label: `invalid-op`)\n\nInsufficient authorization (missing modify_other_conversation_member) (label: `action-denied`)" }, "404": { "content": { @@ -7330,8 +15588,8 @@ "schema": { "example": { "code": 404, - "label": "invalid-code", - "message": "Invalid activation code" + "label": "no-conversation-member", + "message": "Conversation member not found" }, "properties": { "code": { @@ -7342,44 +15600,8 @@ }, "label": { "enum": [ - "invalid-code" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } - } - }, - "description": "Invalid activation code (label: `invalid-code`)\n\nUser does not exist (label: `invalid-code`)" - }, - "409": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 409, - "label": "key-exists", - "message": "The given e-mail address is in use." - }, - "properties": { - "code": { - "enum": [ - 409 - ], - "type": "integer" - }, - "label": { - "enum": [ - "key-exists" + "no-conversation-member", + "no-conversation" ], "type": "string" }, @@ -7396,20 +15618,41 @@ } } }, - "description": "The given e-mail address is in use. (label: `key-exists`)" + "description": "`cnv_domain` or `cnv` or `usr_domain` or `usr` not found\n\nConversation member not found (label: `no-conversation-member`)\n\nConversation not found (label: `no-conversation`)" } }, - "summary": "Activate (i.e. confirm) an email address." + "summary": "Update membership of the specified user" } }, - "/activate/send": { - "post": { - "description": " [internal route ID: \"post-activate-send\"]\n\n", + "/conversations/{cnv_domain}/{cnv}/message-timer": { + "put": { + "description": " [internal route ID: \"update-conversation-message-timer\"]\n\n", + "operationId": "update-conversation-message-timer", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/SendActivationCode" + "$ref": "#/components/schemas/ConversationMessageTimerUpdate_LTcxMjUwNzQ4" } } }, @@ -7417,27 +15660,44 @@ }, "responses": { "200": { - "description": "Activation code sent." + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "Message timer updated" }, - "400": { + "204": { + "description": "Message timer unchanged" + }, + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "invalid-email", - "message": "Invalid e-mail address." + "code": 403, + "label": "invalid-op", + "message": "Invalid operation" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "invalid-email" + "invalid-op", + "access-denied", + "action-denied" ], "type": "string" }, @@ -7454,27 +15714,27 @@ } } }, - "description": "Invalid `body`\n\nInvalid e-mail address. (label: `invalid-email`)" + "description": "Invalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)\n\nInsufficient authorization (missing modify_conversation_message_timer) (label: `action-denied`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "blacklisted-email", - "message": "The given e-mail address has been blacklisted due to a permanent bounce or a complaint." + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "blacklisted-email" + "no-conversation" ], "type": "string" }, @@ -7491,27 +15751,85 @@ } } }, - "description": "The given e-mail address has been blacklisted due to a permanent bounce or a complaint. (label: `blacklisted-email`)" + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Update the message timer for a conversation" + } + }, + "/conversations/{cnv_domain}/{cnv}/name": { + "put": { + "description": " [internal route ID: \"update-conversation-name\"]\n\n\nOAuth scope: `write:conversations_name`", + "operationId": "update-conversation-name", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } }, - "409": { + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationRename_ODkwODg1MzQ0" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "Name unchanged" + }, + "204": { + "description": "Name updated" + }, + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 409, - "label": "key-exists", - "message": "The given e-mail address is in use." + "code": 403, + "label": "invalid-op", + "message": "Invalid operation" }, "properties": { "code": { "enum": [ - 409 + 403 ], "type": "integer" }, "label": { "enum": [ - "key-exists" + "invalid-op", + "action-denied" ], "type": "string" }, @@ -7528,27 +15846,27 @@ } } }, - "description": "The given e-mail address is in use. (label: `key-exists`)" + "description": "Invalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing modify_conversation_name) (label: `action-denied`)" }, - "451": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 451, - "label": "domain-blocked-for-registration", - "message": "[Customer extension] the email domain example.com that you are attempting to register a user with has been blocked for creating wire users. Please contact your IT department." + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { "enum": [ - 451 + 404 ], "type": "integer" }, "label": { "enum": [ - "domain-blocked-for-registration" + "no-conversation" ], "type": "string" }, @@ -7565,85 +15883,82 @@ } } }, - "description": "[Customer extension] the email domain example.com that you are attempting to register a user with has been blocked for creating wire users. Please contact your IT department. (label: `domain-blocked-for-registration`)" + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" } }, - "summary": "Send (or resend) an email activation code." - } - }, - "/api-version": { - "get": { - "description": " [internal route ID: \"get-version\"]\n\n", - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/VersionInfo" - } - } - }, - "description": "" - } - } + "summary": "Update conversation name" } }, - "/assets": { + "/conversations/{cnv_domain}/{cnv}/proteus/messages": { "post": { + "description": " [internal route ID: \"post-proteus-message\"]\n\nThis endpoint ensures that the list of clients is correct and only sends the message if the list is correct.\nTo override this, the endpoint accepts `client_mismatch_strategy` in the body. It can have these values:\n- `report_all`: When set, the message is not sent if any clients are missing. The missing clients are reported in the response.\n- `ignore_all`: When set, no checks about missing clients are carried out.\n- `report_only`: Takes a list of qualified UserIDs. If any clients of the listed users are missing, the message is not sent. The missing clients are reported in the response.\n- `ignore_only`: Takes a list of qualified UserIDs. If any clients of the non-listed users are missing, the message is not sent. The missing clients are reported in the response.\n\nThe sending of messages in a federated conversation could theoretically fail partially. To make this case unlikely, the backend first gets a list of clients from all the involved backends and then tries to send a message. So, if any backend is down, the message is not propagated to anyone. But the actual message fan out to multiple backends could still fail partially. This type of failure is reported as a 201, the clients for which the message sending failed are part of the response body.\n\nThis endpoint can lead to OtrMessageAdd event being sent to the recipients.\n\n**NOTE:** The protobuf definitions of the request body can be found at https://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto.", + "operationId": "post-proteus-message", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], "requestBody": { "content": { - "multipart/mixed": { + "application/x-protobuf": { "schema": { - "$ref": "#/components/schemas/AssetSource" + "$ref": "#/components/schemas/QualifiedNewOtrMessage" } } }, - "description": "A body with content type `multipart/mixed body`. The first section's content type should be `application/json`. The second section's content type should be always be `application/octet-stream`. Other content types will be ignored by the server." + "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Asset" + "$ref": "#/components/schemas/MessageSendingStatus_ODg0NDgyNDk4" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Asset" + "$ref": "#/components/schemas/MessageSendingStatus_ODg0NDgyNDk4" } } }, - "description": "Asset posted", - "headers": { - "Location": { - "description": "Asset location", - "schema": { - "format": "url", - "type": "string" - } - } - } + "description": "Message sent" }, - "400": { + "403": { "content": { - "application/json;charset=utf-8": { + "application/json": { "schema": { "example": { - "code": 400, - "label": "invalid-length", - "message": "Invalid content length" + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "invalid-length" + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" ], "type": "string" }, @@ -7658,29 +15973,26 @@ ], "type": "object" } - } - }, - "description": "Invalid `body`\n\nInvalid content length (label: `invalid-length`)" - }, - "413": { - "content": { + }, "application/json;charset=utf-8": { "schema": { "example": { - "code": 413, - "label": "client-error", - "message": "Asset too large" + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" }, "properties": { "code": { "enum": [ - 413 + 403 ], "type": "integer" }, "label": { "enum": [ - "client-error" + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" ], "type": "string" }, @@ -7697,56 +16009,27 @@ } } }, - "description": "Asset too large (label: `client-error`)" - } - }, - "summary": "Upload an asset" - } - }, - "/assets/{key_domain}/{key}": { - "delete": { - "description": "**Note**: only local assets can be deleted.", - "parameters": [ - { - "in": "path", - "name": "key_domain", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "path", - "name": "key", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Asset deleted" + "description": "Unknown Client (label: `unknown-client`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)" }, - "403": { + "404": { "content": { - "application/json;charset=utf-8": { + "application/json": { "schema": { "example": { - "code": 403, - "label": "unauthorised", - "message": "Unauthorised operation" + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "unauthorised" + "no-conversation" ], "type": "string" }, @@ -7761,18 +16044,13 @@ ], "type": "object" } - } - }, - "description": "Unauthorised operation (label: `unauthorised`)" - }, - "404": { - "content": { + }, "application/json;charset=utf-8": { "schema": { "example": { "code": 404, - "label": "not-found", - "message": "Asset not found" + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { @@ -7783,7 +16061,7 @@ }, "label": { "enum": [ - "not-found" + "no-conversation" ], "type": "string" }, @@ -7800,82 +16078,99 @@ } } }, - "description": "`key_domain` or `key` not found\n\nAsset not found (label: `not-found`)" + "description": "`cnv_domain` or `cnv` or Conversation not found (label: `no-conversation`)" + }, + "412": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageSendingStatus_ODg0NDgyNDk4" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MessageSendingStatus_ODg0NDgyNDk4" + } + } + }, + "description": "Missing clients" } }, - "summary": "Delete an asset" - }, - "get": { - "description": "**Note**: local assets result in a redirect, while remote assets are streamed directly.Calls federation service cargohold on stream-asset
Calls federation service cargohold on get-asset", + "summary": "Post an encrypted message to a conversation (accepts only Protobuf)" + } + }, + "/conversations/{cnv_domain}/{cnv}/protocol": { + "put": { + "description": " [internal route ID: \"update-conversation-protocol\"]\n\n**Note**: Only proteus->mixed upgrade is supported.", + "operationId": "update-conversation-protocol", "parameters": [ { "in": "path", - "name": "key_domain", + "name": "cnv_domain", "required": true, "schema": { "type": "string" } }, { + "description": "Conversation ID", "in": "path", - "name": "key", + "name": "cnv", "required": true, "schema": { - "type": "string" - } - }, - { - "in": "header", - "name": "Asset-Token", - "required": false, - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "asset_token", - "required": false, - "schema": { + "format": "uuid", "type": "string" } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ProtocolUpdate_NzY1ODgxNDQy" + } + } + }, + "required": true + }, "responses": { "200": { - "description": "Asset returned directly with content type `application/octet-stream`" - }, - "302": { - "description": "Asset found", - "headers": { - "Location": { - "description": "Asset location", + "content": { + "application/json": { "schema": { - "format": "url", - "type": "string" + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" } } - } + }, + "description": "Conversation updated" }, - "404": { + "204": { + "description": "Conversation unchanged" + }, + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "not-found", - "message": "Asset not found" + "code": 400, + "label": "mls-migration-criteria-not-satisfied", + "message": "The migration criteria for mixed to MLS protocol transition are not satisfied for this conversation" }, "properties": { "code": { "enum": [ - 404 + 400 ], "type": "integer" }, "label": { "enum": [ - "not-found" + "mls-migration-criteria-not-satisfied" ], "type": "string" }, @@ -7892,53 +16187,7 @@ } } }, - "description": "`key_domain` or `key` or Asset not found (label: `not-found`)\n\nAsset not found (label: `not-found`)" - } - }, - "summary": "Download an asset" - } - }, - "/assets/{key}/token": { - "delete": { - "description": "**Note**: deleting the token makes the asset public.", - "parameters": [ - { - "in": "path", - "name": "key", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Asset token deleted" - } - }, - "summary": "Delete an asset token" - }, - "post": { - "parameters": [ - { - "in": "path", - "name": "key", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/NewAssetToken" - } - } - }, - "description": "" + "description": "Invalid `body`\n\nThe migration criteria for mixed to MLS protocol transition are not satisfied for this conversation (label: `mls-migration-criteria-not-satisfied`)" }, "403": { "content": { @@ -7946,8 +16195,8 @@ "schema": { "example": { "code": 403, - "label": "unauthorised", - "message": "Unauthorised operation" + "label": "operation-denied", + "message": "Insufficient permissions" }, "properties": { "code": { @@ -7958,7 +16207,11 @@ }, "label": { "enum": [ - "unauthorised" + "operation-denied", + "no-team-member", + "invalid-op", + "action-denied", + "invalid-protocol-transition" ], "type": "string" }, @@ -7975,7 +16228,7 @@ } } }, - "description": "Unauthorised operation (label: `unauthorised`)" + "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInvalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing leave_conversation) (label: `action-denied`)\n\nProtocol transition is invalid (label: `invalid-protocol-transition`)" }, "404": { "content": { @@ -7983,8 +16236,8 @@ "schema": { "example": { "code": 404, - "label": "not-found", - "message": "Asset not found" + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { @@ -7995,7 +16248,8 @@ }, "label": { "enum": [ - "not-found" + "no-team", + "no-conversation" ], "type": "string" }, @@ -8012,97 +16266,87 @@ } } }, - "description": "`key` not found\n\nAsset not found (label: `not-found`)" + "description": "`cnv_domain` or `cnv` not found\n\nTeam not found (label: `no-team`)\n\nConversation not found (label: `no-conversation`)" } }, - "summary": "Renew an asset token" + "summary": "Update the protocol of the conversation" } }, - "/await": { - "get": { - "description": " [internal route ID: \"await-notifications\"]\n\n", - "externalDocs": { - "description": "RFC 6455", - "url": "https://datatracker.ietf.org/doc/html/rfc6455" - }, + "/conversations/{cnv_domain}/{cnv}/receipt-mode": { + "put": { + "description": " [internal route ID: \"update-conversation-receipt-mode\"]\n\n", + "operationId": "update-conversation-receipt-mode", "parameters": [ { - "description": "Client ID", - "in": "query", - "name": "client", - "required": false, + "in": "path", + "name": "cnv_domain", + "required": true, "schema": { "type": "string" } - } - ], - "responses": { - "101": { - "description": "Connection upgraded." }, - "426": { - "description": "Upgrade required." + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } } - }, - "summary": "Establish websocket connection" - } - }, - "/bot/assets": { - "post": { + ], "requestBody": { "content": { - "multipart/mixed": { + "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/AssetSource" + "$ref": "#/components/schemas/ConversationReceiptModeUpdate_NDE4MzUzNTU3" } } }, - "description": "A body with content type `multipart/mixed body`. The first section's content type should be `application/json`. The second section's content type should be always be `application/octet-stream`. Other content types will be ignored by the server." + "required": true }, "responses": { - "201": { + "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Asset" + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Asset" + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" } } }, - "description": "Asset posted", - "headers": { - "Location": { - "description": "Asset location", - "schema": { - "format": "url", - "type": "string" - } - } - } + "description": "Receipt mode updated" }, - "400": { + "204": { + "description": "Receipt mode unchanged" + }, + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "invalid-length", - "message": "Invalid content length" + "code": 403, + "label": "mls-receipts-not-allowed", + "message": "Read receipts on MLS conversations are not allowed" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "invalid-length" + "mls-receipts-not-allowed", + "invalid-op", + "access-denied", + "action-denied" ], "type": "string" }, @@ -8119,27 +16363,27 @@ } } }, - "description": "Invalid `body`\n\nInvalid content length (label: `invalid-length`)" + "description": "Read receipts on MLS conversations are not allowed (label: `mls-receipts-not-allowed`)\n\nInvalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)\n\nInsufficient authorization (missing modify_conversation_receipt_mode) (label: `action-denied`)" }, - "413": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 413, - "label": "client-error", - "message": "Asset too large" + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { "enum": [ - 413 + 404 ], "type": "integer" }, "label": { "enum": [ - "client-error" + "no-conversation" ], "type": "string" }, @@ -8156,64 +16400,46 @@ } } }, - "description": "Asset too large (label: `client-error`)" + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" } }, - "summary": "Upload an asset" + "summary": "Update receipt mode for a conversation" } }, - "/bot/assets/{key}": { - "delete": { + "/conversations/{cnv_domain}/{cnv}/self": { + "get": { + "description": " [internal route ID: \"get-conversation-self\"]\n\n", + "operationId": "get-conversation-self", "parameters": [ { "in": "path", - "name": "key", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", "required": true, "schema": { + "format": "uuid", "type": "string" } } ], "responses": { "200": { - "description": "Asset deleted" - }, - "403": { "content": { "application/json;charset=utf-8": { "schema": { - "example": { - "code": 403, - "label": "unauthorised", - "message": "Unauthorised operation" - }, - "properties": { - "code": { - "enum": [ - 403 - ], - "type": "integer" - }, - "label": { - "enum": [ - "unauthorised" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" + "$ref": "#/components/schemas/Member_OTA5OTgyNzcw" } } }, - "description": "Unauthorised operation (label: `unauthorised`)" + "description": "" }, "404": { "content": { @@ -8221,8 +16447,8 @@ "schema": { "example": { "code": 404, - "label": "not-found", - "message": "Asset not found" + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { @@ -8233,7 +16459,7 @@ }, "label": { "enum": [ - "not-found" + "no-conversation" ], "type": "string" }, @@ -8250,91 +16476,56 @@ } } }, - "description": "`key` not found\n\nAsset not found (label: `not-found`)" + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" } }, - "summary": "Delete an asset" + "summary": "Get self membership properties" }, - "get": { + "put": { + "description": " [internal route ID: \"update-conversation-self\"]\n\n**Note**: at least one field has to be provided.", + "operationId": "update-conversation-self", "parameters": [ { "in": "path", - "name": "key", + "name": "cnv_domain", "required": true, "schema": { "type": "string" } }, { - "in": "header", - "name": "Asset-Token", - "required": false, - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "asset_token", - "required": false, + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, "schema": { + "format": "uuid", "type": "string" } } ], - "responses": { - "302": { - "description": "Asset found", - "headers": { - "Location": { - "description": "Asset location", - "schema": { - "format": "url", - "type": "string" - } + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MemberUpdate_LTg4NTQ0OTYz" } } }, + "required": true + }, + "responses": { + "200": { + "description": "Update successful" + }, "404": { "content": { - "application/json": { - "schema": { - "example": { - "code": 404, - "label": "not-found", - "message": "Asset not found" - }, - "properties": { - "code": { - "enum": [ - 404 - ], - "type": "integer" - }, - "label": { - "enum": [ - "not-found" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } - }, "application/json;charset=utf-8": { "schema": { "example": { "code": 404, - "label": "not-found", - "message": "Asset not found" + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { @@ -8345,7 +16536,7 @@ }, "label": { "enum": [ - "not-found" + "no-conversation" ], "type": "string" }, @@ -8362,50 +16553,94 @@ } } }, - "description": "`key` or Asset not found (label: `not-found`)" + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" } }, - "summary": "Download an asset" + "summary": "Update self membership properties" } }, - "/bot/client": { - "get": { - "description": " [internal route ID: \"bot-get-client-v6\"]\n\n", + "/conversations/{cnv_domain}/{cnv}/subconversations/{subconv}": { + "delete": { + "description": " [internal route ID: \"delete-subconversation\"]\n\n", + "operationId": "delete-subconversation", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "subconv", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MLSReset_NzgwODA3ODc4" + } + } + }, + "required": true + }, "responses": { "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Clientv6" + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Clientv6" + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" } } }, - "description": "Client found" + "description": "Deletion successful" }, - "403": { + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "access-denied", - "message": "Access denied." + "code": 400, + "label": "mls-not-enabled", + "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" }, "properties": { "code": { "enum": [ - 403 + 400 ], "type": "integer" }, "label": { "enum": [ - "access-denied" + "mls-not-enabled" ], "type": "string" }, @@ -8422,27 +16657,27 @@ } } }, - "description": "Access denied. (label: `access-denied`)" + "description": "Invalid `body`\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" }, - "404": { + "403": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "client-not-found", - "message": "Client not found" + "code": 403, + "label": "access-denied", + "message": "Conversation access denied" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "client-not-found" + "access-denied" ], "type": "string" }, @@ -8457,13 +16692,18 @@ ], "type": "object" } - }, + } + }, + "description": "Conversation access denied (label: `access-denied`)" + }, + "404": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { "code": 404, - "label": "client-not-found", - "message": "Client not found" + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { @@ -8474,7 +16714,7 @@ }, "label": { "enum": [ - "client-not-found" + "no-conversation" ], "type": "string" }, @@ -8491,50 +16731,27 @@ } } }, - "description": "Client not found (label: `client-not-found`)\n\nClient not found (label: `client-not-found`)" - } - }, - "summary": "Get client for bot" - } - }, - "/bot/client/prekeys": { - "get": { - "description": " [internal route ID: \"bot-list-prekeys\"]\n\n", - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "items": { - "maximum": 65535, - "minimum": 0, - "type": "integer" - }, - "type": "array" - } - } - }, - "description": "" + "description": "`cnv_domain` or `cnv` or `subconv` not found\n\nConversation not found (label: `no-conversation`)" }, - "403": { + "409": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "access-denied", - "message": "Access denied." + "code": 409, + "label": "mls-stale-message", + "message": "The conversation epoch in a message is too old" }, "properties": { "code": { "enum": [ - 403 + 409 ], "type": "integer" }, "label": { "enum": [ - "access-denied" + "mls-stale-message" ], "type": "string" }, @@ -8551,26 +16768,56 @@ } } }, - "description": "Access denied. (label: `access-denied`)" + "description": "The conversation epoch in a message is too old (label: `mls-stale-message`)" } }, - "summary": "List prekeys for bot" + "summary": "Delete an MLS subconversation" }, - "post": { - "description": " [internal route ID: \"bot-update-prekeys\"]\n\n", - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/UpdateBotPrekeys" - } + "get": { + "description": " [internal route ID: \"get-subconversation\"]\n\n", + "operationId": "get-subconversation", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" } }, - "required": true - }, + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "subconv", + "required": true, + "schema": { + "type": "string" + } + } + ], "responses": { "200": { - "description": "" + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicSubConversation_MjI2NTIxMzU4" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PublicSubConversation_MjI2NTIxMzU4" + } + } + }, + "description": "Subconversation" }, "403": { "content": { @@ -8578,8 +16825,8 @@ "schema": { "example": { "code": 403, - "label": "access-denied", - "message": "Access denied." + "label": "mls-subconv-unsupported-convtype", + "message": "MLS subconversations are only supported for regular conversations" }, "properties": { "code": { @@ -8590,6 +16837,7 @@ }, "label": { "enum": [ + "mls-subconv-unsupported-convtype", "access-denied" ], "type": "string" @@ -8607,7 +16855,7 @@ } } }, - "description": "Access denied. (label: `access-denied`)" + "description": "MLS subconversations are only supported for regular conversations (label: `mls-subconv-unsupported-convtype`)\n\nConversation access denied (label: `access-denied`)" }, "404": { "content": { @@ -8615,8 +16863,8 @@ "schema": { "example": { "code": 404, - "label": "client-not-found", - "message": "Client not found" + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { @@ -8627,7 +16875,7 @@ }, "label": { "enum": [ - "client-not-found" + "no-conversation" ], "type": "string" }, @@ -8644,47 +16892,73 @@ } } }, - "description": "Client not found (label: `client-not-found`)" + "description": "`cnv_domain` or `cnv` or `subconv` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Get information about an MLS subconversation" + } + }, + "/conversations/{cnv_domain}/{cnv}/subconversations/{subconv}/groupinfo": { + "get": { + "description": " [internal route ID: \"get-subconversation-group-info\"]\n\n", + "operationId": "get-subconversation-group-info", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "subconv", + "required": true, + "schema": { + "type": "string" + } } - }, - "summary": "Update prekeys for bot" - } - }, - "/bot/conversation": { - "get": { - "description": " [internal route ID: \"get-bot-conversation\"]\n\n", + ], "responses": { "200": { "content": { - "application/json;charset=utf-8": { + "message/mls": { "schema": { - "$ref": "#/components/schemas/BotConvView" + "$ref": "#/components/schemas/GroupInfoData" } } }, - "description": "" + "description": "The group information" }, - "403": { + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "code": 400, + "label": "mls-not-enabled", + "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" }, "properties": { "code": { "enum": [ - 403 + 400 ], "type": "integer" }, "label": { "enum": [ - "no-team-member", - "operation-denied", - "access-denied" + "mls-not-enabled" ], "type": "string" }, @@ -8701,7 +16975,7 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)\n\nYou do not have permission to access this resource (label: `access-denied`)" + "description": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" }, "404": { "content": { @@ -8709,8 +16983,8 @@ "schema": { "example": { "code": 404, - "label": "no-team", - "message": "Team not found" + "label": "mls-missing-group-info", + "message": "The conversation has no group information" }, "properties": { "code": { @@ -8721,7 +16995,7 @@ }, "label": { "enum": [ - "no-team", + "mls-missing-group-info", "no-conversation" ], "type": "string" @@ -8739,79 +17013,67 @@ } } }, - "description": "Team not found (label: `no-team`)\n\nConversation not found (label: `no-conversation`)" + "description": "`cnv_domain` or `cnv` or `subconv` not found\n\nThe conversation has no group information (label: `mls-missing-group-info`)\n\nConversation not found (label: `no-conversation`)" } - } + }, + "summary": "Get MLS group information of subconversation" } }, - "/bot/messages": { - "post": { - "description": " [internal route ID: \"post-bot-message-unqualified\"]\n\nCalls federation service brig on get-user-clients
Calls federation service galley on on-message-sent", + "/conversations/{cnv_domain}/{cnv}/subconversations/{subconv}/self": { + "delete": { + "description": " [internal route ID: \"leave-subconversation\"]\n\n", + "operationId": "leave-subconversation", "parameters": [ { - "in": "query", - "name": "ignore_missing", - "required": false, + "in": "path", + "name": "cnv_domain", + "required": true, "schema": { "type": "string" } }, { - "in": "query", - "name": "report_missing", - "required": false, + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "subconv", + "required": true, "schema": { "type": "string" } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/new-otr-message" - } - } - }, - "required": true - }, "responses": { - "201": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClientMismatch" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ClientMismatch" - } - } - }, - "description": "Message sent" + "200": { + "description": "OK" }, - "403": { + "400": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "unknown-client", - "message": "Unknown Client" + "code": 400, + "label": "mls-not-enabled", + "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" }, "properties": { "code": { "enum": [ - 403 + 400 ], "type": "integer" }, "label": { "enum": [ - "unknown-client", - "missing-legalhold-consent-old-clients", - "missing-legalhold-consent" + "mls-not-enabled", + "mls-protocol-error" ], "type": "string" }, @@ -8826,13 +17088,18 @@ ], "type": "object" } - }, + } + }, + "description": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)\n\nMLS protocol error (label: `mls-protocol-error`)" + }, + "403": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { "code": 403, - "label": "unknown-client", - "message": "Unknown Client" + "label": "access-denied", + "message": "Conversation access denied" }, "properties": { "code": { @@ -8843,9 +17110,7 @@ }, "label": { "enum": [ - "unknown-client", - "missing-legalhold-consent-old-clients", - "missing-legalhold-consent" + "access-denied" ], "type": "string" }, @@ -8862,11 +17127,11 @@ } } }, - "description": "Unknown Client (label: `unknown-client`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)" + "description": "Conversation access denied (label: `access-denied`)" }, "404": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { "code": 404, @@ -8897,24 +17162,29 @@ ], "type": "object" } - }, + } + }, + "description": "`cnv_domain` or `cnv` or `subconv` not found\n\nConversation not found (label: `no-conversation`)" + }, + "409": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "code": 409, + "label": "mls-stale-message", + "message": "The conversation epoch in a message is too old" }, "properties": { "code": { "enum": [ - 404 + 409 ], "type": "integer" }, "label": { "enum": [ - "no-conversation" + "mls-stale-message" ], "type": "string" }, @@ -8931,53 +17201,69 @@ } } }, - "description": "Conversation not found (label: `no-conversation`)\n\nConversation not found (label: `no-conversation`)" - }, - "412": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClientMismatch" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ClientMismatch" - } - } - }, - "description": "Missing clients" + "description": "The conversation epoch in a message is too old (label: `mls-stale-message`)" } - } + }, + "summary": "Leave an MLS subconversation" } }, - "/bot/self": { - "delete": { - "description": " [internal route ID: \"bot-delete-self\"]\n\n", + "/conversations/{cnv_domain}/{cnv}/typing": { + "post": { + "description": " [internal route ID: \"member-typing-qualified\"]\n\n", + "operationId": "member-typing-qualified", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/TypingStatus_LTg5MzcyNDMy" + } + } + }, + "required": true + }, "responses": { "200": { - "description": "" + "description": "Notification sent" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "invalid-bot", - "message": "The targeted user is not a bot." + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "invalid-bot", - "access-denied" + "no-conversation" ], "type": "string" }, @@ -8994,23 +17280,43 @@ } } }, - "description": "The targeted user is not a bot. (label: `invalid-bot`)\n\nAccess denied. (label: `access-denied`)" + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" } }, - "summary": "Delete self" - }, - "get": { - "description": " [internal route ID: \"bot-get-self\"]\n\n", + "summary": "Sending typing notifications" + } + }, + "/conversations/{cnv}/code": { + "delete": { + "description": " [internal route ID: \"remove-code-unqualified\"]\n\n", + "operationId": "remove-code-unqualified", + "parameters": [ + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], "responses": { "200": { "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/UserProfile" + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" } } }, - "description": "" + "description": "Conversation code deleted." }, "403": { "content": { @@ -9019,7 +17325,7 @@ "example": { "code": 403, "label": "access-denied", - "message": "Access denied." + "message": "Conversation access denied" }, "properties": { "code": { @@ -9047,7 +17353,7 @@ } } }, - "description": "Access denied. (label: `access-denied`)" + "description": "Conversation access denied (label: `access-denied`)" }, "404": { "content": { @@ -9055,8 +17361,8 @@ "schema": { "example": { "code": 404, - "label": "not-found", - "message": "User not found" + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { @@ -9067,7 +17373,7 @@ }, "label": { "enum": [ - "not-found" + "no-conversation" ], "type": "string" }, @@ -9084,21 +17390,22 @@ } } }, - "description": "User not found (label: `not-found`)" + "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)" } }, - "summary": "Get self" - } - }, - "/bot/users": { + "summary": "Delete conversation code" + }, "get": { - "description": " [internal route ID: \"bot-list-users\"]\n\n", + "description": " [internal route ID: \"get-code\"]\n\n\nOAuth scope: `write:conversations_code`", + "operationId": "get-code", "parameters": [ { - "in": "query", - "name": "ids", + "description": "Conversation ID", + "in": "path", + "name": "cnv", "required": true, "schema": { + "format": "uuid", "type": "string" } } @@ -9106,16 +17413,18 @@ "responses": { "200": { "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConversationCodeInfo_LTc5MzgzNjg3" + } + }, "application/json;charset=utf-8": { "schema": { - "items": { - "$ref": "#/components/schemas/BotUserView" - }, - "type": "array" + "$ref": "#/components/schemas/ConversationCodeInfo_LTc5MzgzNjg3" } } }, - "description": "" + "description": "Conversation Code" }, "403": { "content": { @@ -9124,7 +17433,7 @@ "example": { "code": 403, "label": "access-denied", - "message": "Access denied." + "message": "Conversation access denied" }, "properties": { "code": { @@ -9152,58 +17461,28 @@ } } }, - "description": "Access denied. (label: `access-denied`)" - } - }, - "summary": "List users" - } - }, - "/bot/users/prekeys": { - "post": { - "description": " [internal route ID: \"bot-claim-users-prekeys\"]\n\n", - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/UserClients" - } - } - }, - "required": true - }, - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/UserClientPrekeyMap" - } - } - }, - "description": "" + "description": "Conversation access denied (label: `access-denied`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "missing-legalhold-consent", - "message": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent" + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "missing-legalhold-consent", - "missing-legalhold-consent-old-clients", - "too-many-clients", - "access-denied" + "no-conversation", + "no-conversation-code" ], "type": "string" }, @@ -9220,59 +17499,27 @@ } } }, - "description": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)\n\nToo many clients (label: `too-many-clients`)\n\nAccess denied. (label: `access-denied`)" - } - }, - "summary": "Claim users prekeys" - } - }, - "/bot/users/{User ID}/clients": { - "get": { - "description": " [internal route ID: \"bot-get-user-clients\"]\n\n", - "parameters": [ - { - "in": "path", - "name": "User ID", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "items": { - "$ref": "#/components/schemas/PubClient" - }, - "type": "array" - } - } - }, - "description": "" + "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)\n\nConversation code not found (label: `no-conversation-code`)" }, - "403": { + "409": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "access-denied", - "message": "Access denied." + "code": 409, + "label": "guest-links-disabled", + "message": "The guest link feature is disabled and all guest links have been revoked" }, "properties": { "code": { "enum": [ - 403 + 409 ], "type": "integer" }, "label": { "enum": [ - "access-denied" + "guest-links-disabled" ], "type": "string" }, @@ -9289,29 +17536,22 @@ } } }, - "description": "Access denied. (label: `access-denied`)" + "description": "The guest link feature is disabled and all guest links have been revoked (label: `guest-links-disabled`)" } }, - "summary": "Get user clients" - } - }, - "/broadcast/otr/messages": { + "summary": "Get existing conversation code" + }, "post": { - "description": " [internal route ID: \"post-otr-broadcast-unqualified\"]\n\nThis endpoint ensures that the list of clients is correct and only sends the message if the list is correct.\nTo override this, the endpoint accepts two query params:\n- `ignore_missing`: Can be 'true' 'false' or a comma separated list of user IDs.\n - When 'true' all missing clients are ignored.\n - When 'false' all missing clients are reported.\n - When comma separated list of user-ids, only clients for listed users are ignored.\n- `report_missing`: Can be 'true' 'false' or a comma separated list of user IDs.\n - When 'true' all missing clients are reported.\n - When 'false' all missing clients are ignored.\n - When comma separated list of user-ids, only clients for listed users are reported.\n\nApart from these, the request body also accepts `report_missing` which can only be a list of user ids and behaves the same way as the query parameter.\n\nAll three of these should be considered mutually exclusive. The server however does not error if more than one is specified, it reads them in this order of precedence:\n- `report_missing` in the request body has highest precedence.\n- `ignore_missing` in the query param is the next.\n- `report_missing` in the query param has the lowest precedence.\n\nThis endpoint can lead to OtrMessageAdd event being sent to the recipients.\n\n**NOTE:** The protobuf definitions of the request body can be found at https://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto.", + "description": " [internal route ID: \"create-conversation-code-unqualified\"]\n\n\nOAuth scope: `write:conversations_code`", + "operationId": "create-conversation-code-unqualified", "parameters": [ { - "in": "query", - "name": "ignore_missing", - "required": false, - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "report_missing", - "required": false, + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, "schema": { + "format": "uuid", "type": "string" } } @@ -9320,52 +17560,62 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/new-otr-message" - } - }, - "application/x-protobuf": { - "schema": { - "$ref": "#/components/schemas/new-otr-message" + "$ref": "#/components/schemas/CreateConversationCodeRequest_NTYzMTA1NDYz" } } }, "required": true }, "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConversationCodeInfo_LTc5MzgzNjg3" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationCodeInfo_LTc5MzgzNjg3" + } + } + }, + "description": "Conversation code already exists." + }, "201": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ClientMismatch" + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ClientMismatch" + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" } } }, - "description": "Message sent" + "description": "Conversation code created." }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "too-many-users-to-broadcast", - "message": "Too many users to fan out the broadcast event to" + "code": 403, + "label": "access-denied", + "message": "Conversation access denied" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "too-many-users-to-broadcast" + "access-denied" ], "type": "string" }, @@ -9382,29 +17632,27 @@ } } }, - "description": "Invalid `body` or `report_missing` or `ignore_missing`\n\nToo many users to fan out the broadcast event to (label: `too-many-users-to-broadcast`)" + "description": "Conversation access denied (label: `access-denied`)" }, - "403": { + "404": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "unknown-client", - "message": "Unknown Client" + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "unknown-client", - "missing-legalhold-consent-old-clients", - "missing-legalhold-consent" + "no-conversation" ], "type": "string" }, @@ -9419,26 +17667,30 @@ ], "type": "object" } - }, + } + }, + "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)" + }, + "409": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "unknown-client", - "message": "Unknown Client" + "code": 409, + "label": "create-conv-code-conflict", + "message": "Conversation code already exists with a different password setting than the requested one." }, "properties": { "code": { "enum": [ - 403 + 409 ], "type": "integer" }, "label": { "enum": [ - "unknown-client", - "missing-legalhold-consent-old-clients", - "missing-legalhold-consent" + "create-conv-code-conflict", + "guest-links-disabled" ], "type": "string" }, @@ -9455,27 +17707,58 @@ } } }, - "description": "Unknown Client (label: `unknown-client`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)" - }, - "404": { + "description": "Conversation code already exists with a different password setting than the requested one. (label: `create-conv-code-conflict`)\n\nThe guest link feature is disabled and all guest links have been revoked (label: `guest-links-disabled`)" + } + }, + "summary": "Create or recreate a conversation code" + } + }, + "/conversations/{cnv}/features/conversationGuestLinks": { + "get": { + "description": " [internal route ID: \"get-conversation-guest-links-status\"]\n\n", + "operationId": "get-conversation-guest-links-status", + "parameters": [ + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { - "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "$ref": "#/components/schemas/LockableFeature_GuestLinksConfig_LTcwNjU0NDMw" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Conversation access denied" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "no-conversation" + "access-denied" ], "type": "string" }, @@ -9490,7 +17773,12 @@ ], "type": "object" } - }, + } + }, + "description": "Conversation access denied (label: `access-denied`)" + }, + "404": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { @@ -9507,9 +17795,7 @@ }, "label": { "enum": [ - "no-conversation", - "non-binding-team", - "no-team" + "no-conversation" ], "type": "string" }, @@ -9526,35 +17812,53 @@ } } }, - "description": "Conversation not found (label: `no-conversation`)\n\nNot a member of a binding team (label: `non-binding-team`)\n\nTeam not found (label: `no-team`)" - }, - "412": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClientMismatch" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ClientMismatch" - } - } - }, - "description": "Missing clients" + "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)" } }, - "summary": "Broadcast an encrypted message to all team members and all contacts (accepts JSON or Protobuf)" + "summary": "Get the status of the guest links feature for a conversation that potentially has been created by someone from another team." } }, - "/broadcast/proteus/messages": { + "/conversations/{cnv}/otr/messages": { "post": { - "description": " [internal route ID: \"post-proteus-broadcast\"]\n\nThis endpoint ensures that the list of clients is correct and only sends the message if the list is correct.\nTo override this, the endpoint accepts `client_mismatch_strategy` in the body. It can have these values:\n- `report_all`: When set, the message is not sent if any clients are missing. The missing clients are reported in the response.\n- `ignore_all`: When set, no checks about missing clients are carried out.\n- `report_only`: Takes a list of qualified UserIDs. If any clients of the listed users are missing, the message is not sent. The missing clients are reported in the response.\n- `ignore_only`: Takes a list of qualified UserIDs. If any clients of the non-listed users are missing, the message is not sent. The missing clients are reported in the response.\n\nThe sending of messages in a federated conversation could theoretically fail partially. To make this case unlikely, the backend first gets a list of clients from all the involved backends and then tries to send a message. So, if any backend is down, the message is not propagated to anyone. But the actual message fan out to multiple backends could still fail partially. This type of failure is reported as a 201, the clients for which the message sending failed are part of the response body.\n\nThis endpoint can lead to OtrMessageAdd event being sent to the recipients.\n\n**NOTE:** The protobuf definitions of the request body can be found at https://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto.", + "description": " [internal route ID: \"post-otr-message-unqualified\"]\n\nThis endpoint ensures that the list of clients is correct and only sends the message if the list is correct.\nTo override this, the endpoint accepts two query params:\n- `ignore_missing`: Can be 'true' 'false' or a comma separated list of user IDs.\n - When 'true' all missing clients are ignored.\n - When 'false' all missing clients are reported.\n - When comma separated list of user-ids, only clients for listed users are ignored.\n- `report_missing`: Can be 'true' 'false' or a comma separated list of user IDs.\n - When 'true' all missing clients are reported.\n - When 'false' all missing clients are ignored.\n - When comma separated list of user-ids, only clients for listed users are reported.\n\nApart from these, the request body also accepts `report_missing` which can only be a list of user ids and behaves the same way as the query parameter.\n\nAll three of these should be considered mutually exclusive. The server however does not error if more than one is specified, it reads them in this order of precedence:\n- `report_missing` in the request body has highest precedence.\n- `ignore_missing` in the query param is the next.\n- `report_missing` in the query param has the lowest precedence.\n\nThis endpoint can lead to OtrMessageAdd event being sent to the recipients.\n\n**NOTE:** The protobuf definitions of the request body can be found at https://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto.", + "operationId": "post-otr-message-unqualified", + "parameters": [ + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "query", + "name": "ignore_missing", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "report_missing", + "required": false, + "schema": { + "type": "string" + } + } + ], "requestBody": { "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewOtrMessage_LTUyMTE5MTMw" + } + }, "application/x-protobuf": { "schema": { - "$ref": "#/components/schemas/QualifiedNewOtrMessage" + "$ref": "#/components/schemas/NewOtrMessage_LTUyMTE5MTMw" } } }, @@ -9565,54 +17869,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/MessageSendingStatus" + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/MessageSendingStatus" + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" } } }, "description": "Message sent" }, - "400": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 400, - "label": "too-many-users-to-broadcast", - "message": "Too many users to fan out the broadcast event to" - }, - "properties": { - "code": { - "enum": [ - 400 - ], - "type": "integer" - }, - "label": { - "enum": [ - "too-many-users-to-broadcast" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } - } - }, - "description": "Invalid `body`\n\nToo many users to fan out the broadcast event to (label: `too-many-users-to-broadcast`)" - }, "403": { "content": { "application/json": { @@ -9736,9 +18003,7 @@ }, "label": { "enum": [ - "no-conversation", - "non-binding-team", - "no-team" + "no-conversation" ], "type": "string" }, @@ -9755,59 +18020,39 @@ } } }, - "description": "Conversation not found (label: `no-conversation`)\n\nNot a member of a binding team (label: `non-binding-team`)\n\nTeam not found (label: `no-team`)" + "description": "`cnv` or Conversation not found (label: `no-conversation`)" }, "412": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/MessageSendingStatus" + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/MessageSendingStatus" + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" } } }, "description": "Missing clients" } }, - "summary": "Post an encrypted message to all team members and all contacts (accepts only Protobuf)" - } - }, - "/calls/config": { - "get": { - "deprecated": true, - "description": " [internal route ID: \"get-calls-config\"]\n\n", - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/RTCConfiguration" - } - } - }, - "description": "" - } - }, - "summary": "Retrieve TURN server addresses and credentials for IP addresses, scheme `turn` and transport `udp` only (deprecated)" + "summary": "Post an encrypted message to a conversation (accepts JSON or Protobuf)" } }, - "/calls/config/v2": { + "/conversations/{cnv}/roles": { "get": { - "description": " [internal route ID: \"get-calls-config-v2\"]\n\n", + "description": " [internal route ID: \"get-conversation-roles\"]\n\n", + "operationId": "get-conversation-roles", "parameters": [ { - "description": "Limit resulting list. Allowed values [1..10]", - "in": "query", - "name": "limit", - "required": false, + "in": "path", + "name": "cnv", + "required": true, "schema": { - "maximum": 10, - "minimum": 1, - "type": "integer" + "format": "uuid", + "type": "string" } } ], @@ -9816,93 +18061,31 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/RTCConfiguration" + "$ref": "#/components/schemas/ConversationRolesList" } } }, "description": "" - } - }, - "summary": "Retrieve all TURN server addresses and credentials. Clients are expected to do a DNS lookup to resolve the IP addresses of the given hostnames " - } - }, - "/clients": { - "get": { - "description": " [internal route ID: \"list-clients-v6\"]\n\n", - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClientListv6" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ClientListv6" - } - } - }, - "description": "List of clients" - } - }, - "summary": "List the registered clients" - }, - "post": { - "description": " [internal route ID: \"add-client\"]\n\nCalls federation service brig on send-connection-action", - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/NewClient" - } - } - }, - "required": true - }, - "responses": { - "201": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Client" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Client" - } - } - }, - "description": "Client registered", - "headers": { - "Location": { - "description": "Client ID", - "schema": { - "type": "string" - } - } - } }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "bad-request", - "message": "Malformed prekeys uploaded" + "code": 403, + "label": "access-denied", + "message": "Conversation access denied" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "bad-request" + "access-denied" ], "type": "string" }, @@ -9919,30 +18102,27 @@ } } }, - "description": "Invalid `body`\n\nMalformed prekeys uploaded (label: `bad-request`)" + "description": "Conversation access denied (label: `access-denied`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "code-authentication-required", - "message": "Code authentication is required" + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "code-authentication-required", - "code-authentication-failed", - "missing-auth", - "too-many-clients" + "no-conversation" ], "type": "string" }, @@ -9959,29 +18139,22 @@ } } }, - "description": "Code authentication is required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nRe-authentication via password required (label: `missing-auth`)\n\nToo many clients (label: `too-many-clients`)" + "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)" } }, - "summary": "Register a new client" + "summary": "Get existing roles available for the given conversation" } }, - "/clients/{cid}/access-token": { - "post": { - "description": " [internal route ID: \"create-access-token\"]\n\nCreate an JWT DPoP access token for the client CSR, given a JWT DPoP proof, specified in the `DPoP` header. The access token will be returned in the JSON response body as a JWT DPoP token.", + "/cookies": { + "get": { + "description": " [internal route ID: \"list-cookies\"]\n\n", + "operationId": "list-cookies", "parameters": [ { - "description": "ClientId", - "in": "path", - "name": "cid", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "header", - "name": "DPoP", - "required": true, + "description": "Filter by label (comma-separated list)", + "in": "query", + "name": "labels", + "required": false, "schema": { "type": "string" } @@ -9992,112 +18165,30 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DPoPAccessTokenResponse" + "$ref": "#/components/schemas/CookieList_LTM4MzYwNzAz" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/DPoPAccessTokenResponse" + "$ref": "#/components/schemas/CookieList_LTM4MzYwNzAz" } } }, - "description": "Access token created", - "headers": { - "Cache-Control": { - "schema": { - "type": "string" - } - } - } + "description": "List of cookies" } }, - "summary": "Create a JWT DPoP access token" + "summary": "Retrieve the list of cookies currently stored for the user" } }, - "/clients/{client}": { - "delete": { - "description": " [internal route ID: \"delete-client\"]\n\n", - "parameters": [ - { - "description": "ClientId", - "in": "path", - "name": "client", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/DeleteClient" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Client deleted" - } - }, - "summary": "Delete an existing client" - }, - "get": { - "description": " [internal route ID: \"get-client-v6\"]\n\n", - "parameters": [ - { - "description": "ClientId", - "in": "path", - "name": "client", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Clientv6" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Clientv6" - } - } - }, - "description": "Client found" - }, - "404": { - "description": "`client` or Client not found(**Note**: This error has an empty body for legacy reasons)" - } - }, - "summary": "Get a registered client by ID" - }, - "put": { - "description": " [internal route ID: \"update-client\"]\n\n", - "parameters": [ - { - "description": "ClientId", - "in": "path", - "name": "client", - "required": true, - "schema": { - "type": "string" - } - } - ], + "/cookies/remove": { + "post": { + "description": " [internal route ID: \"remove-cookies\"]\n\n", + "operationId": "remove-cookies", "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/UpdateClient" + "$ref": "#/components/schemas/RemoveCookies_OTYwMTI0NDMy" } } }, @@ -10105,27 +18196,27 @@ }, "responses": { "200": { - "description": "Client updated" + "description": "Cookies revoked" }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "bad-request", - "message": "Malformed prekeys uploaded" + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "bad-request" + "invalid-credentials" ], "type": "string" }, @@ -10142,20 +18233,21 @@ } } }, - "description": "Invalid `body`\n\nMalformed prekeys uploaded (label: `bad-request`)" + "description": "Authentication failed (label: `invalid-credentials`)" } }, - "summary": "Update a registered client" + "summary": "Revoke stored cookies" } }, - "/clients/{client}/capabilities": { + "/custom-backend/by-domain/{domain}": { "get": { - "description": " [internal route ID: \"get-client-capabilities\"]\n\n", + "description": " [internal route ID: \"get-custom-backend-by-domain\"]\n\n", + "operationId": "get-custom-backend-by-domain", "parameters": [ { - "description": "ClientId", + "description": "URL-encoded email domain", "in": "path", - "name": "client", + "name": "domain", "required": true, "schema": { "type": "string" @@ -10167,233 +18259,196 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ClientCapabilityList" + "$ref": "#/components/schemas/CustomBackend_LTQxODI0MjQ0" } } }, "description": "" - } - }, - "summary": "Read back what the client has been posting about itself" - } - }, - "/clients/{client}/nonce": { - "get": { - "description": " [internal route ID: \"get-nonce\"]\n\nGet a new nonce for a client CSR, specified in the response header `Replay-Nonce` as a uuidv4 in base64url encoding.", - "parameters": [ - { - "description": "ClientId", - "in": "path", - "name": "client", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "No Content", - "headers": { - "Cache-Control": { - "schema": { - "type": "string" - } - }, - "Replay-Nonce": { - "schema": { - "type": "string" - } - } - } - } - }, - "summary": "Get a new nonce for a client CSR" - }, - "head": { - "description": " [internal route ID: \"head-nonce\"]\n\nGet a new nonce for a client CSR, specified in the response header `Replay-Nonce` as a uuidv4 in base64url encoding.", - "parameters": [ - { - "description": "ClientId", - "in": "path", - "name": "client", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "No Content", - "headers": { - "Cache-Control": { - "schema": { - "type": "string" - } - }, - "Replay-Nonce": { - "schema": { - "type": "string" - } - } - } - } - }, - "summary": "Get a new nonce for a client CSR" - } - }, - "/clients/{client}/prekeys": { - "get": { - "description": " [internal route ID: \"get-client-prekeys\"]\n\n", - "parameters": [ - { - "description": "ClientId", - "in": "path", - "name": "client", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { + }, + "404": { "content": { "application/json;charset=utf-8": { "schema": { - "items": { - "maximum": 65535, - "minimum": 0, - "type": "integer" + "example": { + "code": 404, + "label": "custom-backend-not-found", + "message": "Custom backend not found" }, - "type": "array" + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "custom-backend-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "" + "description": "`domain` not found\n\nCustom backend not found (label: `custom-backend-not-found`)" } - }, - "summary": "List the remaining prekey IDs of a client" - } - }, - "/connections/{uid_domain}/{uid}": { - "get": { - "description": " [internal route ID: \"get-connection\"]\n\n", - "parameters": [ - { - "in": "path", - "name": "uid_domain", - "required": true, - "schema": { - "type": "string" + }, + "summary": "Shows information about custom backends related to a given email domain" + } + }, + "/delete": { + "post": { + "description": " [internal route ID: \"verify-delete\"]\n\n", + "operationId": "verify-delete", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/VerifyDeleteUser_Njc1NDQ1MDIy" + } } }, - { - "description": "User Id", - "in": "path", - "name": "uid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], + "required": true + }, "responses": { "200": { + "description": "Deletion is initiated." + }, + "403": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserConnection" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/UserConnection" + "example": { + "code": 403, + "label": "invalid-code", + "message": "Invalid verification code" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "Connection found" - }, - "404": { - "description": "`uid_domain` or `uid` or Connection not found(**Note**: This error has an empty body for legacy reasons)" + "description": "Invalid verification code (label: `invalid-code`)" } }, - "summary": "Get an existing connection to another user (local or remote)" - }, + "summary": "Verify account deletion with a code." + } + }, + "/domain-verification/{domain}/authorize-team": { "post": { - "description": " [internal route ID: \"create-connection\"]\n\nYou can have no more than 1000 connections in accepted or sent state
Calls federation service brig on send-connection-action
Calls federation service brig on get-users-by-ids", + "description": " [internal route ID: \"domain-verification-authorize-team\"]\n\n", + "operationId": "domain-verification-authorize-team", "parameters": [ { "in": "path", - "name": "uid_domain", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "User Id", - "in": "path", - "name": "uid", + "name": "domain", "required": true, "schema": { - "format": "uuid", "type": "string" } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DomainOwnershipToken_NTU0ODc1NDE5" + } + } + }, + "required": true + }, "responses": { "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserConnection" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/UserConnection" - } - } - }, - "description": "Connection existed" + "description": "Authorized" }, - "201": { + "401": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserConnection" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/UserConnection" + "example": { + "code": 401, + "label": "domain-registration-update-auth-failure", + "message": "Domain registration updated auth failure" + }, + "properties": { + "code": { + "enum": [ + 401 + ], + "type": "integer" + }, + "label": { + "enum": [ + "domain-registration-update-auth-failure" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "Connection was created" + "description": "Domain registration updated auth failure (label: `domain-registration-update-auth-failure`)" }, - "400": { + "402": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "invalid-user", - "message": "Invalid user" + "code": 402, + "label": "domain-registration-update-payment-required", + "message": "Domain registration updated payment required" }, "properties": { "code": { "enum": [ - 400 + 402 ], "type": "integer" }, "label": { "enum": [ - "invalid-user" + "domain-registration-update-payment-required" ], "type": "string" }, @@ -10410,7 +18465,7 @@ } } }, - "description": "Invalid user (label: `invalid-user`)" + "description": "Domain registration updated payment required (label: `domain-registration-update-payment-required`)" }, "403": { "content": { @@ -10418,8 +18473,8 @@ "schema": { "example": { "code": 403, - "label": "no-identity", - "message": "The user has no verified email" + "label": "operation-forbidden-for-domain-registration-state", + "message": "Invalid domain registration state update" }, "properties": { "code": { @@ -10430,10 +18485,7 @@ }, "label": { "enum": [ - "no-identity", - "connection-limit", - "missing-legalhold-consent", - "missing-legalhold-consent-old-clients" + "operation-forbidden-for-domain-registration-state" ], "type": "string" }, @@ -10450,29 +18502,30 @@ } } }, - "description": "The user has no verified email (label: `no-identity`)\n\nToo many sent/accepted connections (label: `connection-limit`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)" + "description": "Invalid domain registration state update (label: `operation-forbidden-for-domain-registration-state`)" } }, - "summary": "Create a connection to another user" - }, - "put": { - "description": " [internal route ID: \"update-connection\"]\n\nCalls federation service brig on send-connection-action
Calls federation service brig on get-users-by-ids", + "summary": "Authorize a team to operate on a verified domain" + } + }, + "/domain-verification/{domain}/backend": { + "post": { + "description": " [internal route ID: \"update-domain-redirect\"]\n\n", + "operationId": "update-domain-redirect", "parameters": [ { - "in": "path", - "name": "uid_domain", + "in": "header", + "name": "Authorization", "required": true, "schema": { "type": "string" } }, { - "description": "User Id", "in": "path", - "name": "uid", + "name": "domain", "required": true, "schema": { - "format": "uuid", "type": "string" } } @@ -10481,7 +18534,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ConnectionUpdate" + "$ref": "#/components/schemas/DomainRedirectConfig_NTI5NDE5MDQy" } } }, @@ -10489,42 +18542,27 @@ }, "responses": { "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserConnection" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/UserConnection" - } - } - }, - "description": "Connection updated" + "description": "Updated" }, - "204": { - "description": "Connection unchanged" - }, - "400": { + "401": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "invalid-user", - "message": "Invalid user" + "code": 401, + "label": "domain-registration-update-auth-failure", + "message": "Domain registration updated auth failure" }, "properties": { "code": { "enum": [ - 400 + 401 ], "type": "integer" }, "label": { "enum": [ - "invalid-user" + "domain-registration-update-auth-failure" ], "type": "string" }, @@ -10541,7 +18579,7 @@ } } }, - "description": "Invalid `body`\n\nInvalid user (label: `invalid-user`)" + "description": "Domain registration updated auth failure (label: `domain-registration-update-auth-failure`)" }, "403": { "content": { @@ -10549,8 +18587,8 @@ "schema": { "example": { "code": 403, - "label": "no-identity", - "message": "The user has no verified email" + "label": "operation-forbidden-for-domain-registration-state", + "message": "Invalid domain registration state update" }, "properties": { "code": { @@ -10561,12 +18599,7 @@ }, "label": { "enum": [ - "no-identity", - "bad-conn-update", - "not-connected", - "connection-limit", - "missing-legalhold-consent", - "missing-legalhold-consent-old-clients" + "operation-forbidden-for-domain-registration-state" ], "type": "string" }, @@ -10583,94 +18616,104 @@ } } }, - "description": "The user has no verified email (label: `no-identity`)\n\nInvalid status transition (label: `bad-conn-update`)\n\nUsers are not connected (label: `not-connected`)\n\nToo many sent/accepted connections (label: `connection-limit`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)" + "description": "Invalid domain registration state update (label: `operation-forbidden-for-domain-registration-state`)" } }, - "summary": "Update a connection to another user" + "summary": "Update the domain redirect configuration" } }, - "/conversations": { + "/domain-verification/{domain}/challenges": { "post": { - "description": " [internal route ID: \"create-group-conversation\"]\n\nThis returns 201 when a new conversation is created, and 200 when the conversation already existed
Calls federation service galley on on-conversation-updated
Calls federation service galley on on-conversation-created
Calls federation service brig on get-not-fully-connected-backends
Calls federation service brig on api-version", - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/NewConv" - } + "description": " [internal route ID: \"domain-verification-challenge\"]\n\n", + "operationId": "domain-verification-challenge", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" } - }, - "required": true - }, + } + ], "responses": { "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ConversationV6v6" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ConversationV6v6" + "$ref": "#/components/schemas/DomainVerificationChallenge_NjIwMzA1MjE5" } } }, - "description": "Conversation existed", - "headers": { - "Location": { - "description": "Conversation ID", - "schema": { - "format": "uuid", - "type": "string" - } + "description": "" + } + }, + "summary": "Get a DNS verification challenge" + } + }, + "/domain-verification/{domain}/challenges/{challengeId}": { + "post": { + "description": " [internal route ID: \"verify-challenge\"]\n\n", + "operationId": "verify-challenge", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "challengeId", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ChallengeToken_Mzk3NTcwOTM3" } } }, - "201": { + "required": true + }, + "responses": { + "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateGroupConversationv6" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/CreateGroupConversationv6" + "$ref": "#/components/schemas/DomainOwnershipToken_NTU0ODc1NDE5" } } }, - "description": "Conversation created", - "headers": { - "Location": { - "description": "Conversation ID", - "schema": { - "format": "uuid", - "type": "string" - } - } - } + "description": "" }, - "400": { + "401": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "mls-not-enabled", - "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" + "code": 401, + "label": "domain-registration-update-auth-failure", + "message": "Domain registration updated auth failure" }, "properties": { "code": { "enum": [ - 400 + 401 ], "type": "integer" }, "label": { "enum": [ - "mls-not-enabled", - "non-empty-member-list" + "domain-registration-update-auth-failure" ], "type": "string" }, @@ -10687,7 +18730,7 @@ } } }, - "description": "Invalid `body`\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)\n\nAttempting to add group members outside MLS (label: `non-empty-member-list`)" + "description": "Domain registration updated auth failure (label: `domain-registration-update-auth-failure`)" }, "403": { "content": { @@ -10695,8 +18738,8 @@ "schema": { "example": { "code": 403, - "label": "missing-legalhold-consent", - "message": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent" + "label": "domain-verification-failed", + "message": "Domain verification failed" }, "properties": { "code": { @@ -10707,11 +18750,7 @@ }, "label": { "enum": [ - "missing-legalhold-consent", - "operation-denied", - "no-team-member", - "not-connected", - "access-denied" + "domain-verification-failed" ], "type": "string" }, @@ -10728,62 +18767,68 @@ } } }, - "description": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nInsufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nUsers are not connected (label: `not-connected`)\n\nConversation access denied (label: `access-denied`)" + "description": "Domain verification failed (label: `domain-verification-failed`)" }, - "409": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { - "properties": { - "non_federating_backends": { - "items": { - "$ref": "#/components/schemas/Domain" - }, - "type": "array" - } + "example": { + "code": 404, + "label": "challenge-not-found", + "message": "Challenge not found" }, - "required": [ - "non_federating_backends" - ], - "type": "object" - } - } - }, - "description": "Adding members to the conversation is not possible because the backends involved do not form a fully connected graph" - }, - "533": { - "content": { - "application/json;charset=utf-8": { - "schema": { "properties": { - "unreachable_backends": { - "items": { - "$ref": "#/components/schemas/Domain" - }, - "type": "array" + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "challenge-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" } }, "required": [ - "unreachable_backends" + "code", + "label", + "message" ], "type": "object" } } }, - "description": "Some domains are unreachable" + "description": "`domain` or `challengeId` not found\n\nChallenge not found (label: `challenge-not-found`)" } }, - "summary": "Create a new conversation" + "summary": "Verify a DNS verification challenge" } }, - "/conversations/code-check": { + "/domain-verification/{domain}/team": { "post": { - "description": " [internal route ID: \"code-check\"]\n\nIf the guest links team feature is disabled, this will fail with 404 CodeNotFound.Note that this is currently inconsistent (for backwards compatibility reasons) with `POST /conversations/join` which responds with 409 GuestLinksDisabled if guest links are disabled.", + "description": " [internal route ID: \"update-team-invite\"]\n\n", + "operationId": "update-team-invite", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ConversationCode" + "$ref": "#/components/schemas/TeamInviteConfig_MTg4Nzk4NzMz" } } }, @@ -10791,27 +18836,27 @@ }, "responses": { "200": { - "description": "Valid" + "description": "Updated" }, - "403": { + "402": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "invalid-conversation-password", - "message": "Invalid conversation password" + "code": 402, + "label": "domain-registration-update-payment-required", + "message": "Domain registration updated payment required" }, "properties": { "code": { "enum": [ - 403 + 402 ], "type": "integer" }, "label": { "enum": [ - "invalid-conversation-password" + "domain-registration-update-payment-required" ], "type": "string" }, @@ -10828,28 +18873,27 @@ } } }, - "description": "Invalid conversation password (label: `invalid-conversation-password`)" + "description": "Domain registration updated payment required (label: `domain-registration-update-payment-required`)" }, - "404": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "code": 403, + "label": "operation-forbidden-for-domain-registration-state", + "message": "Invalid domain registration state update" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "no-conversation", - "no-conversation-code" + "operation-forbidden-for-domain-registration-state" ], "type": "string" }, @@ -10866,52 +18910,138 @@ } } }, - "description": "Conversation not found (label: `no-conversation`)\n\nConversation code not found (label: `no-conversation-code`)" + "description": "Invalid domain registration state update (label: `operation-forbidden-for-domain-registration-state`)" } }, - "summary": "Check validity of a conversation code." + "summary": "Update the team-invite configuration" } }, - "/conversations/join": { - "get": { - "description": " [internal route ID: \"get-conversation-by-reusable-code\"]\n\n", + "/domain-verification/{domain}/team/challenges/{challengeId}": { + "post": { + "description": " [internal route ID: \"verify-challenge-team\"]\n\n", + "operationId": "verify-challenge-team", "parameters": [ { - "in": "query", - "name": "key", + "in": "path", + "name": "domain", "required": true, "schema": { "type": "string" } }, { - "in": "query", - "name": "code", + "in": "path", + "name": "challengeId", "required": true, "schema": { + "format": "uuid", "type": "string" } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ChallengeToken_Mzk3NTcwOTM3" + } + } + }, + "required": true + }, "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ConversationCoverView" + "$ref": "#/components/schemas/DomainOwnershipToken_NTU0ODc1NDE5" } } }, "description": "" }, + "401": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 401, + "label": "domain-registration-update-auth-failure", + "message": "Domain registration updated auth failure" + }, + "properties": { + "code": { + "enum": [ + 401 + ], + "type": "integer" + }, + "label": { + "enum": [ + "domain-registration-update-auth-failure" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Domain registration updated auth failure (label: `domain-registration-update-auth-failure`)" + }, + "402": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 402, + "label": "domain-registration-update-payment-required", + "message": "Domain registration updated payment required" + }, + "properties": { + "code": { + "enum": [ + 402 + ], + "type": "integer" + }, + "label": { + "enum": [ + "domain-registration-update-payment-required" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Domain registration updated payment required (label: `domain-registration-update-payment-required`)" + }, "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "label": "operation-forbidden-for-domain-registration-state", + "message": "Invalid domain registration state update" }, "properties": { "code": { @@ -10922,9 +19052,7 @@ }, "label": { "enum": [ - "no-team-member", - "access-denied", - "invalid-conversation-password" + "operation-forbidden-for-domain-registration-state" ], "type": "string" }, @@ -10941,28 +19069,86 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nConversation access denied (label: `access-denied`)\n\nInvalid conversation password (label: `invalid-conversation-password`)" + "description": "Invalid domain registration state update (label: `operation-forbidden-for-domain-registration-state`)" + } + }, + "summary": "Verify a DNS verification challenge for a team" + } + }, + "/events": { + "get": { + "description": " [internal route ID: \"consume-events\"]\n\nThis is the rabbitMQ-based variant of \"await-notifications\"", + "externalDocs": { + "description": "RFC 6455", + "url": "https://datatracker.ietf.org/doc/html/rfc6455" + }, + "operationId": "consume-events", + "parameters": [ + { + "description": "Client ID", + "in": "query", + "name": "client", + "required": false, + "schema": { + "type": "string" + } }, - "404": { + { + "description": "Synchronization marker ID", + "in": "query", + "name": "sync_marker", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "101": { + "description": "Connection upgraded." + }, + "426": { + "description": "Upgrade required." + } + }, + "summary": "Consume events over a websocket connection" + } + }, + "/feature-configs": { + "get": { + "description": " [internal route ID: \"get-all-feature-configs-for-user\"]\n\nGets feature configs for a user. If the user is a member of a team and has the required permissions, this will return the team's feature configs.If the user is not a member of a team, this will return the personal feature configs (the server defaults).\nOAuth scope: `read:feature_configs`", + "operationId": "get-all-feature-configs-for-user", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NP_LockableFtur_ghdCnfiSOVsyAvIRqExmDpB_MGwUT2Q_LTM1Mzc0ODgy" + } + } + }, + "description": "" + }, + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "code": 403, + "label": "operation-denied", + "message": "Insufficient permissions" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "no-conversation", - "no-conversation-code" + "operation-denied", + "no-team-member" ], "type": "string" }, @@ -10979,27 +19165,27 @@ } } }, - "description": "Conversation not found (label: `no-conversation`)\n\nConversation code not found (label: `no-conversation-code`)" + "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" }, - "409": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 409, - "label": "guest-links-disabled", - "message": "The guest link feature is disabled and all guest links have been revoked" + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 409 + 404 ], "type": "integer" }, "label": { "enum": [ - "guest-links-disabled" + "no-team" ], "type": "string" }, @@ -11016,18 +19202,21 @@ } } }, - "description": "The guest link feature is disabled and all guest links have been revoked (label: `guest-links-disabled`)" + "description": "Team not found (label: `no-team`)" } }, - "summary": "Get limited conversation information by key/code pair" - }, + "summary": "Gets feature configs for a user" + } + }, + "/get-domain-registration": { "post": { - "description": " [internal route ID: \"join-conversation-by-code-unqualified\"]\n\nIf the guest links team feature is disabled, this will fail with 409 GuestLinksDisabled.Note that this is currently inconsistent (for backwards compatibility reasons) with `POST /conversations/code-check` which responds with 404 CodeNotFound if guest links are disabled.Calls federation service galley on on-conversation-updated", + "description": " [internal route ID: \"get-domain-registration\"]\n\n- `due_to_existing_account`: boolean (optional, only present if `domain_redirect` is `no-registration`)\n- `backend`: object (optional, must be present if `domain_redirect` is `backend`)\n - `config_url`: string (required)\n - `webapp_url`: string (optional)\n- `sso_code`: string (optional, must be present if `domain_redirect` is `sso`)", + "operationId": "get-domain-registration", "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/JoinConversationByCode" + "$ref": "#/components/schemas/GetDomainRegistrationRequest_LTg4NTM1MzM2" } } }, @@ -11036,45 +19225,33 @@ "responses": { "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Event" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/DomainRedirectResponse_V10_LTEyMjI4NTM0" } } }, - "description": "Conversation joined" - }, - "204": { - "description": "Conversation unchanged" + "description": "" }, - "403": { + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "too-many-members", - "message": "Maximum number of members per conversation reached" + "code": 400, + "label": "invalid-domain", + "message": "Invalid domain" }, "properties": { "code": { "enum": [ - 403 + 400 ], "type": "integer" }, "label": { "enum": [ - "too-many-members", - "no-team-member", - "invalid-op", - "access-denied", - "invalid-conversation-password" + "invalid-domain" ], "type": "string" }, @@ -11091,28 +19268,107 @@ } } }, - "description": "Maximum number of members per conversation reached (label: `too-many-members`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInvalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)\n\nInvalid conversation password (label: `invalid-conversation-password`)" + "description": "Invalid `body`\n\nInvalid domain (label: `invalid-domain`)" + } + }, + "summary": "Get domain registration configuration by email" + } + }, + "/handles": { + "post": { + "description": " [internal route ID: \"check-user-handles\"]\n\n", + "operationId": "check-user-handles", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CheckHandles_LTc0OTkxMzAx" + } + } }, - "404": { + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/Handle" + }, + "type": "array" + } + }, + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/Handle" + }, + "type": "array" + } + } + }, + "description": "List of free handles" + } + }, + "summary": "Check availability of user handles" + } + }, + "/handles/{handle}": { + "head": { + "description": " [internal route ID: \"check-user-handle\"]\n\n", + "operationId": "check-user-handle", + "parameters": [ + { + "in": "path", + "name": "handle", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + } + }, + "description": "Handle is taken" + }, + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "code": 400, + "label": "invalid-handle", + "message": "The given handle is invalid (less than 2 or more than 256 characters; chars not in \"a-z0-9_.-\"; or on the blocklist)" }, "properties": { "code": { "enum": [ - 404 + 400 ], "type": "integer" }, "label": { "enum": [ - "no-conversation", - "no-conversation-code" + "invalid-handle" ], "type": "string" }, @@ -11129,27 +19385,27 @@ } } }, - "description": "Conversation not found (label: `no-conversation`)\n\nConversation code not found (label: `no-conversation-code`)" + "description": "The given handle is invalid (less than 2 or more than 256 characters; chars not in \"a-z0-9_.-\"; or on the blocklist) (label: `invalid-handle`)" }, - "409": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 409, - "label": "guest-links-disabled", - "message": "The guest link feature is disabled and all guest links have been revoked" + "code": 404, + "label": "not-found", + "message": "Handle not found" }, "properties": { "code": { "enum": [ - 409 + 404 ], "type": "integer" }, "label": { "enum": [ - "guest-links-disabled" + "not-found" ], "type": "string" }, @@ -11166,48 +19422,185 @@ } } }, - "description": "The guest link feature is disabled and all guest links have been revoked (label: `guest-links-disabled`)" + "description": "`handle` not found\n\nHandle not found (label: `not-found`)" } }, - "summary": "Join a conversation using a reusable code" + "summary": "Check whether a user handle can be taken" } }, - "/conversations/list": { + "/identity-providers": { + "get": { + "description": " [internal route ID: \"idp-get-all\"]\n\n", + "operationId": "idp-get-all", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/IdPList" + } + } + }, + "description": "" + } + } + }, "post": { - "description": " [internal route ID: \"list-conversations\"]\n\nCalls federation service galley on get-conversations", + "description": " [internal route ID: \"idp-create\"]\n\nCreate a new identity provider.\n\nThe `api_version` parameter controls the uniqueness constraint for IdP issuers:\n- `v1`: IdP issuers must be globally unique across the entire backend (all teams)\n- `v2` (default): IdP issuers must be unique per team (can be reused across different teams)\n\nThese constraints apply to both, multi-ingress and standard backends.", + "operationId": "idp-create", + "parameters": [ + { + "in": "query", + "name": "replaces", + "required": false, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "query", + "name": "api_version", + "required": false, + "schema": { + "default": "v2", + "enum": [ + "v1", + "v2" + ], + "type": "string" + } + }, + { + "in": "query", + "name": "handle", + "required": false, + "schema": { + "maxLength": 32, + "minLength": 1, + "type": "string" + } + } + ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ListConversations" + "$ref": "#/components/schemas/IdPMetadataInfo" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/IdPMetadataInfo" } } }, "required": true }, "responses": { - "200": { + "201": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ConversationsResponse" + "$ref": "#/components/schemas/IdPConfig_WireIdP_NDA5MTE4Mjk0" } } }, "description": "" } - }, - "summary": "Get conversation metadata for a list of conversation ids" + } } }, - "/conversations/list-ids": { - "post": { - "description": " [internal route ID: \"list-conversation-ids\"]\n\nThe IDs returned by this endpoint are paginated. To get the first page, make a call with the `paging_state` field set to `null` (or omitted). Whenever the `has_more` field of the response is set to `true`, more results are available, and they can be obtained by calling the endpoint again, but this time passing the value of `paging_state` returned by the previous call. One can continue in this fashion until all results are returned, which is indicated by `has_more` being `false`. Note that `paging_state` should be considered an opaque token. It should not be inspected, or stored, or reused across multiple unrelated invocations of the endpoint.", + "/identity-providers/{id}": { + "delete": { + "description": " [internal route ID: \"idp-delete\"]\n\n", + "operationId": "idp-delete", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "query", + "name": "purge", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "204": { + "description": "" + } + } + }, + "get": { + "description": " [internal route ID: \"idp-get\"]\n\n", + "operationId": "idp-get", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/IdPConfig_WireIdP_NDA5MTE4Mjk0" + } + } + }, + "description": "" + } + } + }, + "put": { + "description": " [internal route ID: \"idp-update\"]\n\n", + "operationId": "idp-update", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "query", + "name": "handle", + "required": false, + "schema": { + "maxLength": 32, + "minLength": 1, + "type": "string" + } + } + ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/GetPaginated_ConversationIds" + "$ref": "#/components/schemas/IdPMetadataInfo" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/IdPMetadataInfo" } } }, @@ -11218,84 +19611,93 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ConversationIds_Page" + "$ref": "#/components/schemas/IdPConfig_WireIdP_NDA5MTE4Mjk0" } } }, "description": "" } - }, - "summary": "Get all conversation IDs." + } } }, - "/conversations/mls-self": { + "/identity-providers/{id}/raw": { "get": { - "description": " [internal route ID: \"get-mls-self-conversation\"]\n\n", + "description": " [internal route ID: \"idp-get-raw\"]\n\n", + "operationId": "idp-get-raw", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], "responses": { "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Conversation" - } - }, - "application/json;charset=utf-8": { + "application/xml": { "schema": { - "$ref": "#/components/schemas/Conversation" + "type": "string" } } }, - "description": "The MLS self-conversation" + "description": "" + } + } + } + }, + "/list-connections": { + "post": { + "description": " [internal route ID: \"list-connections\"]\n\nThe IDs returned by this endpoint are paginated. To get the first page, make a call with the `paging_state` field set to `null` (or omitted). Whenever the `has_more` field of the response is set to `true`, more results are available, and they can be obtained by calling the endpoint again, but this time passing the value of `paging_state` returned by the previous call. One can continue in this fashion until all results are returned, which is indicated by `has_more` being `false`. Note that `paging_state` should be considered an opaque token. It should not be inspected, or stored, or reused across multiple unrelated invocations of the endpoint.", + "operationId": "list-connections", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/GetMuliTabPgRqs_ConcLOrm501_LTIwMjA4NzYw" + } + } }, - "400": { + "required": true + }, + "responses": { + "200": { "content": { "application/json;charset=utf-8": { "schema": { - "example": { - "code": 400, - "label": "mls-not-enabled", - "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" - }, - "properties": { - "code": { - "enum": [ - 400 - ], - "type": "integer" - }, - "label": { - "enum": [ - "mls-not-enabled" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" + "$ref": "#/components/schemas/MultiTabePg_ConcsLOrRmU_MTgwMzU4OTU5" } } }, - "description": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" + "description": "" } }, - "summary": "Get the user's MLS self-conversation" + "summary": "List the connections to other users, including remote users" } }, - "/conversations/one2one": { + "/list-users": { "post": { - "description": " [internal route ID: \"create-one-to-one-conversation\"]\n\nCalls federation service galley on on-conversation-created", + "description": " [internal route ID: \"list-users-by-ids-or-handles\"]\n\nThe 'qualified_ids' and 'qualified_handles' parameters are mutually exclusive.", + "operationId": "list-users-by-ids-or-handles", + "parameters": [ + { + "description": "Include whether each local user can currently be contacted", + "in": "query", + "name": "include-contact-status", + "required": false, + "schema": { + "type": "boolean" + } + } + ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/NewConv" + "$ref": "#/components/schemas/ListUsersQuery" } } }, @@ -11304,47 +19706,61 @@ "responses": { "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ConversationV3v3" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ConversationV3v3" + "$ref": "#/components/schemas/ListUsersById_LTQ5MTE3NDc0" } } }, - "description": "Conversation existed", - "headers": { - "Location": { - "description": "Conversation ID", - "schema": { - "format": "uuid", - "type": "string" - } + "description": "" + } + }, + "summary": "List users" + } + }, + "/login": { + "post": { + "description": " [internal route ID: \"login\"]\n\nLogins are throttled at the server's discretion", + "operationId": "login", + "parameters": [ + { + "description": "Request a persistent cookie instead of a session cookie", + "in": "query", + "name": "persist", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Login_LTgyNTIzMTM1" } } }, - "201": { + "required": true + }, + "responses": { + "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ConversationV3v3" + "$ref": "#/components/schemas/AccessToken_ODIyMTczMjMw" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ConversationV3v3" + "$ref": "#/components/schemas/AccessToken_ODIyMTczMjMw" } } }, - "description": "Conversation created", + "description": "OK", "headers": { - "Location": { - "description": "Conversation ID", + "Set-Cookie": { "schema": { - "format": "uuid", "type": "string" } } @@ -11356,8 +19772,8 @@ "schema": { "example": { "code": 403, - "label": "missing-legalhold-consent", - "message": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent" + "label": "code-authentication-required", + "message": "Code authentication is required" }, "properties": { "code": { @@ -11368,13 +19784,11 @@ }, "label": { "enum": [ - "missing-legalhold-consent", - "operation-denied", - "not-connected", - "no-team-member", - "non-binding-team-members", - "invalid-op", - "access-denied" + "code-authentication-required", + "code-authentication-failed", + "pending-activation", + "suspended", + "invalid-credentials" ], "type": "string" }, @@ -11391,28 +19805,61 @@ } } }, - "description": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nInsufficient permissions (label: `operation-denied`)\n\nUsers are not connected (label: `not-connected`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nBoth users must be members of the same binding team (label: `non-binding-team-members`)\n\nInvalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)" + "description": "Code authentication is required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nAccount pending activation (label: `pending-activation`)\n\nAccount suspended (label: `suspended`)\n\nAuthentication failed (label: `invalid-credentials`)" + } + }, + "summary": "Authenticate a user to obtain a cookie and first access token" + } + }, + "/meetings": { + "post": { + "description": " [internal route ID: \"create-meeting\"]\n\n\nOAuth scope: `write:meetings`", + "operationId": "create-meeting", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewMeeting_LTI1NTMzOTU5" + } + } }, - "404": { + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MeetingWithConversation_LTMyNzA4NzU0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MeetingWithConversation_LTMyNzA4NzU0" + } + } + }, + "description": "Meeting created" + }, + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-team", - "message": "Team not found" + "code": 403, + "label": "invalid-op", + "message": "Invalid meeting times, empty update, or meetings feature disabled" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "no-team", - "non-binding-team" + "invalid-op" ], "type": "string" }, @@ -11429,7 +19876,7 @@ } } }, - "description": "Team not found (label: `no-team`)\n\nNot a member of a binding team (label: `non-binding-team`)" + "description": "Invalid meeting times, empty update, or meetings feature disabled (label: `invalid-op`)" }, "533": { "content": { @@ -11453,16 +19900,39 @@ "description": "Some domains are unreachable" } }, - "summary": "Create a 1:1 conversation" + "summary": "Create a new meeting" } }, - "/conversations/one2one/{usr_domain}/{usr}": { + "/meetings/list": { "get": { - "description": " [internal route ID: \"get-one-to-one-mls-conversation@v6\"]\n\n", + "description": " [internal route ID: \"list-meetings\"]\n\n", + "operationId": "list-meetings", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/Meeting_ODU0OTMzMTgw" + }, + "type": "array" + } + } + }, + "description": "" + } + }, + "summary": "List all meetings for the authenticated user" + } + }, + "/meetings/{domain}/{id}": { + "delete": { + "description": " [internal route ID: \"delete-meeting\"]\n\n", + "operationId": "delete-meeting", "parameters": [ { "in": "path", - "name": "usr_domain", + "name": "domain", "required": true, "schema": { "type": "string" @@ -11470,49 +19940,38 @@ }, { "in": "path", - "name": "usr", + "name": "id", "required": true, "schema": { "format": "uuid", "type": "string" } } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MLSOne2OneConversation_MLSPublicKey" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/MLSOne2OneConversation_MLSPublicKey" - } - } - }, - "description": "MLS 1-1 conversation" + ], + "responses": { + "200": { + "description": "Meeting deleted" }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "mls-not-enabled", - "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" + "code": 403, + "label": "invalid-op", + "message": "Invalid meeting times, empty update, or meetings feature disabled" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "mls-not-enabled" + "invalid-op", + "access-denied" ], "type": "string" }, @@ -11529,27 +19988,27 @@ } } }, - "description": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" + "description": "Invalid meeting times, empty update, or meetings feature disabled (label: `invalid-op`)\n\nYou do not have permission to access this resource (label: `access-denied`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "not-connected", - "message": "Users are not connected" + "code": 404, + "label": "meeting-not-found", + "message": "Meeting not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "not-connected" + "meeting-not-found" ], "type": "string" }, @@ -11566,75 +20025,26 @@ } } }, - "description": "Users are not connected (label: `not-connected`)" + "description": "`domain` or `id` or Meeting not found (label: `meeting-not-found`)" } }, - "summary": "Get an MLS 1:1 conversation" - } - }, - "/conversations/self": { - "post": { - "description": " [internal route ID: \"create-self-conversation\"]\n\n", - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ConversationV6v6" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ConversationV6v6" - } - } - }, - "description": "Conversation existed", - "headers": { - "Location": { - "description": "Conversation ID", - "schema": { - "format": "uuid", - "type": "string" - } - } + "summary": "Delete a meeting" + }, + "get": { + "description": " [internal route ID: \"get-meeting\"]\n\n", + "operationId": "get-meeting", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" } }, - "201": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ConversationV6v6" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ConversationV6v6" - } - } - }, - "description": "Conversation created", - "headers": { - "Location": { - "description": "Conversation ID", - "schema": { - "format": "uuid", - "type": "string" - } - } - } - } - }, - "summary": "Create a self-conversation" - } - }, - "/conversations/{Conversation ID}/bots": { - "post": { - "description": " [internal route ID: \"add-bot\"]\n\n", - "parameters": [ { "in": "path", - "name": "Conversation ID", + "name": "id", "required": true, "schema": { "format": "uuid", @@ -11642,54 +20052,36 @@ } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/AddBot" - } - } - }, - "required": true - }, "responses": { - "201": { + "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddBotResponse" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/AddBotResponse" + "$ref": "#/components/schemas/Meeting_ODU0OTMzMTgw" } } }, "description": "" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "service-disabled", - "message": "The desired service is currently disabled." + "code": 404, + "label": "meeting-not-found", + "message": "Meeting not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "service-disabled", - "too-many-members", - "invalid-conversation", - "access-denied" + "meeting-not-found" ], "type": "string" }, @@ -11706,28 +20098,26 @@ } } }, - "description": "The desired service is currently disabled. (label: `service-disabled`)\n\nMaximum number of members per conversation reached. (label: `too-many-members`)\n\nThe operation is not allowed in this conversation. (label: `invalid-conversation`)\n\nAccess denied. (label: `access-denied`)" + "description": "`domain` or `id` or Meeting not found (label: `meeting-not-found`)" } }, - "summary": "Add bot" - } - }, - "/conversations/{Conversation ID}/bots/{Bot ID}": { - "delete": { - "description": " [internal route ID: \"remove-bot\"]\n\n", + "summary": "Get a single meeting by ID" + }, + "put": { + "description": " [internal route ID: \"update-meeting\"]\n\n", + "operationId": "update-meeting", "parameters": [ { "in": "path", - "name": "Conversation ID", + "name": "domain", "required": true, "schema": { - "format": "uuid", "type": "string" } }, { "in": "path", - "name": "Bot ID", + "name": "id", "required": true, "schema": { "format": "uuid", @@ -11735,24 +20125,31 @@ } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UpdateMeeting_NTExNzYxMTcz" + } + } + }, + "required": true + }, "responses": { "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/RemoveBotResponse" + "$ref": "#/components/schemas/MeetingWithConversation_LTMyNzA4NzU0" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/RemoveBotResponse" + "$ref": "#/components/schemas/MeetingWithConversation_LTMyNzA4NzU0" } } }, - "description": "User found" - }, - "204": { - "description": "" + "description": "Meeting updated" }, "403": { "content": { @@ -11760,8 +20157,8 @@ "schema": { "example": { "code": 403, - "label": "invalid-conversation", - "message": "The operation is not allowed in this conversation." + "label": "invalid-op", + "message": "Invalid meeting times, empty update, or meetings feature disabled" }, "properties": { "code": { @@ -11772,7 +20169,7 @@ }, "label": { "enum": [ - "invalid-conversation", + "invalid-op", "access-denied" ], "type": "string" @@ -11790,19 +20187,57 @@ } } }, - "description": "The operation is not allowed in this conversation. (label: `invalid-conversation`)\n\nAccess denied. (label: `access-denied`)" + "description": "Invalid meeting times, empty update, or meetings feature disabled (label: `invalid-op`)\n\nYou do not have permission to access this resource (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "meeting-not-found", + "message": "Meeting not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "meeting-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`domain` or `id` or Meeting not found (label: `meeting-not-found`)" } }, - "summary": "Remove bot" + "summary": "Update an existing meeting" } }, - "/conversations/{cnv_domain}/{cnv}": { - "get": { - "description": " [internal route ID: \"get-conversation\"]\n\nCalls federation service galley on get-conversations", + "/meetings/{domain}/{id}/invitations": { + "post": { + "description": " [internal route ID: \"add-meeting-invitation\"]\n\n", + "operationId": "add-meeting-invitation", "parameters": [ { "in": "path", - "name": "cnv_domain", + "name": "domain", "required": true, "schema": { "type": "string" @@ -11810,7 +20245,7 @@ }, { "in": "path", - "name": "cnv", + "name": "id", "required": true, "schema": { "format": "uuid", @@ -11818,16 +20253,19 @@ } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MeetingEmailsInvitation_NzgyNzUzMzcz" + } + } + }, + "required": true + }, "responses": { "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Conversation" - } - } - }, - "description": "" + "description": "Invitation added" }, "403": { "content": { @@ -11835,8 +20273,8 @@ "schema": { "example": { "code": 403, - "label": "access-denied", - "message": "Conversation access denied" + "label": "invalid-op", + "message": "Invalid meeting times, empty update, or meetings feature disabled" }, "properties": { "code": { @@ -11847,6 +20285,7 @@ }, "label": { "enum": [ + "invalid-op", "access-denied" ], "type": "string" @@ -11864,7 +20303,7 @@ } } }, - "description": "Conversation access denied (label: `access-denied`)" + "description": "Invalid meeting times, empty update, or meetings feature disabled (label: `invalid-op`)\n\nYou do not have permission to access this resource (label: `access-denied`)" }, "404": { "content": { @@ -11872,8 +20311,8 @@ "schema": { "example": { "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "label": "meeting-not-found", + "message": "Meeting not found" }, "properties": { "code": { @@ -11884,7 +20323,7 @@ }, "label": { "enum": [ - "no-conversation" + "meeting-not-found" ], "type": "string" }, @@ -11901,28 +20340,26 @@ } } }, - "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + "description": "`domain` or `id` or Meeting not found (label: `meeting-not-found`)" } }, - "summary": "Get a conversation by ID" - } - }, - "/conversations/{cnv_domain}/{cnv}/access": { + "summary": "Add an email to the invited emails" + }, "put": { - "description": " [internal route ID: \"update-conversation-access\"]\n\nCalls federation service brig on get-users-by-ids
Calls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated", + "description": " [internal route ID: \"replace-meeting-invitation\"]\n\n", + "operationId": "replace-meeting-invitation", "parameters": [ { "in": "path", - "name": "cnv_domain", + "name": "domain", "required": true, "schema": { "type": "string" } }, { - "description": "Conversation ID", "in": "path", - "name": "cnv", + "name": "id", "required": true, "schema": { "format": "uuid", @@ -11934,7 +20371,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ConversationAccessData" + "$ref": "#/components/schemas/MeetingEmailsInvitation_NzgyNzUzMzcz" } } }, @@ -11942,22 +20379,7 @@ }, "responses": { "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Event" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Event" - } - } - }, - "description": "Access updated" - }, - "204": { - "description": "Access unchanged" + "description": "Invitations replaced" }, "403": { "content": { @@ -11966,7 +20388,7 @@ "example": { "code": 403, "label": "invalid-op", - "message": "Invalid target access" + "message": "Invalid meeting times, empty update, or meetings feature disabled" }, "properties": { "code": { @@ -11978,8 +20400,7 @@ "label": { "enum": [ "invalid-op", - "access-denied", - "action-denied" + "access-denied" ], "type": "string" }, @@ -11996,7 +20417,7 @@ } } }, - "description": "Invalid target access (label: `invalid-op`)\n\nInvalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)\n\nInsufficient authorization (missing modify_conversation_access) (label: `action-denied`)" + "description": "Invalid meeting times, empty update, or meetings feature disabled (label: `invalid-op`)\n\nYou do not have permission to access this resource (label: `access-denied`)" }, "404": { "content": { @@ -12004,8 +20425,8 @@ "schema": { "example": { "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "label": "meeting-not-found", + "message": "Meeting not found" }, "properties": { "code": { @@ -12016,7 +20437,7 @@ }, "label": { "enum": [ - "no-conversation" + "meeting-not-found" ], "type": "string" }, @@ -12033,19 +20454,20 @@ } } }, - "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + "description": "`domain` or `id` or Meeting not found (label: `meeting-not-found`)" } }, - "summary": "Update access modes for a conversation" + "summary": "Replace the invited emails" } }, - "/conversations/{cnv_domain}/{cnv}/groupinfo": { - "get": { - "description": " [internal route ID: \"get-group-info\"]\n\nCalls federation service galley on query-group-info", + "/meetings/{domain}/{id}/invitations/delete": { + "post": { + "description": " [internal route ID: \"remove-meeting-invitation\"]\n\n", + "operationId": "remove-meeting-invitation", "parameters": [ { "in": "path", - "name": "cnv_domain", + "name": "domain", "required": true, "schema": { "type": "string" @@ -12053,7 +20475,7 @@ }, { "in": "path", - "name": "cnv", + "name": "id", "required": true, "schema": { "format": "uuid", @@ -12061,36 +20483,40 @@ } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MeetingEmailsInvitation_NzgyNzUzMzcz" + } + } + }, + "required": true + }, "responses": { "200": { - "content": { - "message/mls": { - "schema": { - "$ref": "#/components/schemas/GroupInfoData" - } - } - }, - "description": "The group information" + "description": "Invitations removed" }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "mls-not-enabled", - "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" + "code": 403, + "label": "invalid-op", + "message": "Invalid meeting times, empty update, or meetings feature disabled" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "mls-not-enabled" + "invalid-op", + "access-denied" ], "type": "string" }, @@ -12107,7 +20533,7 @@ } } }, - "description": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" + "description": "Invalid meeting times, empty update, or meetings feature disabled (label: `invalid-op`)\n\nYou do not have permission to access this resource (label: `access-denied`)" }, "404": { "content": { @@ -12115,8 +20541,8 @@ "schema": { "example": { "code": 404, - "label": "mls-missing-group-info", - "message": "The conversation has no group information" + "label": "meeting-not-found", + "message": "Meeting not found" }, "properties": { "code": { @@ -12127,8 +20553,7 @@ }, "label": { "enum": [ - "mls-missing-group-info", - "no-conversation" + "meeting-not-found" ], "type": "string" }, @@ -12145,62 +20570,87 @@ } } }, - "description": "`cnv_domain` or `cnv` not found\n\nThe conversation has no group information (label: `mls-missing-group-info`)\n\nConversation not found (label: `no-conversation`)" + "description": "`domain` or `id` or Meeting not found (label: `meeting-not-found`)" } }, - "summary": "Get MLS group information" + "summary": "Remove emails from the invited emails" } }, - "/conversations/{cnv_domain}/{cnv}/members": { + "/mls/commit-bundles": { "post": { - "description": " [internal route ID: \"add-members-to-conversation\"]\n\nCalls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated", - "parameters": [ - { - "in": "path", - "name": "cnv_domain", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "path", - "name": "cnv", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], + "description": " [internal route ID: \"mls-commit-bundle\"]\n\n\n\n**Note**: this endpoint can execute proposals, and therefore return all possible errors associated with adding or removing members to a conversation, in addition to the ones listed below. See the documentation of [POST /conversations/{cnv}/members/v2](#/default/post_conversations__cnv__members_v2) and [POST /conversations/{cnv_domain}/{cnv}/members/{usr_domain}/{usr}](#/default/delete_conversations__cnv_domain___cnv__members__usr_domain___usr_) for more details on the possible error responses of each type of proposal.", + "operationId": "mls-commit-bundle", "requestBody": { "content": { - "application/json;charset=utf-8": { + "message/mls": { "schema": { - "$ref": "#/components/schemas/InviteQualified" + "$ref": "#/components/schemas/CommitBundle" } } }, "required": true }, "responses": { - "200": { + "201": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/MLSMessageSendingStatus_NjA1NDA0MTE4" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/MLSMessageSendingStatus_NjA1NDA0MTE4" } } }, - "description": "Conversation updated" + "description": "Commit accepted and forwarded" }, - "204": { - "description": "Conversation unchanged" + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-invalid-leaf-node-signature", + "message": "Invalid leaf node signature" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-invalid-leaf-node-signature", + "mls-group-id-not-supported", + "mls-welcome-mismatch", + "mls-self-removal-not-allowed", + "mls-protocol-error", + "mls-not-enabled", + "mls-invalid-leaf-node-index", + "mls-group-conversation-mismatch", + "mls-commit-missing-references", + "mls-client-sender-user-mismatch" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid leaf node signature (label: `mls-invalid-leaf-node-signature`)\n\nThe group ID version of the conversation is not supported by one of the federated backends (label: `mls-group-id-not-supported`)\n\nSubmitted group info is inconsistent with the backend group state (label `inconsistent-group-state`)\n\nThe list of targets of a welcome message does not match the list of new clients in a group (label: `mls-welcome-mismatch`)\n\nSelf removal from group is not allowed (label: `mls-self-removal-not-allowed`)\n\nMLS protocol error (label: `mls-protocol-error`)\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)\n\nA referenced leaf node index points to a blank or non-existing node (label: `mls-invalid-leaf-node-index`)\n\nConversation ID resolved from Group ID does not match submitted Conversation ID (label: `mls-group-conversation-mismatch`)\n\nThe commit is not referencing all pending proposals (label: `mls-commit-missing-references`)\n\nUser ID resolved from Client ID does not match message's sender user ID (label: `mls-client-sender-user-mismatch`)" }, "403": { "content": { @@ -12208,8 +20658,8 @@ "schema": { "example": { "code": 403, - "label": "missing-legalhold-consent", - "message": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent" + "label": "mls-identity-mismatch", + "message": "Leaf node signature key does not match the client's key" }, "properties": { "code": { @@ -12220,13 +20670,11 @@ }, "label": { "enum": [ + "mls-identity-mismatch", + "mls-subconv-join-parent-missing", "missing-legalhold-consent", - "not-connected", - "no-team-member", - "access-denied", - "too-many-members", - "invalid-op", - "action-denied" + "legalhold-not-enabled", + "access-denied" ], "type": "string" }, @@ -12243,7 +20691,7 @@ } } }, - "description": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nUsers are not connected (label: `not-connected`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nConversation access denied (label: `access-denied`)\n\nMaximum number of members per conversation reached (label: `too-many-members`)\n\nInvalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing leave_conversation) (label: `action-denied`)\n\nInsufficient authorization (missing add_conversation_member) (label: `action-denied`)" + "description": "Leaf node signature key does not match the client's key (label: `mls-identity-mismatch`)\n\nMLS client cannot join the subconversation because it is not member of the parent conversation (label: `mls-subconv-join-parent-missing`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nlegal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nConversation access denied (label: `access-denied`)" }, "404": { "content": { @@ -12251,8 +20699,8 @@ "schema": { "example": { "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "label": "mls-proposal-not-found", + "message": "A proposal referenced in a commit message could not be found" }, "properties": { "code": { @@ -12263,7 +20711,9 @@ }, "label": { "enum": [ - "no-conversation" + "mls-proposal-not-found", + "no-conversation", + "no-conversation-member" ], "type": "string" }, @@ -12280,28 +20730,66 @@ } } }, - "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + "description": "A proposal referenced in a commit message could not be found (label: `mls-proposal-not-found`)\n\nConversation not found (label: `no-conversation`)\n\nConversation member not found (label: `no-conversation-member`)" }, "409": { "content": { "application/json;charset=utf-8": { "schema": { "properties": { - "non_federating_backends": { + "missing_users": { "items": { - "$ref": "#/components/schemas/Domain" + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" }, "type": "array" } }, "required": [ - "non_federating_backends" + "missing_users" ], "type": "object" } } }, - "description": "Adding members to the conversation is not possible because the backends involved do not form a fully connected graph" + "description": "Group is out of sync\n\nAdding members to the conversation is not possible because the backends involved do not form a fully connected graph\n\nA user who is under legal-hold may not participate in MLS conversations (label: `mls-legal-hold-not-allowed`)\n\nThe conversation epoch in a message is too old (label: `mls-stale-message`)\n\nA proposal of type Add or Remove does not apply to the full list of clients for a user (label: `mls-client-mismatch`)" + }, + "422": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 422, + "label": "mls-unsupported-proposal", + "message": "Unsupported proposal type" + }, + "properties": { + "code": { + "enum": [ + 422 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-unsupported-proposal", + "mls-unsupported-message" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unsupported proposal type (label: `mls-unsupported-proposal`)\n\nAttempted to send a message with an unsupported combination of content type and wire format (label: `mls-unsupported-message`)" }, "533": { "content": { @@ -12325,25 +20813,26 @@ "description": "Some domains are unreachable" } }, - "summary": "Add qualified members to an existing conversation." + "summary": "Post a MLS CommitBundle" } }, - "/conversations/{cnv_domain}/{cnv}/members/{usr_domain}/{usr}": { - "delete": { - "description": " [internal route ID: \"remove-member\"]\n\nCalls federation service brig on get-users-by-ids
Calls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated
Calls federation service galley on leave-conversation", + "/mls/key-packages/claim/{user_domain}/{user}": { + "post": { + "description": " [internal route ID: \"mls-key-packages-claim\"]\n\nOnly key packages for the specified ciphersuite are claimed.", + "operationId": "mls-key-packages-claim", "parameters": [ { "in": "path", - "name": "cnv_domain", + "name": "user_domain", "required": true, "schema": { "type": "string" } }, { - "description": "Conversation ID", + "description": "User Id", "in": "path", - "name": "cnv", + "name": "user", "required": true, "schema": { "format": "uuid", @@ -12351,21 +20840,12 @@ } }, { - "in": "path", - "name": "usr_domain", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "Target User ID", - "in": "path", - "name": "usr", + "description": "Ciphersuite in hex format (e.g. 0x0002)", + "in": "query", + "name": "ciphersuite", "required": true, "schema": { - "format": "uuid", - "type": "string" + "type": "number" } } ], @@ -12374,40 +20854,109 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/KeyPackageBundle_MjU2MjY0MDU2" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/KeyPackageBundle_MjU2MjY0MDU2" } } - }, - "description": "Member removed" + }, + "description": "Claimed key packages" + } + }, + "summary": "Claim one key package for each client of the given user" + } + }, + "/mls/key-packages/self/{client}": { + "delete": { + "description": " [internal route ID: \"mls-key-packages-delete\"]\n\n", + "operationId": "mls-key-packages-delete", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Ciphersuite in hex format (e.g. 0x0002)", + "in": "query", + "name": "ciphersuite", + "required": true, + "schema": { + "type": "number" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DeleteKeyPackages_LTQxNTcxNjY3" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "OK" + } + }, + "summary": "Delete all key packages for a given ciphersuite and client" + }, + "post": { + "description": " [internal route ID: \"mls-key-packages-upload\"]\n\nThe request body should be a json object containing a list of base64-encoded key packages.", + "operationId": "mls-key-packages-upload", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/KeyPackageUpload_NTQ2Mjk2NzEx" + } + } }, - "204": { - "description": "No change" + "required": true + }, + "responses": { + "201": { + "description": "Key packages uploaded" }, - "403": { + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "invalid-op", - "message": "Invalid operation" + "code": 400, + "label": "mls-protocol-error", + "message": "MLS protocol error" }, "properties": { "code": { "enum": [ - 403 + 400 ], "type": "integer" }, "label": { "enum": [ - "invalid-op", - "action-denied" + "mls-protocol-error" ], "type": "string" }, @@ -12424,27 +20973,27 @@ } } }, - "description": "Invalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)" + "description": "Invalid `body`\n\nMLS protocol error (label: `mls-protocol-error`)" }, - "404": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "code": 403, + "label": "mls-identity-mismatch", + "message": "Key package credential does not match qualified client ID" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "no-conversation" + "mls-identity-mismatch" ], "type": "string" }, @@ -12461,47 +21010,30 @@ } } }, - "description": "`cnv_domain` or `cnv` or `usr_domain` or `usr` not found\n\nConversation not found (label: `no-conversation`)" + "description": "Key package credential does not match qualified client ID (label: `mls-identity-mismatch`)" } }, - "summary": "Remove a member from a conversation" + "summary": "Upload a fresh batch of key packages" }, "put": { - "description": " [internal route ID: \"update-other-member\"]\n\n**Note**: at least one field has to be provided.Calls federation service brig on get-users-by-ids
Calls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated", + "description": " [internal route ID: \"mls-key-packages-replace\"]\n\nThe request body should be a json object containing a list of base64-encoded key packages. Use this sparingly.", + "operationId": "mls-key-packages-replace", "parameters": [ { + "description": "ClientId", "in": "path", - "name": "cnv_domain", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "Conversation ID", - "in": "path", - "name": "cnv", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - }, - { - "in": "path", - "name": "usr_domain", + "name": "client", "required": true, "schema": { "type": "string" } }, { - "description": "Target User ID", - "in": "path", - "name": "usr", + "description": "Comma-separated list of ciphersuites in hex format (e.g. 0x0002)", + "in": "query", + "name": "ciphersuites", "required": true, "schema": { - "format": "uuid", "type": "string" } } @@ -12510,36 +21042,35 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/OtherMemberUpdate" + "$ref": "#/components/schemas/KeyPackageUpload_NTQ2Mjk2NzEx" } } }, "required": true }, "responses": { - "200": { - "description": "Membership updated" + "201": { + "description": "Key packages replaced" }, - "403": { + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "invalid-op", - "message": "Invalid operation" + "code": 400, + "label": "mls-protocol-error", + "message": "MLS protocol error" }, "properties": { "code": { "enum": [ - 403 + 400 ], "type": "integer" }, "label": { "enum": [ - "invalid-op", - "action-denied" + "mls-protocol-error" ], "type": "string" }, @@ -12556,28 +21087,27 @@ } } }, - "description": "Invalid operation (label: `invalid-op`)\n\nInvalid target (label: `invalid-op`)\n\nInsufficient authorization (missing modify_other_conversation_member) (label: `action-denied`)" + "description": "Invalid `body` or `ciphersuites`\n\nMLS protocol error (label: `mls-protocol-error`)" }, - "404": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-conversation-member", - "message": "Conversation member not found" + "code": 403, + "label": "mls-identity-mismatch", + "message": "Key package credential does not match qualified client ID" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "no-conversation-member", - "no-conversation" + "mls-identity-mismatch" ], "type": "string" }, @@ -12594,63 +21124,129 @@ } } }, - "description": "`cnv_domain` or `cnv` or `usr_domain` or `usr` not found\n\nConversation member not found (label: `no-conversation-member`)\n\nConversation not found (label: `no-conversation`)" + "description": "Key package credential does not match qualified client ID (label: `mls-identity-mismatch`)" } }, - "summary": "Update membership of the specified user" + "summary": "Upload a fresh batch of key packages and replace the old ones" } }, - "/conversations/{cnv_domain}/{cnv}/message-timer": { - "put": { - "description": " [internal route ID: \"update-conversation-message-timer\"]\n\nCalls federation service brig on get-users-by-ids
Calls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated", + "/mls/key-packages/self/{client}/count": { + "get": { + "description": " [internal route ID: \"mls-key-packages-count\"]\n\n", + "operationId": "mls-key-packages-count", "parameters": [ { + "description": "ClientId", "in": "path", - "name": "cnv_domain", + "name": "client", "required": true, "schema": { "type": "string" } }, { - "description": "Conversation ID", - "in": "path", - "name": "cnv", + "description": "Ciphersuite in hex format (e.g. 0x0002)", + "in": "query", + "name": "ciphersuite", "required": true, "schema": { - "format": "uuid", - "type": "string" + "type": "number" } } ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyPackageCount_LTYwNDg5MDcz" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/KeyPackageCount_LTYwNDg5MDcz" + } + } + }, + "description": "Number of key packages" + } + }, + "summary": "Return the number of unclaimed key packages for a given ciphersuite and client" + } + }, + "/mls/messages": { + "post": { + "description": " [internal route ID: \"mls-message\"]\n\n\n\n**Note**: this endpoint can execute proposals, and therefore return all possible errors associated with adding or removing members to a conversation, in addition to the ones listed below. See the documentation of [POST /conversations/{cnv}/members/v2](#/default/post_conversations__cnv__members_v2) and [POST /conversations/{cnv_domain}/{cnv}/members/{usr_domain}/{usr}](#/default/delete_conversations__cnv_domain___cnv__members__usr_domain___usr_) for more details on the possible error responses of each type of proposal.", + "operationId": "mls-message", "requestBody": { "content": { - "application/json;charset=utf-8": { + "message/mls": { "schema": { - "$ref": "#/components/schemas/ConversationMessageTimerUpdate" + "$ref": "#/components/schemas/MLSMessage" } } }, "required": true }, "responses": { - "200": { + "201": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/MLSMessageSendingStatus_NjA1NDA0MTE4" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/MLSMessageSendingStatus_NjA1NDA0MTE4" } } }, - "description": "Message timer updated" + "description": "Message sent" }, - "204": { - "description": "Message timer unchanged" + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-invalid-leaf-node-signature", + "message": "Invalid leaf node signature" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-invalid-leaf-node-signature", + "mls-self-removal-not-allowed", + "mls-protocol-error", + "mls-not-enabled", + "mls-invalid-leaf-node-index", + "mls-group-conversation-mismatch", + "mls-commit-missing-references", + "mls-client-sender-user-mismatch" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid leaf node signature (label: `mls-invalid-leaf-node-signature`)\n\nSubmitted group info is inconsistent with the backend group state (label `inconsistent-group-state`)\n\nSelf removal from group is not allowed (label: `mls-self-removal-not-allowed`)\n\nMLS protocol error (label: `mls-protocol-error`)\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)\n\nA referenced leaf node index points to a blank or non-existing node (label: `mls-invalid-leaf-node-index`)\n\nConversation ID resolved from Group ID does not match submitted Conversation ID (label: `mls-group-conversation-mismatch`)\n\nThe commit is not referencing all pending proposals (label: `mls-commit-missing-references`)\n\nUser ID resolved from Client ID does not match message's sender user ID (label: `mls-client-sender-user-mismatch`)" }, "403": { "content": { @@ -12658,8 +21254,8 @@ "schema": { "example": { "code": 403, - "label": "invalid-op", - "message": "Invalid operation" + "label": "mls-subconv-join-parent-missing", + "message": "MLS client cannot join the subconversation because it is not member of the parent conversation" }, "properties": { "code": { @@ -12670,9 +21266,10 @@ }, "label": { "enum": [ - "invalid-op", - "access-denied", - "action-denied" + "mls-subconv-join-parent-missing", + "missing-legalhold-consent", + "legalhold-not-enabled", + "access-denied" ], "type": "string" }, @@ -12689,7 +21286,7 @@ } } }, - "description": "Invalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)\n\nInsufficient authorization (missing modify_conversation_message_timer) (label: `action-denied`)" + "description": "MLS client cannot join the subconversation because it is not member of the parent conversation (label: `mls-subconv-join-parent-missing`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nlegal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nConversation access denied (label: `access-denied`)" }, "404": { "content": { @@ -12697,8 +21294,8 @@ "schema": { "example": { "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "label": "mls-proposal-not-found", + "message": "A proposal referenced in a commit message could not be found" }, "properties": { "code": { @@ -12709,7 +21306,9 @@ }, "label": { "enum": [ - "no-conversation" + "mls-proposal-not-found", + "no-conversation", + "no-conversation-member" ], "type": "string" }, @@ -12726,84 +21325,49 @@ } } }, - "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" - } - }, - "summary": "Update the message timer for a conversation" - } - }, - "/conversations/{cnv_domain}/{cnv}/name": { - "put": { - "description": " [internal route ID: \"update-conversation-name\"]\n\nCalls federation service brig on get-users-by-ids
Calls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated", - "parameters": [ - { - "in": "path", - "name": "cnv_domain", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "Conversation ID", - "in": "path", - "name": "cnv", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ConversationRename" - } - } + "description": "A proposal referenced in a commit message could not be found (label: `mls-proposal-not-found`)\n\nConversation not found (label: `no-conversation`)\n\nConversation member not found (label: `no-conversation-member`)" }, - "required": true - }, - "responses": { - "200": { + "409": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Event" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Event" + "properties": { + "missing_users": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "type": "array" + } + }, + "required": [ + "missing_users" + ], + "type": "object" } } }, - "description": "Name unchanged" - }, - "204": { - "description": "Name updated" + "description": "Group is out of sync\n\nAdding members to the conversation is not possible because the backends involved do not form a fully connected graph\n\nThe conversation epoch in a message is too old (label: `mls-stale-message`)\n\nA proposal of type Add or Remove does not apply to the full list of clients for a user (label: `mls-client-mismatch`)" }, - "403": { + "422": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "invalid-op", - "message": "Invalid operation" + "code": 422, + "label": "mls-unsupported-proposal", + "message": "Unsupported proposal type" }, "properties": { "code": { "enum": [ - 403 + 422 ], "type": "integer" }, "label": { "enum": [ - "invalid-op", - "action-denied" + "mls-unsupported-proposal", + "mls-unsupported-message" ], "type": "string" }, @@ -12820,27 +21384,86 @@ } } }, - "description": "Invalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing modify_conversation_name) (label: `action-denied`)" + "description": "Unsupported proposal type (label: `mls-unsupported-proposal`)\n\nAttempted to send a message with an unsupported combination of content type and wire format (label: `mls-unsupported-message`)" }, - "404": { + "533": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "unreachable_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "unreachable_backends" + ], + "type": "object" + } + } + }, + "description": "Some domains are unreachable" + } + }, + "summary": "Post an MLS message" + } + }, + "/mls/public-keys": { + "get": { + "description": " [internal route ID: \"mls-public-keys\"]\n\nThe format of the returned key is determined by the `format` query parameter:\n - raw (default): base64-encoded raw public keys\n - jwk: keys are nested objects in JWK format.", + "operationId": "mls-public-keys", + "parameters": [ + { + "in": "query", + "name": "format", + "required": false, + "schema": { + "enum": [ + "raw", + "jwk" + ], + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MLSKeysByPurpose_MLSKeys_SomeKey_NjkxMjk0MTAx" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MLSKeysByPurpose_MLSKeys_SomeKey_NjkxMjk0MTAx" + } + } + }, + "description": "Public keys" + }, + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "code": 400, + "label": "mls-not-enabled", + "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" }, "properties": { "code": { "enum": [ - 404 + 400 ], "type": "integer" }, "label": { "enum": [ - "no-conversation" + "mls-not-enabled" ], "type": "string" }, @@ -12857,68 +21480,78 @@ } } }, - "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + "description": "Invalid `format`\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" } }, - "summary": "Update conversation name" + "summary": "Get public keys used by the backend to sign external proposals" } }, - "/conversations/{cnv_domain}/{cnv}/proteus/messages": { + "/mls/reset-conversation": { "post": { - "description": " [internal route ID: \"post-proteus-message\"]\n\nThis endpoint ensures that the list of clients is correct and only sends the message if the list is correct.\nTo override this, the endpoint accepts `client_mismatch_strategy` in the body. It can have these values:\n- `report_all`: When set, the message is not sent if any clients are missing. The missing clients are reported in the response.\n- `ignore_all`: When set, no checks about missing clients are carried out.\n- `report_only`: Takes a list of qualified UserIDs. If any clients of the listed users are missing, the message is not sent. The missing clients are reported in the response.\n- `ignore_only`: Takes a list of qualified UserIDs. If any clients of the non-listed users are missing, the message is not sent. The missing clients are reported in the response.\n\nThe sending of messages in a federated conversation could theoretically fail partially. To make this case unlikely, the backend first gets a list of clients from all the involved backends and then tries to send a message. So, if any backend is down, the message is not propagated to anyone. But the actual message fan out to multiple backends could still fail partially. This type of failure is reported as a 201, the clients for which the message sending failed are part of the response body.\n\nThis endpoint can lead to OtrMessageAdd event being sent to the recipients.\n\n**NOTE:** The protobuf definitions of the request body can be found at https://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto.Calls federation service galley on send-message
Calls federation service galley on on-message-sent
Calls federation service brig on get-user-clients", - "parameters": [ - { - "in": "path", - "name": "cnv_domain", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "path", - "name": "cnv", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], + "description": " [internal route ID: \"mls-reset-conversation\"]\n\n", + "operationId": "mls-reset-conversation", "requestBody": { "content": { - "application/x-protobuf": { + "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/QualifiedNewOtrMessage" + "$ref": "#/components/schemas/MLSReset_NzgwODA3ODc4" } } }, "required": true }, "responses": { - "201": { + "200": { + "description": "Conversation reset" + }, + "400": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MessageSendingStatus" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/MessageSendingStatus" + "example": { + "code": 400, + "label": "mls-protocol-error", + "message": "MLS protocol error" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-protocol-error", + "mls-group-id-not-supported", + "mls-federated-reset-not-supported", + "mls-not-enabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "Message sent" + "description": "MLS protocol error (label: `mls-protocol-error`)\n\nThe group ID version of the conversation is not supported by one of the federated backends (label: `mls-group-id-not-supported`)\n\nReset is not supported by the owning backend of the conversation (label: `mls-federated-reset-not-supported`)\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`) or `body`" }, "403": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { "code": 403, - "label": "unknown-client", - "message": "Unknown Client" + "label": "action-denied", + "message": "Insufficient authorization (missing leave_conversation)" }, "properties": { "code": { @@ -12929,9 +21562,9 @@ }, "label": { "enum": [ - "unknown-client", - "missing-legalhold-consent-old-clients", - "missing-legalhold-consent" + "action-denied", + "invalid-op", + "access-denied" ], "type": "string" }, @@ -12946,26 +21579,66 @@ ], "type": "object" } - }, + } + }, + "description": "Insufficient authorization (missing leave_conversation) (label: `action-denied`)\n\nInvalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)" + }, + "404": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "unknown-client", - "message": "Unknown Client" + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "unknown-client", - "missing-legalhold-consent-old-clients", - "missing-legalhold-consent" + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation not found (label: `no-conversation`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "mls-stale-message", + "message": "The conversation epoch in a message is too old" + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-stale-message" ], "type": "string" }, @@ -12982,7 +21655,64 @@ } } }, - "description": "Unknown Client (label: `unknown-client`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)" + "description": "The conversation epoch in a message is too old (label: `mls-stale-message`)" + } + }, + "summary": "Reset an MLS conversation to epoch 0" + } + }, + "/notifications": { + "get": { + "description": " [internal route ID: \"get-notifications\"]\n\nSee also: GET /teams/notifications", + "operationId": "get-notifications", + "parameters": [ + { + "description": "Only return notifications more recent than this", + "in": "query", + "name": "since", + "required": false, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "description": "Only return notifications targeted at the given client", + "in": "query", + "name": "client", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum number of notifications to return", + "in": "query", + "name": "size", + "required": false, + "schema": { + "format": "int32", + "maximum": 10000, + "minimum": 100, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueuedNotificationList_MTU0ODEyNTQ2" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/QueuedNotificationList_MTU0ODEyNTQ2" + } + } + }, + "description": "Notification list" }, "404": { "content": { @@ -12990,8 +21720,8 @@ "schema": { "example": { "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "label": "not-found", + "message": "Some notifications not found" }, "properties": { "code": { @@ -13002,7 +21732,7 @@ }, "label": { "enum": [ - "no-conversation" + "not-found" ], "type": "string" }, @@ -13022,8 +21752,8 @@ "schema": { "example": { "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "label": "not-found", + "message": "Some notifications not found" }, "properties": { "code": { @@ -13034,7 +21764,7 @@ }, "label": { "enum": [ - "no-conversation" + "not-found" ], "type": "string" }, @@ -13051,139 +21781,62 @@ } } }, - "description": "`cnv_domain` or `cnv` or Conversation not found (label: `no-conversation`)" - }, - "412": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MessageSendingStatus" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/MessageSendingStatus" - } - } - }, - "description": "Missing clients" + "description": "Some notifications not found (label: `not-found`)" } }, - "summary": "Post an encrypted message to a conversation (accepts only Protobuf)" + "summary": "Fetch notifications" } }, - "/conversations/{cnv_domain}/{cnv}/protocol": { - "put": { - "description": " [internal route ID: \"update-conversation-protocol\"]\n\n**Note**: Only proteus->mixed upgrade is supported.", + "/notifications/last": { + "get": { + "description": " [internal route ID: \"get-last-notification\"]\n\n", + "operationId": "get-last-notification", "parameters": [ { - "in": "path", - "name": "cnv_domain", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "Conversation ID", - "in": "path", - "name": "cnv", - "required": true, + "description": "Only return notifications targeted at the given client", + "in": "query", + "name": "client", + "required": false, "schema": { - "format": "uuid", "type": "string" } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ProtocolUpdate" - } - } - }, - "required": true - }, "responses": { "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/QueuedNotification_NTY2NzY2MTU2" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Event" - } - } - }, - "description": "Conversation updated" - }, - "204": { - "description": "Conversation unchanged" - }, - "400": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 400, - "label": "mls-migration-criteria-not-satisfied", - "message": "The migration criteria for mixed to MLS protocol transition are not satisfied for this conversation" - }, - "properties": { - "code": { - "enum": [ - 400 - ], - "type": "integer" - }, - "label": { - "enum": [ - "mls-migration-criteria-not-satisfied" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" + "$ref": "#/components/schemas/QueuedNotification_NTY2NzY2MTU2" } } }, - "description": "Invalid `body`\n\nThe migration criteria for mixed to MLS protocol transition are not satisfied for this conversation (label: `mls-migration-criteria-not-satisfied`)" + "description": "Notification found" }, - "403": { + "404": { "content": { - "application/json;charset=utf-8": { + "application/json": { "schema": { "example": { - "code": 403, - "label": "operation-denied", - "message": "Insufficient permissions" + "code": 404, + "label": "not-found", + "message": "Some notifications not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "operation-denied", - "no-team-member", - "invalid-op", - "action-denied", - "invalid-protocol-transition" + "not-found" ], "type": "string" }, @@ -13198,18 +21851,13 @@ ], "type": "object" } - } - }, - "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInvalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing leave_conversation) (label: `action-denied`)\n\nProtocol transition is invalid (label: `invalid-protocol-transition`)" - }, - "404": { - "content": { + }, "application/json;charset=utf-8": { "schema": { "example": { "code": 404, - "label": "no-team", - "message": "Team not found" + "label": "not-found", + "message": "Some notifications not found" }, "properties": { "code": { @@ -13220,8 +21868,7 @@ }, "label": { "enum": [ - "no-team", - "no-conversation" + "not-found" ], "type": "string" }, @@ -13238,85 +21885,72 @@ } } }, - "description": "`cnv_domain` or `cnv` not found\n\nTeam not found (label: `no-team`)\n\nConversation not found (label: `no-conversation`)" + "description": "Some notifications not found (label: `not-found`)" } }, - "summary": "Update the protocol of the conversation" + "summary": "Fetch the last notification" } }, - "/conversations/{cnv_domain}/{cnv}/receipt-mode": { - "put": { - "description": " [internal route ID: \"update-conversation-receipt-mode\"]\n\nCalls federation service brig on get-users-by-ids
Calls federation service galley on update-conversation
Calls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated", + "/notifications/{id}": { + "get": { + "description": " [internal route ID: \"get-notification-by-id\"]\n\n", + "operationId": "get-notification-by-id", "parameters": [ { + "description": "Notification ID", "in": "path", - "name": "cnv_domain", + "name": "id", "required": true, "schema": { + "format": "uuid", "type": "string" } }, { - "description": "Conversation ID", - "in": "path", - "name": "cnv", - "required": true, + "description": "Only return notifications targeted at the given client", + "in": "query", + "name": "client", + "required": false, "schema": { - "format": "uuid", "type": "string" } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ConversationReceiptModeUpdate" - } - } - }, - "required": true - }, "responses": { "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/QueuedNotification_NTY2NzY2MTU2" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/QueuedNotification_NTY2NzY2MTU2" } } }, - "description": "Receipt mode updated" - }, - "204": { - "description": "Receipt mode unchanged" + "description": "Notification found" }, - "403": { + "404": { "content": { - "application/json;charset=utf-8": { + "application/json": { "schema": { "example": { - "code": 403, - "label": "invalid-op", - "message": "Invalid operation" + "code": 404, + "label": "not-found", + "message": "Some notifications not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "invalid-op", - "access-denied", - "action-denied" + "not-found" ], "type": "string" }, @@ -13331,18 +21965,13 @@ ], "type": "object" } - } - }, - "description": "Invalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)\n\nInsufficient authorization (missing modify_conversation_receipt_mode) (label: `action-denied`)" - }, - "404": { - "content": { + }, "application/json;charset=utf-8": { "schema": { "example": { "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "label": "not-found", + "message": "Some notifications not found" }, "properties": { "code": { @@ -13353,7 +21982,7 @@ }, "label": { "enum": [ - "no-conversation" + "not-found" ], "type": "string" }, @@ -13370,28 +21999,51 @@ } } }, - "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + "description": "`id` or Some notifications not found (label: `not-found`)" } }, - "summary": "Update receipt mode for a conversation" + "summary": "Fetch a notification by ID" } }, - "/conversations/{cnv_domain}/{cnv}/self": { - "put": { - "description": " [internal route ID: \"update-conversation-self\"]\n\n**Note**: at least one field has to be provided.", + "/oauth/applications": { + "get": { + "description": " [internal route ID: \"get-oauth-applications\"]\n\nGet all OAuth applications with active account access for a user.", + "operationId": "get-oauth-applications", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/OAuthApplication_Mjk5NTUxNjA1" + }, + "type": "array" + } + }, + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/OAuthApplication_Mjk5NTUxNjA1" + }, + "type": "array" + } + } + }, + "description": "OAuth applications found" + } + }, + "summary": "Get OAuth applications with account access" + } + }, + "/oauth/applications/{OAuthClientId}/sessions": { + "delete": { + "description": " [internal route ID: \"revoke-oauth-account-access\"]\n\n", + "operationId": "revoke-oauth-account-access", "parameters": [ { + "description": "The ID of the OAuth client", "in": "path", - "name": "cnv_domain", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "Conversation ID", - "in": "path", - "name": "cnv", + "name": "OAuthClientId", "required": true, "schema": { "format": "uuid", @@ -13403,35 +22055,35 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/MemberUpdate" + "$ref": "#/components/schemas/PasswordReqBody_LTcxMzE3ODE3" } } }, "required": true }, "responses": { - "200": { - "description": "Update successful" + "204": { + "description": "OAuth application access revoked" }, - "404": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "code": 403, + "label": "access-denied", + "message": "Access denied." }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "no-conversation" + "access-denied" ], "type": "string" }, @@ -13448,27 +22100,21 @@ } } }, - "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + "description": "Access denied. (label: `access-denied`)" } }, - "summary": "Update self membership properties" + "summary": "Revoke account access from an OAuth application" } }, - "/conversations/{cnv_domain}/{cnv}/subconversations/{subconv}": { + "/oauth/applications/{OAuthClientId}/sessions/{RefreshTokenId}": { "delete": { - "description": " [internal route ID: \"delete-subconversation\"]\n\nCalls federation service galley on delete-sub-conversation", + "description": " [internal route ID: \"delete-oauth-refresh-token\"]\n\nRevoke an active OAuth session by providing the refresh token ID.", + "operationId": "delete-oauth-refresh-token", "parameters": [ { + "description": "The ID of the OAuth client", "in": "path", - "name": "cnv_domain", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "path", - "name": "cnv", + "name": "OAuthClientId", "required": true, "schema": { "format": "uuid", @@ -13476,10 +22122,12 @@ } }, { + "description": "The ID of the refresh token", "in": "path", - "name": "subconv", + "name": "RefreshTokenId", "required": true, "schema": { + "format": "uuid", "type": "string" } } @@ -13488,7 +22136,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/DeleteSubConversationRequest" + "$ref": "#/components/schemas/PasswordReqBody_LTcxMzE3ODE3" } } }, @@ -13497,14 +22145,6 @@ "responses": { "200": { "content": { - "application/json": { - "schema": { - "example": [], - "items": {}, - "maxItems": 0, - "type": "array" - } - }, "application/json;charset=utf-8": { "schema": { "example": [], @@ -13514,27 +22154,27 @@ } } }, - "description": "Deletion successful" + "description": "" }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "mls-not-enabled", - "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" + "code": 403, + "label": "access-denied", + "message": "Access denied." }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "mls-not-enabled" + "access-denied" ], "type": "string" }, @@ -13551,27 +22191,27 @@ } } }, - "description": "Invalid `body`\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" + "description": "Access denied. (label: `access-denied`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "access-denied", - "message": "Conversation access denied" + "code": 404, + "label": "not-found", + "message": "OAuth client not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "access-denied" + "not-found" ], "type": "string" }, @@ -13588,27 +22228,56 @@ } } }, - "description": "Conversation access denied (label: `access-denied`)" + "description": "`OAuthClientId` or `RefreshTokenId` not found\n\nOAuth client not found (label: `not-found`)" + } + }, + "summary": "Revoke an active OAuth session" + } + }, + "/oauth/authorization/codes": { + "post": { + "description": " [internal route ID: \"create-oauth-auth-code\"]\n\nCurrently only supports the 'code' response type, which corresponds to the authorization code flow.", + "operationId": "create-oauth-auth-code", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CreateOAuthAuthorizationCodeRequest_LTQ3NzI1Mjkz" + } + } }, - "404": { + "required": true + }, + "responses": { + "201": { + "description": "Created", + "headers": { + "Location": { + "schema": { + "type": "string" + } + } + } + }, + "400": { "content": { - "application/json;charset=utf-8": { + "application/json": { "schema": { "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "code": 400, + "label": "redirect-url-miss-match", + "message": "The redirect URL does not match the one registered with the client" }, "properties": { "code": { "enum": [ - 404 + 400 ], "type": "integer" }, "label": { "enum": [ - "no-conversation" + "redirect-url-miss-match" ], "type": "string" }, @@ -13623,29 +22292,24 @@ ], "type": "object" } - } - }, - "description": "`cnv_domain` or `cnv` or `subconv` not found\n\nConversation not found (label: `no-conversation`)" - }, - "409": { - "content": { + }, "application/json;charset=utf-8": { "schema": { "example": { - "code": 409, - "label": "mls-stale-message", - "message": "The conversation epoch in a message is too old" + "code": 400, + "label": "redirect-url-miss-match", + "message": "The redirect URL does not match the one registered with the client" }, "properties": { "code": { "enum": [ - 409 + 400 ], "type": "integer" }, "label": { "enum": [ - "mls-stale-message" + "redirect-url-miss-match" ], "type": "string" }, @@ -13662,38 +22326,53 @@ } } }, - "description": "The conversation epoch in a message is too old (label: `mls-stale-message`)" + "description": "Bad Request\n\nThe redirect URL does not match the one registered with the client (label: `redirect-url-miss-match`) or `body`", + "headers": { + "Location": { + "schema": { + "type": "string" + } + } + } + }, + "403": { + "description": "Forbidden", + "headers": { + "Location": { + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "Not Found", + "headers": { + "Location": { + "schema": { + "type": "string" + } + } + } } }, - "summary": "Delete an MLS subconversation" - }, + "summary": "Create an OAuth authorization code" + } + }, + "/oauth/clients/{OAuthClientId}": { "get": { - "description": " [internal route ID: \"get-subconversation\"]\n\nCalls federation service galley on get-sub-conversation", + "description": " [internal route ID: \"get-oauth-client\"]\n\n", + "operationId": "get-oauth-client", "parameters": [ { + "description": "The ID of the OAuth client", "in": "path", - "name": "cnv_domain", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "path", - "name": "cnv", + "name": "OAuthClientId", "required": true, "schema": { "format": "uuid", "type": "string" } - }, - { - "in": "path", - "name": "subconv", - "required": true, - "schema": { - "type": "string" - } } ], "responses": { @@ -13701,16 +22380,16 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PublicSubConversation" + "$ref": "#/components/schemas/OAuthClient_NzExMTI5NTIy" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/PublicSubConversation" + "$ref": "#/components/schemas/OAuthClient_NzExMTI5NTIy" } } }, - "description": "Subconversation" + "description": "OAuth client found" }, "403": { "content": { @@ -13718,8 +22397,8 @@ "schema": { "example": { "code": 403, - "label": "mls-subconv-unsupported-convtype", - "message": "MLS subconversations are only supported for regular conversations" + "label": "forbidden", + "message": "OAuth is disabled" }, "properties": { "code": { @@ -13730,8 +22409,7 @@ }, "label": { "enum": [ - "mls-subconv-unsupported-convtype", - "access-denied" + "forbidden" ], "type": "string" }, @@ -13748,16 +22426,48 @@ } } }, - "description": "MLS subconversations are only supported for regular conversations (label: `mls-subconv-unsupported-convtype`)\n\nConversation access denied (label: `access-denied`)" + "description": "OAuth is disabled (label: `forbidden`)" }, "404": { "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "OAuth client not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, "application/json;charset=utf-8": { "schema": { "example": { "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "label": "not-found", + "message": "OAuth client not found" }, "properties": { "code": { @@ -13768,7 +22478,7 @@ }, "label": { "enum": [ - "no-conversation" + "not-found" ], "type": "string" }, @@ -13785,72 +22495,59 @@ } } }, - "description": "`cnv_domain` or `cnv` or `subconv` not found\n\nConversation not found (label: `no-conversation`)" + "description": "`OAuthClientId` or OAuth client not found (label: `not-found`)\n\nOAuth client not found (label: `not-found`)" } }, - "summary": "Get information about an MLS subconversation" + "summary": "Get OAuth client information" } }, - "/conversations/{cnv_domain}/{cnv}/subconversations/{subconv}/groupinfo": { - "get": { - "description": " [internal route ID: \"get-subconversation-group-info\"]\n\nCalls federation service galley on query-group-info", - "parameters": [ - { - "in": "path", - "name": "cnv_domain", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "path", - "name": "cnv", - "required": true, - "schema": { - "format": "uuid", - "type": "string" + "/oauth/revoke": { + "post": { + "description": " [internal route ID: \"revoke-oauth-refresh-token\"]\n\nRevoke an access token.", + "operationId": "revoke-oauth-refresh-token", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/OAuthRevokeRefreshTokenRequest_MjA1MDg4MzQ4" + } } }, - { - "in": "path", - "name": "subconv", - "required": true, - "schema": { - "type": "string" - } - } - ], + "required": true + }, "responses": { "200": { "content": { - "message/mls": { + "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/GroupInfoData" + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" } } }, - "description": "The group information" + "description": "" }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "mls-not-enabled", - "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" + "code": 403, + "label": "forbidden", + "message": "Invalid refresh token" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "mls-not-enabled" + "forbidden" ], "type": "string" }, @@ -13867,7 +22564,7 @@ } } }, - "description": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" + "description": "Invalid refresh token (label: `forbidden`)" }, "404": { "content": { @@ -13875,8 +22572,8 @@ "schema": { "example": { "code": 404, - "label": "mls-missing-group-info", - "message": "The conversation has no group information" + "label": "not-found", + "message": "OAuth client not found" }, "properties": { "code": { @@ -13887,8 +22584,7 @@ }, "label": { "enum": [ - "mls-missing-group-info", - "no-conversation" + "not-found" ], "type": "string" }, @@ -13905,66 +22601,27 @@ } } }, - "description": "`cnv_domain` or `cnv` or `subconv` not found\n\nThe conversation has no group information (label: `mls-missing-group-info`)\n\nConversation not found (label: `no-conversation`)" - } - }, - "summary": "Get MLS group information of subconversation" - } - }, - "/conversations/{cnv_domain}/{cnv}/subconversations/{subconv}/self": { - "delete": { - "description": " [internal route ID: \"leave-subconversation\"]\n\nCalls federation service galley on leave-sub-conversation
Calls federation service galley on on-mls-message-sent", - "parameters": [ - { - "in": "path", - "name": "cnv_domain", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "path", - "name": "cnv", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - }, - { - "in": "path", - "name": "subconv", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" + "description": "OAuth client not found (label: `not-found`)" }, - "400": { + "500": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "mls-not-enabled", - "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" + "code": 500, + "label": "jwt-error", + "message": "Internal error while handling JWT token" }, "properties": { "code": { "enum": [ - 400 + 500 ], "type": "integer" }, "label": { "enum": [ - "mls-not-enabled", - "mls-protocol-error" + "jwt-error" ], "type": "string" }, @@ -13981,7 +22638,36 @@ } } }, - "description": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)\n\nMLS protocol error (label: `mls-protocol-error`)" + "description": "Internal error while handling JWT token (label: `jwt-error`)" + } + }, + "summary": "Revoke an OAuth refresh token" + } + }, + "/oauth/token": { + "post": { + "description": " [internal route ID: \"create-oauth-access-token\"]\n\nObtain a new access token from an authorization code or a refresh token.", + "operationId": "create-oauth-access-token", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Either_OAuthAccessTokenRequest_OAuthRefreshAccessTokenRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/OAuthAccessTokenResponse_NzEwOTI4NjQ0" + } + } + }, + "description": "" }, "403": { "content": { @@ -13989,8 +22675,8 @@ "schema": { "example": { "code": 403, - "label": "access-denied", - "message": "Conversation access denied" + "label": "invalid_grant", + "message": "Invalid grant" }, "properties": { "code": { @@ -14001,7 +22687,8 @@ }, "label": { "enum": [ - "access-denied" + "invalid_grant", + "forbidden" ], "type": "string" }, @@ -14018,7 +22705,7 @@ } } }, - "description": "Conversation access denied (label: `access-denied`)" + "description": "Invalid grant (label: `invalid_grant`)\n\nInvalid client credentials (label: `forbidden`)\n\nInvalid grant type (label: `forbidden`)\n\nInvalid refresh token (label: `forbidden`)\n\nOAuth is disabled (label: `forbidden`)" }, "404": { "content": { @@ -14026,8 +22713,8 @@ "schema": { "example": { "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "label": "not-found", + "message": "OAuth client not found" }, "properties": { "code": { @@ -14038,7 +22725,7 @@ }, "label": { "enum": [ - "no-conversation" + "not-found" ], "type": "string" }, @@ -14055,27 +22742,27 @@ } } }, - "description": "`cnv_domain` or `cnv` or `subconv` not found\n\nConversation not found (label: `no-conversation`)" + "description": "OAuth client not found (label: `not-found`)\n\nOAuth authorization code not found (label: `not-found`)" }, - "409": { + "500": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 409, - "label": "mls-stale-message", - "message": "The conversation epoch in a message is too old" + "code": 500, + "label": "jwt-error", + "message": "Internal error while handling JWT token" }, "properties": { "code": { "enum": [ - 409 + 500 ], "type": "integer" }, "label": { "enum": [ - "mls-stale-message" + "jwt-error" ], "type": "string" }, @@ -14092,40 +22779,21 @@ } } }, - "description": "The conversation epoch in a message is too old (label: `mls-stale-message`)" + "description": "Internal error while handling JWT token (label: `jwt-error`)" } }, - "summary": "Leave an MLS subconversation" + "summary": "Create an OAuth access token" } }, - "/conversations/{cnv_domain}/{cnv}/typing": { + "/one2one-conversations": { "post": { - "description": " [internal route ID: \"member-typing-qualified\"]\n\nCalls federation service galley on on-typing-indicator-updated
Calls federation service galley on update-typing-indicator", - "parameters": [ - { - "in": "path", - "name": "cnv_domain", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "Conversation ID", - "in": "path", - "name": "cnv", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], + "description": " [internal route ID: \"create-one-to-one-conversation\"]\n\n", + "operationId": "create-one-to-one-conversation", "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/TypingData" + "$ref": "#/components/schemas/NewOne2OneConv_LTI3OTc4NDAz" } } }, @@ -14133,93 +22801,52 @@ }, "responses": { "200": { - "description": "Notification sent" - }, - "404": { "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/v3_OwnConversation_GroupConvType_LTU2MzYxNTg0V3" + } + }, "application/json;charset=utf-8": { "schema": { - "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" - }, - "properties": { - "code": { - "enum": [ - 404 - ], - "type": "integer" - }, - "label": { - "enum": [ - "no-conversation" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" + "$ref": "#/components/schemas/v3_OwnConversation_GroupConvType_LTU2MzYxNTg0V3" } } }, - "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" - } - }, - "summary": "Sending typing notifications" - } - }, - "/conversations/{cnv}": { - "put": { - "deprecated": true, - "description": " [internal route ID: \"update-conversation-name-deprecated\"]\n\nUse `/conversations/:domain/:conv/name` instead.Calls federation service brig on get-users-by-ids
Calls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated", - "parameters": [ - { - "description": "Conversation ID", - "in": "path", - "name": "cnv", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ConversationRename" + "description": "Conversation existed", + "headers": { + "Location": { + "description": "Conversation ID", + "schema": { + "format": "uuid", + "type": "string" + } } } }, - "required": true - }, - "responses": { - "200": { + "201": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/v3_OwnConversation_GroupConvType_LTU2MzYxNTg0V3" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/v3_OwnConversation_GroupConvType_LTU2MzYxNTg0V3" } } }, - "description": "Name updated" - }, - "204": { - "description": "Name unchanged" + "description": "Conversation created", + "headers": { + "Location": { + "description": "Conversation ID", + "schema": { + "format": "uuid", + "type": "string" + } + } + } }, "403": { "content": { @@ -14227,8 +22854,8 @@ "schema": { "example": { "code": 403, - "label": "invalid-op", - "message": "Invalid operation" + "label": "missing-legalhold-consent", + "message": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent" }, "properties": { "code": { @@ -14239,8 +22866,13 @@ }, "label": { "enum": [ + "missing-legalhold-consent", + "operation-denied", + "not-connected", + "no-team-member", + "non-binding-team-members", "invalid-op", - "action-denied" + "access-denied" ], "type": "string" }, @@ -14257,7 +22889,7 @@ } } }, - "description": "Invalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing modify_conversation_name) (label: `action-denied`)" + "description": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nInsufficient permissions (label: `operation-denied`)\n\nUsers are not connected (label: `not-connected`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nBoth users must be members of the same binding team (label: `non-binding-team-members`)\n\nInvalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)" }, "404": { "content": { @@ -14265,8 +22897,8 @@ "schema": { "example": { "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { @@ -14277,7 +22909,8 @@ }, "label": { "enum": [ - "no-conversation" + "no-team", + "non-binding-team" ], "type": "string" }, @@ -14294,25 +22927,66 @@ } } }, - "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)" + "description": "Team not found (label: `no-team`)\n\nNot a member of a binding team (label: `non-binding-team`)" + }, + "533": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "unreachable_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "unreachable_backends" + ], + "type": "object" + } + } + }, + "description": "Some domains are unreachable" } }, - "summary": "Update conversation name (deprecated)" + "summary": "Create a 1:1 conversation" } }, - "/conversations/{cnv}/code": { - "delete": { - "description": " [internal route ID: \"remove-code-unqualified\"]\n\n", + "/one2one-conversations/{usr_domain}/{usr}": { + "get": { + "description": " [internal route ID: \"get-one-to-one-mls-conversation\"]\n\n", + "operationId": "get-one-to-one-mls-conversation", "parameters": [ { - "description": "Conversation ID", "in": "path", - "name": "cnv", + "name": "usr_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "usr", "required": true, "schema": { "format": "uuid", "type": "string" } + }, + { + "in": "query", + "name": "format", + "required": false, + "schema": { + "enum": [ + "raw", + "jwk" + ], + "type": "string" + } } ], "responses": { @@ -14320,16 +22994,53 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/MLSOne2OneConversation_SomeKey_GroupConvType_LTg2MTcwMjY3" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/MLSOne2OneConversation_SomeKey_GroupConvType_LTg2MTcwMjY3" } } }, - "description": "Conversation code deleted." + "description": "MLS 1-1 conversation" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-not-enabled", + "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-not-enabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `format`\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" }, "403": { "content": { @@ -14337,8 +23048,8 @@ "schema": { "example": { "code": 403, - "label": "access-denied", - "message": "Conversation access denied" + "label": "not-connected", + "message": "Users are not connected" }, "properties": { "code": { @@ -14349,7 +23060,7 @@ }, "label": { "enum": [ - "access-denied" + "not-connected" ], "type": "string" }, @@ -14366,27 +23077,71 @@ } } }, - "description": "Conversation access denied (label: `access-denied`)" + "description": "Users are not connected (label: `not-connected`)" + } + }, + "summary": "Get an MLS 1:1 conversation" + } + }, + "/password-reset": { + "post": { + "description": " [internal route ID: \"post-password-reset\"]\n\n", + "operationId": "post-password-reset", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewPasswordReset_LTEyNzAxMTcy" + } + } }, - "404": { + "required": true + }, + "responses": { + "201": { + "description": "Password reset code created and sent by email." + } + }, + "summary": "Initiate a password reset." + } + }, + "/password-reset/complete": { + "post": { + "description": " [internal route ID: \"post-password-reset-complete\"]\n\n", + "operationId": "post-password-reset-complete", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CompletePasswordReset_NDcyMjY5OTc4" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Password reset successful." + }, + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "code": 400, + "label": "invalid-code", + "message": "Invalid password reset code." }, "properties": { "code": { "enum": [ - 404 + 400 ], "type": "integer" }, "label": { "enum": [ - "no-conversation" + "invalid-code" ], "type": "string" }, @@ -14403,21 +23158,103 @@ } } }, - "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)" + "description": "Invalid `body`\n\nInvalid password reset code. (label: `invalid-code`)" + } + }, + "summary": "Complete a password reset." + } + }, + "/properties": { + "delete": { + "description": " [internal route ID: \"clear-properties\"]\n\n", + "operationId": "clear-properties", + "responses": { + "200": { + "description": "Properties cleared" + } + }, + "summary": "Clear all properties" + }, + "get": { + "description": " [internal route ID: \"list-property-keys\"]\n\n", + "operationId": "list-property-keys", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ASCII" + }, + "type": "array" + } + }, + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/ASCII" + }, + "type": "array" + } + } + }, + "description": "List of property keys" + } + }, + "summary": "List all property keys" + } + }, + "/properties-values": { + "get": { + "description": " [internal route ID: \"list-properties\"]\n\n", + "operationId": "list-properties", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PropertyKeysAndValues" + } + } + }, + "description": "" } }, - "summary": "Delete conversation code" + "summary": "List all properties with key and value" + } + }, + "/properties/{key}": { + "delete": { + "description": " [internal route ID: \"delete-property\"]\n\n", + "operationId": "delete-property", + "parameters": [ + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "format": "printable", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Property deleted" + } + }, + "summary": "Delete a property" }, "get": { - "description": " [internal route ID: \"get-code\"]\n\n", + "description": " [internal route ID: \"get-property\"]\n\n", + "operationId": "get-property", "parameters": [ { - "description": "Conversation ID", "in": "path", - "name": "cnv", + "name": "key", "required": true, "schema": { - "format": "uuid", + "format": "printable", "type": "string" } } @@ -14427,111 +23264,94 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ConversationCodeInfo" + "$ref": "#/components/schemas/PropertyValue" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ConversationCodeInfo" + "$ref": "#/components/schemas/PropertyValue" } } }, - "description": "Conversation Code" + "description": "The property value" }, - "403": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 403, - "label": "access-denied", - "message": "Conversation access denied" - }, - "properties": { - "code": { - "enum": [ - 403 - ], - "type": "integer" - }, - "label": { - "enum": [ - "access-denied" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } + "404": { + "description": "`key` or Property not found(**Note**: This error has an empty body for legacy reasons)" + } + }, + "summary": "Get a property value" + }, + "put": { + "description": " [internal route ID: \"set-property\"]\n\n", + "operationId": "set-property", + "parameters": [ + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "format": "printable", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PropertyValue" } - }, - "description": "Conversation access denied (label: `access-denied`)" + } }, - "404": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" - }, - "properties": { - "code": { - "enum": [ - 404 - ], - "type": "integer" - }, - "label": { - "enum": [ - "no-conversation", - "no-conversation-code" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } + "required": true + }, + "responses": { + "200": { + "description": "Property set" + } + }, + "summary": "Set a user property" + } + }, + "/provider": { + "delete": { + "description": " [internal route ID: \"provider-delete\"]\n\n", + "operationId": "provider-delete", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DeleteProvider_MzYxMzM3Mjg2" } - }, - "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)\n\nConversation code not found (label: `no-conversation-code`)" + } }, - "409": { + "required": true + }, + "responses": { + "200": { + "description": "" + }, + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 409, - "label": "guest-links-disabled", - "message": "The guest link feature is disabled and all guest links have been revoked" + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" }, "properties": { "code": { "enum": [ - 409 + 403 ], "type": "integer" }, "label": { "enum": [ - "guest-links-disabled" + "invalid-credentials", + "invalid-provider", + "access-denied" ], "type": "string" }, @@ -14548,65 +23368,29 @@ } } }, - "description": "The guest link feature is disabled and all guest links have been revoked (label: `guest-links-disabled`)" + "description": "Authentication failed (label: `invalid-credentials`)\n\nThe provider does not exist. (label: `invalid-provider`)\n\nAccess denied. (label: `access-denied`)" } }, - "summary": "Get existing conversation code" + "summary": "Delete a provider" }, - "post": { - "description": " [internal route ID: \"create-conversation-code-unqualified\"]\n\n\nOAuth scope: `write:conversations_code`", - "parameters": [ - { - "description": "Conversation ID", - "in": "path", - "name": "cnv", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/CreateConversationCodeRequest" - } - } - }, - "required": true - }, + "get": { + "description": " [internal route ID: \"provider-get-account\"]\n\n", + "operationId": "provider-get-account", "responses": { "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ConversationCodeInfo" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ConversationCodeInfo" - } - } - }, - "description": "Conversation code already exists." - }, - "201": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/Provider_NDIyMzQ3ODIy" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/Provider_NDIyMzQ3ODIy" } } }, - "description": "Conversation code created." + "description": "" }, "403": { "content": { @@ -14615,7 +23399,7 @@ "example": { "code": 403, "label": "access-denied", - "message": "Conversation access denied" + "message": "Access denied." }, "properties": { "code": { @@ -14643,16 +23427,16 @@ } } }, - "description": "Conversation access denied (label: `access-denied`)" + "description": "Access denied. (label: `access-denied`)" }, "404": { "content": { - "application/json;charset=utf-8": { + "application/json": { "schema": { "example": { "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "label": "not-found", + "message": "Provider not found." }, "properties": { "code": { @@ -14663,7 +23447,7 @@ }, "label": { "enum": [ - "no-conversation" + "not-found" ], "type": "string" }, @@ -14678,30 +23462,24 @@ ], "type": "object" } - } - }, - "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)" - }, - "409": { - "content": { + }, "application/json;charset=utf-8": { "schema": { "example": { - "code": 409, - "label": "create-conv-code-conflict", - "message": "Conversation code already exists with a different password setting than the requested one." + "code": 404, + "label": "not-found", + "message": "Provider not found." }, "properties": { "code": { "enum": [ - 409 + 404 ], "type": "integer" }, "label": { "enum": [ - "create-conv-code-conflict", - "guest-links-disabled" + "not-found" ], "type": "string" }, @@ -14718,36 +23496,26 @@ } } }, - "description": "Conversation code already exists with a different password setting than the requested one. (label: `create-conv-code-conflict`)\n\nThe guest link feature is disabled and all guest links have been revoked (label: `guest-links-disabled`)" + "description": "Provider not found. (label: `not-found`)\n\nProvider not found. (label: `not-found`)" } }, - "summary": "Create or recreate a conversation code" - } - }, - "/conversations/{cnv}/features/conversationGuestLinks": { - "get": { - "description": " [internal route ID: \"get-conversation-guest-links-status\"]\n\n", - "parameters": [ - { - "description": "Conversation ID", - "in": "path", - "name": "cnv", - "required": true, - "schema": { - "format": "uuid", - "type": "string" + "summary": "Get account" + }, + "put": { + "description": " [internal route ID: \"provider-update\"]\n\n", + "operationId": "provider-update", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UpdateProvider_LTQwMjY4MDgy" + } } - } - ], + }, + "required": true + }, "responses": { "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/GuestLinksConfig.LockableFeature" - } - } - }, "description": "" }, "403": { @@ -14756,8 +23524,8 @@ "schema": { "example": { "code": 403, - "label": "access-denied", - "message": "Conversation access denied" + "label": "invalid-provider", + "message": "The provider does not exist." }, "properties": { "code": { @@ -14768,6 +23536,7 @@ }, "label": { "enum": [ + "invalid-provider", "access-denied" ], "type": "string" @@ -14785,147 +23554,73 @@ } } }, - "description": "Conversation access denied (label: `access-denied`)" - }, - "404": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" - }, - "properties": { - "code": { - "enum": [ - 404 - ], - "type": "integer" - }, - "label": { - "enum": [ - "no-conversation" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } - } - }, - "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)" + "description": "The provider does not exist. (label: `invalid-provider`)\n\nAccess denied. (label: `access-denied`)" } }, - "summary": "Get the status of the guest links feature for a conversation that potentially has been created by someone from another team." + "summary": "Update a provider" } }, - "/conversations/{cnv}/members/{usr}": { - "put": { - "deprecated": true, - "description": " [internal route ID: \"update-other-member-unqualified\"]\n\nUse `PUT /conversations/:cnv_domain/:cnv/members/:usr_domain/:usr` insteadCalls federation service brig on get-users-by-ids
Calls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated", + "/provider/activate": { + "get": { + "description": " [internal route ID: \"provider-activate\"]\n\n", + "operationId": "provider-activate", "parameters": [ { - "description": "Conversation ID", - "in": "path", - "name": "cnv", + "in": "query", + "name": "key", "required": true, "schema": { - "format": "uuid", "type": "string" } }, { - "description": "Target User ID", - "in": "path", - "name": "usr", + "in": "query", + "name": "code", "required": true, "schema": { - "format": "uuid", "type": "string" } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/OtherMemberUpdate" - } - } - }, - "required": true - }, "responses": { "200": { - "description": "Membership updated" - }, - "403": { "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderActivationResponse_LTgzNTU3MzA5" + } + }, "application/json;charset=utf-8": { "schema": { - "example": { - "code": 403, - "label": "invalid-op", - "message": "Invalid operation" - }, - "properties": { - "code": { - "enum": [ - 403 - ], - "type": "integer" - }, - "label": { - "enum": [ - "invalid-op", - "action-denied" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" + "$ref": "#/components/schemas/ProviderActivationResponse_LTgzNTU3MzA5" } } }, - "description": "Invalid operation (label: `invalid-op`)\n\nInvalid target (label: `invalid-op`)\n\nInsufficient authorization (missing modify_other_conversation_member) (label: `action-denied`)" + "description": "" }, - "404": { + "204": { + "description": "" + }, + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-conversation-member", - "message": "Conversation member not found" + "code": 403, + "label": "invalid-code", + "message": "Invalid verification code" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "no-conversation-member", - "no-conversation" + "invalid-code", + "access-denied" ], "type": "string" }, @@ -14942,78 +23637,71 @@ } } }, - "description": "`cnv` or `usr` not found\n\nConversation member not found (label: `no-conversation-member`)\n\nConversation not found (label: `no-conversation`)" + "description": "Invalid verification code (label: `invalid-code`)\n\nAccess denied. (label: `access-denied`)" } }, - "summary": "Update membership of the specified user (deprecated)" + "summary": "Activate a provider" } }, - "/conversations/{cnv}/message-timer": { - "put": { - "deprecated": true, - "description": " [internal route ID: \"update-conversation-message-timer-unqualified\"]\n\nUse `/conversations/:domain/:cnv/message-timer` instead.Calls federation service brig on get-users-by-ids
Calls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated", - "parameters": [ - { - "description": "Conversation ID", - "in": "path", - "name": "cnv", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], + "/provider/assets": { + "post": { + "description": " [internal route ID: (\"assets-upload-v3\", provider)]\n\n

Construct the request as multipart/mixed; set header Content-Type: multipart/mixed; boundary=<boundary>.

Use exactly two parts in this order:

  1. application/json metadata (AssetSettings)
  2. application/octet-stream asset bytes

Each part must include Content-Type and Content-Length; the second part may include Content-MD5. Use CRLF between headers and bodies.

When asset audit logging is enabled, the JSON metadata must include:

  • convId: object { id: UUID, domain: String } (qualified conversation ID)
  • filename: String
  • filetype: String MIME type (e.g. image/png, application/pdf)

Optional metadata: public (Bool, default false), retention (one of eternal, persistent, volatile, eternal-infrequent_access, expiring).

For profile pictures or team icons without a conversation, set convId.id to 00000000-0000-0000-0000-000000000000 and convId.domain to the tenant’s domain; use any reasonable filename.

Note: the server treats the asset bytes as application/octet-stream; filetype is used for auditing only.

Example body (boundary=frontier):

Content-Type: multipart/mixed; boundary=frontier

--frontier
Content-Type: application/json
Content-Length: 191

{\"public\":false,\"retention\":\"volatile\",\"convId\":{\"id\":\"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\",\"domain\":\"example.com\"},\"filename\":\"report.pdf\",\"filetype\":\"application/pdf\"}
--frontier
Content-Type: application/octet-stream
Content-Length: 11

Hello Audit
--frontier--
", + "operationId": "assets-upload-v3_provider", "requestBody": { "content": { - "application/json;charset=utf-8": { + "multipart/mixed": { "schema": { - "$ref": "#/components/schemas/ConversationMessageTimerUpdate" + "$ref": "#/components/schemas/AssetSource" } } }, - "required": true + "description": "A body with content type `multipart/mixed body`. The first section's content type should be `application/json`. The second section's content type should be always be `application/octet-stream`. Other content types will be ignored by the server." }, "responses": { - "200": { + "201": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/Asset_Qualified_AssetKey_MzU1MjMxNTA5" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Event" + "$ref": "#/components/schemas/Asset_Qualified_AssetKey_MzU1MjMxNTA5" } } }, - "description": "Message timer updated" - }, - "204": { - "description": "Message timer unchanged" + "description": "Asset posted", + "headers": { + "Location": { + "description": "Asset location", + "schema": { + "format": "url", + "type": "string" + } + } + } }, - "403": { + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "invalid-op", - "message": "Invalid operation" + "code": 400, + "label": "incomplete-body", + "message": "HTTP content-length header does not match body size" }, "properties": { "code": { "enum": [ - 403 + 400 ], "type": "integer" }, "label": { "enum": [ - "invalid-op", - "access-denied", - "action-denied" + "incomplete-body", + "invalid-length" ], "type": "string" }, @@ -15030,27 +23718,27 @@ } } }, - "description": "Invalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)\n\nInsufficient authorization (missing modify_conversation_message_timer) (label: `action-denied`)" + "description": "Invalid `body`\n\nHTTP content-length header does not match body size (label: `incomplete-body`)\n\nInvalid content length (label: `invalid-length`)" }, - "404": { + "413": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "code": 413, + "label": "client-error", + "message": "Asset too large" }, "properties": { "code": { "enum": [ - 404 + 413 ], "type": "integer" }, "label": { "enum": [ - "no-conversation" + "client-error" ], "type": "string" }, @@ -15067,56 +23755,29 @@ } } }, - "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)" + "description": "Asset too large (label: `client-error`)" } }, - "summary": "Update the message timer for a conversation (deprecated)" + "summary": "Upload an asset" } }, - "/conversations/{cnv}/name": { - "put": { - "deprecated": true, - "description": " [internal route ID: \"update-conversation-name-unqualified\"]\n\nUse `/conversations/:domain/:conv/name` instead.Calls federation service brig on get-users-by-ids
Calls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated", + "/provider/assets/{key}": { + "delete": { + "description": " [internal route ID: (\"assets-delete-v3\", provider)]\n\n", + "operationId": "assets-delete-v3_provider", "parameters": [ { - "description": "Conversation ID", "in": "path", - "name": "cnv", + "name": "key", "required": true, "schema": { - "format": "uuid", "type": "string" } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ConversationRename" - } - } - }, - "required": true - }, "responses": { "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Event" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Event" - } - } - }, - "description": "Name updated" - }, - "204": { - "description": "Name unchanged" + "description": "Asset deleted" }, "403": { "content": { @@ -15124,8 +23785,8 @@ "schema": { "example": { "code": 403, - "label": "invalid-op", - "message": "Invalid operation" + "label": "unauthorised", + "message": "Unauthorised operation" }, "properties": { "code": { @@ -15136,8 +23797,7 @@ }, "label": { "enum": [ - "invalid-op", - "action-denied" + "unauthorised" ], "type": "string" }, @@ -15154,7 +23814,7 @@ } } }, - "description": "Invalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing modify_conversation_name) (label: `action-denied`)" + "description": "Unauthorised operation (label: `unauthorised`)" }, "404": { "content": { @@ -15162,8 +23822,8 @@ "schema": { "example": { "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "label": "not-found", + "message": "Asset not found" }, "properties": { "code": { @@ -15174,7 +23834,7 @@ }, "label": { "enum": [ - "no-conversation" + "not-found" ], "type": "string" }, @@ -15191,28 +23851,26 @@ } } }, - "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)" + "description": "`key` not found\n\nAsset not found (label: `not-found`)" } }, - "summary": "Update conversation name (deprecated)" - } - }, - "/conversations/{cnv}/otr/messages": { - "post": { - "description": " [internal route ID: \"post-otr-message-unqualified\"]\n\nThis endpoint ensures that the list of clients is correct and only sends the message if the list is correct.\nTo override this, the endpoint accepts two query params:\n- `ignore_missing`: Can be 'true' 'false' or a comma separated list of user IDs.\n - When 'true' all missing clients are ignored.\n - When 'false' all missing clients are reported.\n - When comma separated list of user-ids, only clients for listed users are ignored.\n- `report_missing`: Can be 'true' 'false' or a comma separated list of user IDs.\n - When 'true' all missing clients are reported.\n - When 'false' all missing clients are ignored.\n - When comma separated list of user-ids, only clients for listed users are reported.\n\nApart from these, the request body also accepts `report_missing` which can only be a list of user ids and behaves the same way as the query parameter.\n\nAll three of these should be considered mutually exclusive. The server however does not error if more than one is specified, it reads them in this order of precedence:\n- `report_missing` in the request body has highest precedence.\n- `ignore_missing` in the query param is the next.\n- `report_missing` in the query param has the lowest precedence.\n\nThis endpoint can lead to OtrMessageAdd event being sent to the recipients.\n\n**NOTE:** The protobuf definitions of the request body can be found at https://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto.Calls federation service brig on get-user-clients
Calls federation service galley on on-message-sent", + "summary": "Delete an asset" + }, + "get": { + "description": " [internal route ID: (\"assets-download-v3\", provider)]\n\n", + "operationId": "assets-download-v3_provider", "parameters": [ { "in": "path", - "name": "cnv", + "name": "key", "required": true, "schema": { - "format": "uuid", "type": "string" } }, { - "in": "query", - "name": "ignore_missing", + "in": "header", + "name": "Asset-Token", "required": false, "schema": { "type": "string" @@ -15220,65 +23878,45 @@ }, { "in": "query", - "name": "report_missing", + "name": "asset_token", "required": false, "schema": { "type": "string" } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/new-otr-message" - } - }, - "application/x-protobuf": { - "schema": { - "$ref": "#/components/schemas/new-otr-message" - } - } - }, - "required": true - }, "responses": { - "201": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClientMismatch" - } - }, - "application/json;charset=utf-8": { + "302": { + "description": "Asset found", + "headers": { + "Location": { + "description": "Asset location", "schema": { - "$ref": "#/components/schemas/ClientMismatch" + "format": "url", + "type": "string" } } - }, - "description": "Message sent" + } }, - "403": { + "404": { "content": { "application/json": { "schema": { "example": { - "code": 403, - "label": "unknown-client", - "message": "Unknown Client" + "code": 404, + "label": "not-found", + "message": "Asset not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "unknown-client", - "missing-legalhold-consent-old-clients", - "missing-legalhold-consent" + "not-found" ], "type": "string" }, @@ -15297,22 +23935,20 @@ "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "unknown-client", - "message": "Unknown Client" + "code": 404, + "label": "not-found", + "message": "Asset not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "unknown-client", - "missing-legalhold-consent-old-clients", - "missing-legalhold-consent" + "not-found" ], "type": "string" }, @@ -15329,27 +23965,49 @@ } } }, - "description": "Unknown Client (label: `unknown-client`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)" + "description": "`key` or Asset not found (label: `not-found`)" + } + }, + "summary": "Download an asset" + } + }, + "/provider/email": { + "put": { + "description": " [internal route ID: \"provider-update-email\"]\n\n", + "operationId": "provider-update-email", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/EmailUpdate_LTYwODE0ODQ5" + } + } }, - "404": { + "required": true + }, + "responses": { + "202": { + "description": "" + }, + "400": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "code": 400, + "label": "invalid-email", + "message": "Invalid e-mail address." }, "properties": { "code": { "enum": [ - 404 + 400 ], "type": "integer" }, "label": { "enum": [ - "no-conversation" + "invalid-email" ], "type": "string" }, @@ -15364,24 +24022,30 @@ ], "type": "object" } - }, + } + }, + "description": "Invalid `body`\n\nInvalid e-mail address. (label: `invalid-email`)" + }, + "403": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "code": 403, + "label": "invalid-provider", + "message": "The provider does not exist." }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "no-conversation" + "invalid-provider", + "access-denied" ], "type": "string" }, @@ -15398,48 +24062,58 @@ } } }, - "description": "`cnv` or Conversation not found (label: `no-conversation`)" + "description": "The provider does not exist. (label: `invalid-provider`)\n\nAccess denied. (label: `access-denied`)" }, - "412": { + "429": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClientMismatch" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ClientMismatch" + "example": { + "code": 429, + "label": "too-many-requests", + "message": "Too many request to generate a verification code." + }, + "properties": { + "code": { + "enum": [ + 429 + ], + "type": "integer" + }, + "label": { + "enum": [ + "too-many-requests" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "Missing clients" + "description": "Too many request to generate a verification code. (label: `too-many-requests`)" } }, - "summary": "Post an encrypted message to a conversation (accepts JSON or Protobuf)" + "summary": "Update a provider email" } }, - "/conversations/{cnv}/receipt-mode": { - "put": { - "deprecated": true, - "description": " [internal route ID: \"update-conversation-receipt-mode-unqualified\"]\n\nUse `PUT /conversations/:domain/:cnv/receipt-mode` instead.Calls federation service brig on get-users-by-ids
Calls federation service galley on update-conversation
Calls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated", - "parameters": [ - { - "description": "Conversation ID", - "in": "path", - "name": "cnv", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], + "/provider/login": { + "post": { + "description": " [internal route ID: \"provider-login\"]\n\n", + "operationId": "provider-login", "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ConversationReceiptModeUpdate" + "$ref": "#/components/schemas/ProviderLogin_LTE2MTk2NTM5" } } }, @@ -15447,22 +24121,74 @@ }, "responses": { "200": { - "content": { - "application/json": { + "description": "OK", + "headers": { + "Set-Cookie": { "schema": { - "$ref": "#/components/schemas/Event" + "type": "string" } - }, + } + } + }, + "403": { + "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Event" + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "Receipt mode updated" + "description": "Authentication failed (label: `invalid-credentials`)\n\nAccess denied. (label: `access-denied`)" + } + }, + "summary": "Login as a provider" + } + }, + "/provider/password": { + "put": { + "description": " [internal route ID: \"provider-update-password\"]\n\n", + "operationId": "provider-update-password", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PasswordChange_NDI0ODgwNDU0" + } + } }, - "204": { - "description": "Receipt mode unchanged" + "required": true + }, + "responses": { + "200": { + "description": "" }, "403": { "content": { @@ -15470,8 +24196,8 @@ "schema": { "example": { "code": 403, - "label": "invalid-op", - "message": "Invalid operation" + "label": "invalid-credentials", + "message": "Authentication failed" }, "properties": { "code": { @@ -15482,9 +24208,8 @@ }, "label": { "enum": [ - "invalid-op", - "access-denied", - "action-denied" + "invalid-credentials", + "access-denied" ], "type": "string" }, @@ -15501,27 +24226,27 @@ } } }, - "description": "Invalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)\n\nInsufficient authorization (missing modify_conversation_receipt_mode) (label: `action-denied`)" + "description": "Authentication failed (label: `invalid-credentials`)\n\nAccess denied. (label: `access-denied`)" }, - "404": { + "409": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "code": 409, + "label": "password-must-differ", + "message": "For password reset, new and old password must be different." }, "properties": { "code": { "enum": [ - 404 + 409 ], "type": "integer" }, "label": { "enum": [ - "no-conversation" + "password-must-differ" ], "type": "string" }, @@ -15538,36 +24263,67 @@ } } }, - "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)" + "description": "For password reset, new and old password must be different. (label: `password-must-differ`)" } }, - "summary": "Update receipt mode for a conversation (deprecated)" + "summary": "Update a provider password" } }, - "/conversations/{cnv}/roles": { - "get": { - "description": " [internal route ID: \"get-conversation-roles\"]\n\n", - "parameters": [ - { - "in": "path", - "name": "cnv", - "required": true, - "schema": { - "format": "uuid", - "type": "string" + "/provider/password-reset": { + "post": { + "description": " [internal route ID: \"provider-password-reset\"]\n\n", + "operationId": "provider-password-reset", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PasswordReset_LTYzNDYxNTQ3" + } } - } - ], + }, + "required": true + }, "responses": { - "200": { + "201": { + "description": "" + }, + "400": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ConversationRolesList" + "example": { + "code": 400, + "label": "invalid-code", + "message": "Invalid password reset code." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-code", + "invalid-key" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "" + "description": "Invalid `body`\n\nInvalid password reset code. (label: `invalid-code`)\n\nInvalid email or mobile number for password reset. (label: `invalid-key`)" }, "403": { "content": { @@ -15575,8 +24331,8 @@ "schema": { "example": { "code": 403, - "label": "access-denied", - "message": "Conversation access denied" + "label": "invalid-credentials", + "message": "Authentication failed" }, "properties": { "code": { @@ -15587,6 +24343,7 @@ }, "label": { "enum": [ + "invalid-credentials", "access-denied" ], "type": "string" @@ -15604,27 +24361,28 @@ } } }, - "description": "Conversation access denied (label: `access-denied`)" + "description": "Authentication failed (label: `invalid-credentials`)\n\nAccess denied. (label: `access-denied`)" }, - "404": { + "409": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "code": 409, + "label": "password-must-differ", + "message": "For password reset, new and old password must be different." }, "properties": { "code": { "enum": [ - 404 + 409 ], "type": "integer" }, "label": { "enum": [ - "no-conversation" + "password-must-differ", + "code-exists" ], "type": "string" }, @@ -15641,90 +24399,27 @@ } } }, - "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)" - } - }, - "summary": "Get existing roles available for the given conversation" - } - }, - "/conversations/{cnv}/self": { - "get": { - "deprecated": true, - "description": " [internal route ID: \"get-conversation-self-unqualified\"]\n\n", - "parameters": [ - { - "description": "Conversation ID", - "in": "path", - "name": "cnv", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Member" - } - } - }, - "description": "" - } - }, - "summary": "Get self membership properties (deprecated)" - }, - "put": { - "deprecated": true, - "description": " [internal route ID: \"update-conversation-self-unqualified\"]\n\nUse `/conversations/:domain/:conv/self` instead.", - "parameters": [ - { - "description": "Conversation ID", - "in": "path", - "name": "cnv", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/MemberUpdate" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Update successful" + "description": "For password reset, new and old password must be different. (label: `password-must-differ`)\n\nA password reset is already in progress. (label: `code-exists`)\n\nA password reset is already in progress. (label: `code-exists`)" }, - "404": { + "429": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "code": 429, + "label": "too-many-requests", + "message": "Too many request to generate a verification code." }, "properties": { "code": { "enum": [ - 404 + 429 ], "type": "integer" }, "label": { "enum": [ - "no-conversation" + "too-many-requests" ], "type": "string" }, @@ -15741,54 +24436,21 @@ } } }, - "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)" - } - }, - "summary": "Update self membership properties (deprecated)" - } - }, - "/cookies": { - "get": { - "description": " [internal route ID: \"list-cookies\"]\n\n", - "parameters": [ - { - "description": "Filter by label (comma-separated list)", - "in": "query", - "name": "labels", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CookieList" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/CookieList" - } - } - }, - "description": "List of cookies" + "description": "Too many request to generate a verification code. (label: `too-many-requests`)" } }, - "summary": "Retrieve the list of cookies currently stored for the user" + "summary": "Begin a password reset" } }, - "/cookies/remove": { + "/provider/password-reset/complete": { "post": { - "description": " [internal route ID: \"remove-cookies\"]\n\n", + "description": " [internal route ID: \"provider-password-reset-complete\"]\n\n", + "operationId": "provider-password-reset-complete", "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/RemoveCookies" + "$ref": "#/components/schemas/CompletePasswordReset_LTYzMDAxNDA1" } } }, @@ -15796,7 +24458,44 @@ }, "responses": { "200": { - "description": "Cookies revoked" + "description": "" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-code", + "message": "Invalid password reset code." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid password reset code. (label: `invalid-code`)" }, "403": { "content": { @@ -15816,7 +24515,9 @@ }, "label": { "enum": [ - "invalid-credentials" + "invalid-credentials", + "invalid-code", + "access-denied" ], "type": "string" }, @@ -15833,56 +24534,27 @@ } } }, - "description": "Authentication failed (label: `invalid-credentials`)" - } - }, - "summary": "Revoke stored cookies" - } - }, - "/custom-backend/by-domain/{domain}": { - "get": { - "description": " [internal route ID: \"get-custom-backend-by-domain\"]\n\n", - "parameters": [ - { - "description": "URL-encoded email domain", - "in": "path", - "name": "domain", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/CustomBackend" - } - } - }, - "description": "" + "description": "Authentication failed (label: `invalid-credentials`)\n\nInvalid verification code (label: `invalid-code`)\n\nAccess denied. (label: `access-denied`)" }, - "404": { + "409": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "custom-backend-not-found", - "message": "Custom backend not found" + "code": 409, + "label": "password-must-differ", + "message": "For password reset, new and old password must be different." }, "properties": { "code": { "enum": [ - 404 + 409 ], "type": "integer" }, "label": { "enum": [ - "custom-backend-not-found" + "password-must-differ" ], "type": "string" }, @@ -15899,48 +24571,71 @@ } } }, - "description": "`domain` not found\n\nCustom backend not found (label: `custom-backend-not-found`)" + "description": "For password reset, new and old password must be different. (label: `password-must-differ`)" } }, - "summary": "Shows information about custom backends related to a given email domain" + "summary": "Complete a password reset" } }, - "/delete": { + "/provider/register": { "post": { - "description": " [internal route ID: \"verify-delete\"]\n\nCalls federation service brig on send-connection-action", + "description": " [internal route ID: \"provider-register\"]\n\n", + "operationId": "provider-register", + "parameters": [ + { + "in": "header", + "name": "X-Forwarded-For", + "required": true, + "schema": { + "type": "string" + } + } + ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/VerifyDeleteUser" + "$ref": "#/components/schemas/NewProvider_LTEyMTY5MjYy" } } }, "required": true }, "responses": { - "200": { - "description": "Deletion is initiated." + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewProviderResponse_OTE0ODI2NjU0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewProviderResponse_OTE0ODI2NjU0" + } + } + }, + "description": "" }, - "403": { + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "invalid-code", - "message": "Invalid verification code" + "code": 400, + "label": "invalid-email", + "message": "Invalid e-mail address." }, "properties": { "code": { "enum": [ - 403 + 400 ], "type": "integer" }, "label": { "enum": [ - "invalid-code" + "invalid-email" ], "type": "string" }, @@ -15957,25 +24652,7 @@ } } }, - "description": "Invalid verification code (label: `invalid-code`)" - } - }, - "summary": "Verify account deletion with a code." - } - }, - "/feature-configs": { - "get": { - "description": " [internal route ID: \"get-all-feature-configs-for-user\"]\n\nGets feature configs for a user. If the user is a member of a team and has the required permissions, this will return the team's feature configs.If the user is not a member of a team, this will return the personal feature configs (the server defaults).\nOAuth scope: `read:feature_configs`", - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/AllTeamFeatures" - } - } - }, - "description": "" + "description": "Invalid `body` or `X-Forwarded-For`\n\nInvalid e-mail address. (label: `invalid-email`)" }, "403": { "content": { @@ -15983,8 +24660,8 @@ "schema": { "example": { "code": 403, - "label": "operation-denied", - "message": "Insufficient permissions" + "label": "access-denied", + "message": "Access denied." }, "properties": { "code": { @@ -15995,8 +24672,7 @@ }, "label": { "enum": [ - "operation-denied", - "no-team-member" + "access-denied" ], "type": "string" }, @@ -16013,27 +24689,27 @@ } } }, - "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" + "description": "Access denied. (label: `access-denied`)" }, - "404": { + "429": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-team", - "message": "Team not found" + "code": 429, + "label": "too-many-requests", + "message": "Too many request to generate a verification code." }, "properties": { "code": { "enum": [ - 404 + 429 ], "type": "integer" }, "label": { "enum": [ - "no-team" + "too-many-requests" ], "type": "string" }, @@ -16050,72 +24726,78 @@ } } }, - "description": "Team not found (label: `no-team`)" + "description": "Too many request to generate a verification code. (label: `too-many-requests`)" } }, - "summary": "Gets feature configs for a user" + "summary": "Register a new provider" } }, - "/identity-providers": { + "/provider/services": { "get": { + "description": " [internal route ID: \"get-provider-services\"]\n\n", + "operationId": "get-provider-services", "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/IdPList" + "items": { + "$ref": "#/components/schemas/Service_MjcyOTA5NjQx" + }, + "type": "array" } } }, "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" } - } + }, + "summary": "List provider services" }, "post": { - "parameters": [ - { - "in": "query", - "name": "replaces", - "required": false, - "schema": { - "format": "uuid", - "type": "string" - } - }, - { - "in": "query", - "name": "api_version", - "required": false, - "schema": { - "default": "v2", - "enum": [ - "v1", - "v2" - ], - "type": "string" - } - }, - { - "in": "query", - "name": "handle", - "required": false, - "schema": { - "maxLength": 1, - "minLength": 32, - "type": "string" - } - } - ], + "description": " [internal route ID: \"post-provider-services\"]\n\n", + "operationId": "post-provider-services", "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/IdPMetadataInfo" - } - }, - "application/xml": { - "schema": { - "$ref": "#/components/schemas/IdPMetadataInfo" + "$ref": "#/components/schemas/NewService_LTYwOTU1MDQ3" } } }, @@ -16124,126 +24806,105 @@ "responses": { "201": { "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewServiceResponse_LTExMzcwMjg5" + } + }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/IdPConfig_WireIdP" + "$ref": "#/components/schemas/NewServiceResponse_LTExMzcwMjg5" } } }, "description": "" - } - } - } - }, - "/identity-providers/{id}": { - "delete": { - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } }, - { - "in": "query", - "name": "purge", - "required": false, - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "204": { - "description": "" - } - } - }, - "get": { - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { + "400": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/IdPConfig_WireIdP" + "example": { + "code": 400, + "label": "invalid-service-key", + "message": "Invalid service key." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-service-key" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "" - } - } - }, - "put": { - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - }, - { - "in": "query", - "name": "handle", - "required": false, - "schema": { - "maxLength": 1, - "minLength": 32, - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/IdPMetadataInfo" - } - }, - "application/xml": { - "schema": { - "$ref": "#/components/schemas/IdPMetadataInfo" - } - } + "description": "Invalid `body`\n\nInvalid service key. (label: `invalid-service-key`)" }, - "required": true - }, - "responses": { - "200": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/IdPConfig_WireIdP" + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "" + "description": "Access denied. (label: `access-denied`)" } - } + }, + "summary": "Create a new service" } }, - "/identity-providers/{id}/raw": { - "get": { + "/provider/services/{service-id}": { + "delete": { + "description": " [internal route ID: \"delete-provider-services-by-service-id\"]\n\n", + "operationId": "delete-provider-services-by-service-id", "parameters": [ { "in": "path", - "name": "id", + "name": "service-id", "required": true, "schema": { "format": "uuid", @@ -16251,122 +24912,122 @@ } } ], - "responses": { - "200": { - "content": { - "application/xml": { - "schema": { - "type": "string" - } - } - }, - "description": "" - } - } - } - }, - "/list-connections": { - "post": { - "description": " [internal route ID: \"list-connections\"]\n\nThe IDs returned by this endpoint are paginated. To get the first page, make a call with the `paging_state` field set to `null` (or omitted). Whenever the `has_more` field of the response is set to `true`, more results are available, and they can be obtained by calling the endpoint again, but this time passing the value of `paging_state` returned by the previous call. One can continue in this fashion until all results are returned, which is indicated by `has_more` being `false`. Note that `paging_state` should be considered an opaque token. It should not be inspected, or stored, or reused across multiple unrelated invocations of the endpoint.", "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/GetPaginated_Connections" + "$ref": "#/components/schemas/DeleteService_LTY2NzY5NzMz" } } }, "required": true }, "responses": { - "200": { + "202": { + "description": "" + }, + "403": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Connections_Page" + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "" - } - }, - "summary": "List the connections to other users, including remote users" - } - }, - "/list-users": { - "post": { - "description": " [internal route ID: \"list-users-by-ids-or-handles\"]\n\nThe 'qualified_ids' and 'qualified_handles' parameters are mutually exclusive.Calls federation service brig on get-users-by-ids", - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ListUsersQuery" - } - } + "description": "Authentication failed (label: `invalid-credentials`)\n\nAccess denied. (label: `access-denied`)" }, - "required": true - }, - "responses": { - "200": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ListUsersById" + "example": { + "code": 404, + "label": "not-found", + "message": "Service not found." + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "" + "description": "`service-id` not found\n\nService not found. (label: `not-found`)" } }, - "summary": "List users" - } - }, - "/login": { - "post": { - "description": " [internal route ID: \"login\"]\n\nLogins are throttled at the server's discretionCalls federation service brig on send-connection-action", + "summary": "Delete service" + }, + "get": { + "description": " [internal route ID: \"get-provider-services-by-service-id\"]\n\n", + "operationId": "get-provider-services-by-service-id", "parameters": [ { - "description": "Request a persistent cookie instead of a session cookie", - "in": "query", - "name": "persist", - "required": false, - "schema": { - "type": "boolean" - } - } - ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Login" - } + "in": "path", + "name": "service-id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" } - }, - "required": true - }, + } + ], "responses": { "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccessToken" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/AccessToken" + "$ref": "#/components/schemas/Service_MjcyOTA5NjQx" } } }, - "description": "OK", - "headers": { - "Set-Cookie": { - "schema": { - "type": "string" - } - } - } + "description": "" }, "403": { "content": { @@ -16374,8 +25035,8 @@ "schema": { "example": { "code": 403, - "label": "code-authentication-required", - "message": "Code authentication is required" + "label": "access-denied", + "message": "Access denied." }, "properties": { "code": { @@ -16386,11 +25047,7 @@ }, "label": { "enum": [ - "code-authentication-required", - "code-authentication-failed", - "pending-activation", - "suspended", - "invalid-credentials" + "access-denied" ], "type": "string" }, @@ -16407,67 +25064,27 @@ } } }, - "description": "Code authentication is required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nAccount pending activation (label: `pending-activation`)\n\nAccount suspended (label: `suspended`)\n\nAuthentication failed (label: `invalid-credentials`)" - } - }, - "summary": "Authenticate a user to obtain a cookie and first access token" - } - }, - "/mls/commit-bundles": { - "post": { - "description": " [internal route ID: \"mls-commit-bundle\"]\n\n\n\n**Note**: this endpoint can execute proposals, and therefore return all possible errors associated with adding or removing members to a conversation, in addition to the ones listed below. See the documentation of [POST /conversations/{cnv}/members/v2](#/default/post_conversations__cnv__members_v2) and [POST /conversations/{cnv_domain}/{cnv}/members/{usr_domain}/{usr}](#/default/delete_conversations__cnv_domain___cnv__members__usr_domain___usr_) for more details on the possible error responses of each type of proposal.
Calls federation service brig on api-version
Calls federation service brig on get-users-by-ids
Calls federation service brig on get-mls-clients
Calls federation service galley on on-conversation-updated
Calls federation service galley on send-mls-commit-bundle
Calls federation service galley on mls-welcome
Calls federation service galley on on-mls-message-sent", - "requestBody": { - "content": { - "message/mls": { - "schema": { - "$ref": "#/components/schemas/CommitBundle" - } - } - }, - "required": true - }, - "responses": { - "201": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MLSMessageSendingStatus" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/MLSMessageSendingStatus" - } - } - }, - "description": "Commit accepted and forwarded" + "description": "Access denied. (label: `access-denied`)" }, - "400": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "mls-welcome-mismatch", - "message": "The list of targets of a welcome message does not match the list of new clients in a group" + "code": 404, + "label": "not-found", + "message": "Service not found." }, "properties": { "code": { "enum": [ - 400 + 404 ], "type": "integer" }, "label": { "enum": [ - "mls-welcome-mismatch", - "mls-self-removal-not-allowed", - "mls-protocol-error", - "mls-not-enabled", - "mls-invalid-leaf-node-index", - "mls-group-conversation-mismatch", - "mls-commit-missing-references", - "mls-client-sender-user-mismatch" + "not-found" ], "type": "string" }, @@ -16484,7 +25101,38 @@ } } }, - "description": "Invalid `body`\n\nThe list of targets of a welcome message does not match the list of new clients in a group (label: `mls-welcome-mismatch`)\n\nSelf removal from group is not allowed (label: `mls-self-removal-not-allowed`)\n\nMLS protocol error (label: `mls-protocol-error`)\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)\n\nA referenced leaf node index points to a blank or non-existing node (label: `mls-invalid-leaf-node-index`)\n\nConversation ID resolved from Group ID does not match submitted Conversation ID (label: `mls-group-conversation-mismatch`)\n\nThe commit is not referencing all pending proposals (label: `mls-commit-missing-references`)\n\nUser ID resolved from Client ID does not match message's sender user ID (label: `mls-client-sender-user-mismatch`)" + "description": "`service-id` not found\n\nService not found. (label: `not-found`)" + } + }, + "summary": "Get provider service by service id" + }, + "put": { + "description": " [internal route ID: \"put-provider-services-by-service-id\"]\n\n", + "operationId": "put-provider-services-by-service-id", + "parameters": [ + { + "in": "path", + "name": "service-id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UpdateService_MjAxNzQ2Njkz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Provider service updated" }, "403": { "content": { @@ -16492,8 +25140,8 @@ "schema": { "example": { "code": 403, - "label": "mls-subconv-join-parent-missing", - "message": "MLS client cannot join the subconversation because it is not member of the parent conversation" + "label": "access-denied", + "message": "Access denied." }, "properties": { "code": { @@ -16504,9 +25152,6 @@ }, "label": { "enum": [ - "mls-subconv-join-parent-missing", - "missing-legalhold-consent", - "legalhold-not-enabled", "access-denied" ], "type": "string" @@ -16524,7 +25169,7 @@ } } }, - "description": "MLS client cannot join the subconversation because it is not member of the parent conversation (label: `mls-subconv-join-parent-missing`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nlegal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nConversation access denied (label: `access-denied`)" + "description": "Access denied. (label: `access-denied`)" }, "404": { "content": { @@ -16532,8 +25177,8 @@ "schema": { "example": { "code": 404, - "label": "mls-proposal-not-found", - "message": "A proposal referenced in a commit message could not be found" + "label": "not-found", + "message": "Provider not found." }, "properties": { "code": { @@ -16544,9 +25189,7 @@ }, "label": { "enum": [ - "mls-proposal-not-found", - "no-conversation", - "no-conversation-member" + "not-found" ], "type": "string" }, @@ -16563,49 +25206,98 @@ } } }, - "description": "A proposal referenced in a commit message could not be found (label: `mls-proposal-not-found`)\n\nConversation not found (label: `no-conversation`)\n\nConversation member not found (label: `no-conversation-member`)" + "description": "`service-id` not found\n\nProvider not found. (label: `not-found`)\n\nService not found. (label: `not-found`)" + } + }, + "summary": "Update provider service" + } + }, + "/provider/services/{service-id}/connection": { + "put": { + "description": " [internal route ID: \"put-provider-services-connection-by-service-id\"]\n\n", + "operationId": "put-provider-services-connection-by-service-id", + "parameters": [ + { + "in": "path", + "name": "service-id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UpdateServiceConn_LTQ1OTYwNjIz" + } + } }, - "409": { + "required": true + }, + "responses": { + "200": { + "description": "Provider service connection updated" + }, + "400": { "content": { "application/json;charset=utf-8": { "schema": { + "example": { + "code": 400, + "label": "invalid-service-key", + "message": "Invalid service key." + }, "properties": { - "non_federating_backends": { - "items": { - "$ref": "#/components/schemas/Domain" - }, - "type": "array" + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-service-key" + ], + "type": "string" + }, + "message": { + "type": "string" } }, "required": [ - "non_federating_backends" + "code", + "label", + "message" ], "type": "object" } } }, - "description": "Adding members to the conversation is not possible because the backends involved do not form a fully connected graph\n\nThe conversation epoch in a message is too old (label: `mls-stale-message`)\n\nA proposal of type Add or Remove does not apply to the full list of clients for a user (label: `mls-client-mismatch`)" + "description": "Invalid `body`\n\nInvalid service key. (label: `invalid-service-key`)" }, - "422": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 422, - "label": "mls-unsupported-proposal", - "message": "Unsupported proposal type" + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" }, "properties": { "code": { "enum": [ - 422 + 403 ], "type": "integer" }, "label": { "enum": [ - "mls-unsupported-proposal", - "mls-unsupported-message" + "invalid-credentials", + "access-denied" ], "type": "string" }, @@ -16622,63 +25314,62 @@ } } }, - "description": "Unsupported proposal type (label: `mls-unsupported-proposal`)\n\nAttempted to send a message with an unsupported combination of content type and wire format (label: `mls-unsupported-message`)" + "description": "Authentication failed (label: `invalid-credentials`)\n\nAccess denied. (label: `access-denied`)" }, - "533": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Service not found." + }, "properties": { - "unreachable_backends": { - "items": { - "$ref": "#/components/schemas/Domain" - }, - "type": "array" + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" } }, "required": [ - "unreachable_backends" + "code", + "label", + "message" ], "type": "object" } } }, - "description": "Some domains are unreachable" + "description": "`service-id` not found\n\nService not found. (label: `not-found`)" } }, - "summary": "Post a MLS CommitBundle" + "summary": "Update provider service connection" } }, - "/mls/key-packages/claim/{user_domain}/{user}": { - "post": { - "description": " [internal route ID: \"mls-key-packages-claim\"]\n\nOnly key packages for the specified ciphersuite are claimed. For backwards compatibility, the `ciphersuite` parameter is optional, defaulting to ciphersuite 0x0001 when omitted.", + "/providers/{pid}": { + "get": { + "description": " [internal route ID: \"provider-get-profile\"]\n\n", + "operationId": "provider-get-profile", "parameters": [ { "in": "path", - "name": "user_domain", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "User Id", - "in": "path", - "name": "user", + "name": "pid", "required": true, "schema": { "format": "uuid", "type": "string" } - }, - { - "description": "Ciphersuite in hex format (e.g. 0xf031) - default is 0x0001", - "in": "query", - "name": "ciphersuite", - "required": false, - "schema": { - "type": "number" - } } ], "responses": { @@ -16686,107 +25377,68 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/KeyPackageBundle" + "$ref": "#/components/schemas/Provider_NDIyMzQ3ODIy" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/KeyPackageBundle" + "$ref": "#/components/schemas/Provider_NDIyMzQ3ODIy" } } }, - "description": "Claimed key packages" - } - }, - "summary": "Claim one key package for each client of the given user" - } - }, - "/mls/key-packages/self/{client}": { - "delete": { - "description": " [internal route ID: \"mls-key-packages-delete\"]\n\n", - "parameters": [ - { - "description": "ClientId", - "in": "path", - "name": "client", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "Ciphersuite in hex format (e.g. 0xf031) - default is 0x0001", - "in": "query", - "name": "ciphersuite", - "required": false, - "schema": { - "type": "number" - } - } - ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/DeleteKeyPackages" - } - } - }, - "required": true - }, - "responses": { - "201": { - "description": "OK" - } - }, - "summary": "Delete all key packages for a given ciphersuite and client" - }, - "post": { - "description": " [internal route ID: \"mls-key-packages-upload\"]\n\nThe request body should be a json object containing a list of base64-encoded key packages.", - "parameters": [ - { - "description": "ClientId", - "in": "path", - "name": "client", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/KeyPackageUpload" - } - } - }, - "required": true - }, - "responses": { - "201": { - "description": "Key packages uploaded" + "description": "" }, - "400": { + "404": { "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Provider not found." + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "mls-protocol-error", - "message": "MLS protocol error" + "code": 404, + "label": "not-found", + "message": "Provider not found." }, "properties": { "code": { "enum": [ - 400 + 404 ], "type": "integer" }, "label": { "enum": [ - "mls-protocol-error" + "not-found" ], "type": "string" }, @@ -16803,7 +25455,40 @@ } } }, - "description": "Invalid `body`\n\nMLS protocol error (label: `mls-protocol-error`)" + "description": "`pid` or Provider not found. (label: `not-found`)" + } + }, + "summary": "Get profile" + } + }, + "/providers/{provider-id}/services": { + "get": { + "description": " [internal route ID: \"get-provider-services-by-provider-id\"]\n\n", + "operationId": "get-provider-services-by-provider-id", + "parameters": [ + { + "in": "path", + "name": "provider-id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/ServiceProfile_LTc2MDQzNTk3" + }, + "type": "array" + } + } + }, + "description": "" }, "403": { "content": { @@ -16811,8 +25496,8 @@ "schema": { "example": { "code": 403, - "label": "mls-identity-mismatch", - "message": "Key package credential does not match qualified client ID" + "label": "access-denied", + "message": "Access denied." }, "properties": { "code": { @@ -16823,7 +25508,7 @@ }, "label": { "enum": [ - "mls-identity-mismatch" + "access-denied" ], "type": "string" }, @@ -16840,66 +25525,66 @@ } } }, - "description": "Key package credential does not match qualified client ID (label: `mls-identity-mismatch`)" + "description": "Access denied. (label: `access-denied`)" } }, - "summary": "Upload a fresh batch of key packages" - }, - "put": { - "description": " [internal route ID: \"mls-key-packages-replace\"]\n\nThe request body should be a json object containing a list of base64-encoded key packages. Use this sparingly.", + "summary": "Get provider services by provider id" + } + }, + "/providers/{provider-id}/services/{service-id}": { + "get": { + "description": " [internal route ID: \"get-provider-services-by-provider-id-and-service-id\"]\n\n", + "operationId": "get-provider-services-by-provider-id-and-service-id", "parameters": [ { - "description": "ClientId", "in": "path", - "name": "client", + "name": "provider-id", "required": true, "schema": { + "format": "uuid", "type": "string" } }, { - "description": "Comma-separated list of ciphersuites in hex format (e.g. 0xf031) - default is 0x0001", - "in": "query", - "name": "ciphersuites", - "required": false, + "in": "path", + "name": "service-id", + "required": true, "schema": { + "format": "uuid", "type": "string" } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/KeyPackageUpload" - } - } - }, - "required": true - }, "responses": { - "201": { - "description": "Key packages replaced" + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ServiceProfile_LTc2MDQzNTk3" + } + } + }, + "description": "" }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "mls-protocol-error", - "message": "MLS protocol error" + "code": 403, + "label": "access-denied", + "message": "Access denied." }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "mls-protocol-error" + "access-denied" ], "type": "string" }, @@ -16916,27 +25601,27 @@ } } }, - "description": "Invalid `body` or `ciphersuites`\n\nMLS protocol error (label: `mls-protocol-error`)" + "description": "Access denied. (label: `access-denied`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "mls-identity-mismatch", - "message": "Key package credential does not match qualified client ID" + "code": 404, + "label": "not-found", + "message": "Service not found." }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "mls-identity-mismatch" + "not-found" ], "type": "string" }, @@ -16953,63 +25638,45 @@ } } }, - "description": "Key package credential does not match qualified client ID (label: `mls-identity-mismatch`)" - } - }, - "summary": "Upload a fresh batch of key packages and replace the old ones" - } - }, - "/mls/key-packages/self/{client}/count": { - "get": { - "description": " [internal route ID: \"mls-key-packages-count\"]\n\n", - "parameters": [ - { - "description": "ClientId", - "in": "path", - "name": "client", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "Ciphersuite in hex format (e.g. 0xf031) - default is 0x0001", - "in": "query", - "name": "ciphersuite", - "required": false, - "schema": { - "type": "number" - } + "description": "`provider-id` or `service-id` not found\n\nService not found. (label: `not-found`)" } - ], + }, + "summary": "Get provider service by provider id and service id" + } + }, + "/proxy/giphy/v1/gifs": {}, + "/proxy/googlemaps/api/staticmap": {}, + "/proxy/googlemaps/maps/api/geocode": {}, + "/proxy/soundcloud/resolve": {}, + "/proxy/soundcloud/stream": {}, + "/proxy/spotify/api/token": {}, + "/proxy/youtube/v3": {}, + "/push/tokens": { + "get": { + "description": " [internal route ID: \"get-push-tokens\"]\n\n", + "operationId": "get-push-tokens", "responses": { "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/OwnKeyPackages" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/OwnKeyPackages" + "$ref": "#/components/schemas/PushTokenList_NDI0Mjc3MzY3" } } }, - "description": "Number of key packages" + "description": "" } }, - "summary": "Return the number of unclaimed key packages for a given ciphersuite and client" - } - }, - "/mls/messages": { + "summary": "List the user's registered push tokens" + }, "post": { - "description": " [internal route ID: \"mls-message\"]\n\n\n\n**Note**: this endpoint can execute proposals, and therefore return all possible errors associated with adding or removing members to a conversation, in addition to the ones listed below. See the documentation of [POST /conversations/{cnv}/members/v2](#/default/post_conversations__cnv__members_v2) and [POST /conversations/{cnv_domain}/{cnv}/members/{usr_domain}/{usr}](#/default/delete_conversations__cnv_domain___cnv__members__usr_domain___usr_) for more details on the possible error responses of each type of proposal.
Calls federation service brig on get-mls-clients
Calls federation service galley on on-conversation-updated
Calls federation service galley on send-mls-message
Calls federation service galley on on-mls-message-sent", + "description": " [internal route ID: \"register-push-token\"]\n\n", + "operationId": "register-push-token", "requestBody": { "content": { - "message/mls": { + "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/MLSMessage" + "$ref": "#/components/schemas/PushToken_ODYzMDYzOTA4" } } }, @@ -17020,25 +25687,32 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/MLSMessageSendingStatus" + "$ref": "#/components/schemas/PushToken_ODYzMDYzOTA4" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/MLSMessageSendingStatus" + "$ref": "#/components/schemas/PushToken_ODYzMDYzOTA4" } } }, - "description": "Message sent" + "description": "Push token registered", + "headers": { + "Location": { + "schema": { + "type": "string" + } + } + } }, "400": { "content": { - "application/json;charset=utf-8": { + "application/json": { "schema": { "example": { "code": 400, - "label": "mls-self-removal-not-allowed", - "message": "Self removal from group is not allowed" + "label": "apns-voip-not-supported", + "message": "Adding APNS_VOIP tokens is not supported" }, "properties": { "code": { @@ -17049,13 +25723,7 @@ }, "label": { "enum": [ - "mls-self-removal-not-allowed", - "mls-protocol-error", - "mls-not-enabled", - "mls-invalid-leaf-node-index", - "mls-group-conversation-mismatch", - "mls-commit-missing-references", - "mls-client-sender-user-mismatch" + "apns-voip-not-supported" ], "type": "string" }, @@ -17070,32 +25738,24 @@ ], "type": "object" } - } - }, - "description": "Invalid `body`\n\nSelf removal from group is not allowed (label: `mls-self-removal-not-allowed`)\n\nMLS protocol error (label: `mls-protocol-error`)\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)\n\nA referenced leaf node index points to a blank or non-existing node (label: `mls-invalid-leaf-node-index`)\n\nConversation ID resolved from Group ID does not match submitted Conversation ID (label: `mls-group-conversation-mismatch`)\n\nThe commit is not referencing all pending proposals (label: `mls-commit-missing-references`)\n\nUser ID resolved from Client ID does not match message's sender user ID (label: `mls-client-sender-user-mismatch`)" - }, - "403": { - "content": { + }, "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "mls-subconv-join-parent-missing", - "message": "MLS client cannot join the subconversation because it is not member of the parent conversation" + "code": 400, + "label": "apns-voip-not-supported", + "message": "Adding APNS_VOIP tokens is not supported" }, "properties": { "code": { "enum": [ - 403 + 400 ], "type": "integer" }, "label": { "enum": [ - "mls-subconv-join-parent-missing", - "missing-legalhold-consent", - "legalhold-not-enabled", - "access-denied" + "apns-voip-not-supported" ], "type": "string" }, @@ -17112,16 +25772,16 @@ } } }, - "description": "MLS client cannot join the subconversation because it is not member of the parent conversation (label: `mls-subconv-join-parent-missing`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nlegal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nConversation access denied (label: `access-denied`)" + "description": "Adding APNS_VOIP tokens is not supported (label: `apns-voip-not-supported`) or `body`" }, "404": { "content": { - "application/json;charset=utf-8": { + "application/json": { "schema": { "example": { "code": 404, - "label": "mls-proposal-not-found", - "message": "A proposal referenced in a commit message could not be found" + "label": "app-not-found", + "message": "App does not exist" }, "properties": { "code": { @@ -17132,9 +25792,8 @@ }, "label": { "enum": [ - "mls-proposal-not-found", - "no-conversation", - "no-conversation-member" + "app-not-found", + "invalid-token" ], "type": "string" }, @@ -17149,51 +25808,25 @@ ], "type": "object" } - } - }, - "description": "A proposal referenced in a commit message could not be found (label: `mls-proposal-not-found`)\n\nConversation not found (label: `no-conversation`)\n\nConversation member not found (label: `no-conversation-member`)" - }, - "409": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "properties": { - "non_federating_backends": { - "items": { - "$ref": "#/components/schemas/Domain" - }, - "type": "array" - } - }, - "required": [ - "non_federating_backends" - ], - "type": "object" - } - } - }, - "description": "Adding members to the conversation is not possible because the backends involved do not form a fully connected graph\n\nThe conversation epoch in a message is too old (label: `mls-stale-message`)\n\nA proposal of type Add or Remove does not apply to the full list of clients for a user (label: `mls-client-mismatch`)" - }, - "422": { - "content": { + }, "application/json;charset=utf-8": { "schema": { "example": { - "code": 422, - "label": "mls-unsupported-proposal", - "message": "Unsupported proposal type" + "code": 404, + "label": "app-not-found", + "message": "App does not exist" }, "properties": { "code": { "enum": [ - 422 + 404 ], "type": "integer" }, "label": { "enum": [ - "mls-unsupported-proposal", - "mls-unsupported-message" + "app-not-found", + "invalid-token" ], "type": "string" }, @@ -17210,85 +25843,63 @@ } } }, - "description": "Unsupported proposal type (label: `mls-unsupported-proposal`)\n\nAttempted to send a message with an unsupported combination of content type and wire format (label: `mls-unsupported-message`)" + "description": "App does not exist (label: `app-not-found`)\n\nInvalid push token (label: `invalid-token`)" }, - "533": { + "413": { "content": { - "application/json;charset=utf-8": { + "application/json": { "schema": { + "example": { + "code": 413, + "label": "sns-thread-budget-reached", + "message": "Too many concurrent calls to SNS; is SNS down?" + }, "properties": { - "unreachable_backends": { - "items": { - "$ref": "#/components/schemas/Domain" - }, - "type": "array" + "code": { + "enum": [ + 413 + ], + "type": "integer" + }, + "label": { + "enum": [ + "sns-thread-budget-reached", + "token-too-long", + "metadata-too-long" + ], + "type": "string" + }, + "message": { + "type": "string" } }, "required": [ - "unreachable_backends" + "code", + "label", + "message" ], "type": "object" } - } - }, - "description": "Some domains are unreachable" - } - }, - "summary": "Post an MLS message" - } - }, - "/mls/public-keys": { - "get": { - "description": " [internal route ID: \"mls-public-keys\"]\n\nThe format of the returned key is determined by the `format` query parameter:\n - raw (default): base64-encoded raw public keys\n - jwk: keys are nested objects in JWK format.", - "parameters": [ - { - "in": "query", - "name": "format", - "required": false, - "schema": { - "enum": [ - "raw", - "jwk" - ], - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MLSKeysByPurpose" - } }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/MLSKeysByPurpose" - } - } - }, - "description": "Public keys" - }, - "400": { - "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "mls-not-enabled", - "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" + "code": 413, + "label": "sns-thread-budget-reached", + "message": "Too many concurrent calls to SNS; is SNS down?" }, "properties": { "code": { "enum": [ - 400 + 413 ], "type": "integer" }, "label": { "enum": [ - "mls-not-enabled" + "sns-thread-budget-reached", + "token-too-long", + "metadata-too-long" ], "type": "string" }, @@ -17305,63 +25916,30 @@ } } }, - "description": "Invalid `format`\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" + "description": "Too many concurrent calls to SNS; is SNS down? (label: `sns-thread-budget-reached`)\n\nPush token length must be < 8192 for GCM or 400 for APNS (label: `token-too-long`)\n\nTried to add token to endpoint resulting in metadata length > 2048 (label: `metadata-too-long`)" } }, - "summary": "Get public keys used by the backend to sign external proposals" + "summary": "Register a native push token" } }, - "/notifications": { - "get": { - "description": " [internal route ID: \"get-notifications\"]\n\n", + "/push/tokens/{pid}": { + "delete": { + "description": " [internal route ID: \"delete-push-token\"]\n\n", + "operationId": "delete-push-token", "parameters": [ { - "description": "Only return notifications more recent than this", - "in": "query", - "name": "since", - "required": false, - "schema": { - "format": "uuid", - "type": "string" - } - }, - { - "description": "Only return notifications targeted at the given client", - "in": "query", - "name": "client", - "required": false, + "description": "The push token to delete", + "in": "path", + "name": "pid", + "required": true, "schema": { "type": "string" } - }, - { - "description": "Maximum number of notifications to return", - "in": "query", - "name": "size", - "required": false, - "schema": { - "format": "int32", - "maximum": 10000, - "minimum": 100, - "type": "integer" - } } ], "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueuedNotificationList" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/QueuedNotificationList" - } - } - }, - "description": "Notification list" + "204": { + "description": "Push token unregistered" }, "404": { "content": { @@ -17370,7 +25948,7 @@ "example": { "code": 404, "label": "not-found", - "message": "Some notifications not found" + "message": "Push token not found" }, "properties": { "code": { @@ -17402,7 +25980,7 @@ "example": { "code": 404, "label": "not-found", - "message": "Some notifications not found" + "message": "Push token not found" }, "properties": { "code": { @@ -17430,61 +26008,88 @@ } } }, - "description": "Some notifications not found (label: `not-found`)" + "description": "`pid` or Push token not found (label: `not-found`)" } }, - "summary": "Fetch notifications" + "summary": "Unregister a native push token" } }, - "/notifications/last": { - "get": { - "description": " [internal route ID: \"get-last-notification\"]\n\n", + "/register": { + "post": { + "description": " [internal route ID: \"register@v16\"]\n\nIf the environment where the registration takes place is private and a registered email address is not whitelisted, a 403 error is returned.", + "operationId": "register@v16", "parameters": [ { - "description": "Only return notifications targeted at the given client", - "in": "query", - "name": "client", - "required": false, + "in": "header", + "name": "X-Forwarded-For", + "required": true, "schema": { "type": "string" } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewUser_PlainTextPassword_8_LTI4MzI5NzQx" + } + } + }, + "required": true + }, "responses": { - "200": { + "201": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/QueuedNotification" + "$ref": "#/components/schemas/User_NjA4OTQwMTQ4" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/QueuedNotification" + "$ref": "#/components/schemas/User_NjA4OTQwMTQ4" } } }, - "description": "Notification found" + "description": "User created and pending activation", + "headers": { + "Location": { + "description": "UserId", + "schema": { + "format": "uuid", + "type": "string" + } + }, + "Set-Cookie": { + "description": "Cookie", + "schema": { + "type": "string" + } + } + } }, - "404": { + "400": { "content": { "application/json": { "schema": { "example": { - "code": 404, - "label": "not-found", - "message": "Some notifications not found" + "code": 400, + "label": "invalid-invitation-code", + "message": "Invalid invitation code." }, "properties": { "code": { "enum": [ - 404 + 400 ], "type": "integer" }, "label": { "enum": [ - "not-found" + "invalid-invitation-code", + "invalid-email", + "invalid-phone" ], "type": "string" }, @@ -17503,20 +26108,22 @@ "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "not-found", - "message": "Some notifications not found" + "code": 400, + "label": "invalid-invitation-code", + "message": "Invalid invitation code." }, "properties": { "code": { "enum": [ - 404 + 400 ], "type": "integer" }, "label": { "enum": [ - "not-found" + "invalid-invitation-code", + "invalid-email", + "invalid-phone" ], "type": "string" }, @@ -17533,51 +26140,88 @@ } } }, - "description": "Some notifications not found (label: `not-found`)" - } - }, - "summary": "Fetch the last notification" - } - }, - "/notifications/{id}": { - "get": { - "description": " [internal route ID: \"get-notification-by-id\"]\n\n", - "parameters": [ - { - "description": "Notification ID", - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } + "description": "Invalid invitation code. (label: `invalid-invitation-code`)\n\nInvalid e-mail address. (label: `invalid-email`)\n\nInvalid mobile phone number (label: `invalid-phone`) or `body` or `X-Forwarded-For`" }, - { - "description": "Only return notifications targeted at the given client", - "in": "query", - "name": "client", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { + "403": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/QueuedNotification" + "example": { + "code": 403, + "label": "unauthorized", + "message": "Unauthorized e-mail address" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unauthorized", + "missing-identity", + "blacklisted-email", + "too-many-team-members", + "user-creation-restricted", + "ephemeral-user-creation-disabled", + "managed-by-scim" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/QueuedNotification" + "example": { + "code": 403, + "label": "unauthorized", + "message": "Unauthorized e-mail address" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unauthorized", + "missing-identity", + "blacklisted-email", + "too-many-team-members", + "user-creation-restricted", + "ephemeral-user-creation-disabled", + "managed-by-scim" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "Notification found" + "description": "Unauthorized e-mail address (label: `unauthorized`)\n\nUsing an invitation code requires registering the given email. (label: `missing-identity`)\n\nThe given e-mail address has been blacklisted due to a permanent bounce or a complaint. (label: `blacklisted-email`)\n\nToo many members in this team. (label: `too-many-team-members`)\n\nThis instance does not allow creation of personal users or teams. (label: `user-creation-restricted`)\n\nEphemeral user creation is disabled on this instance. (label: `ephemeral-user-creation-disabled`)\n\nUpdating name is not allowed, because it is managed by SCIM, or E2EId is enabled (label: `managed-by-scim`)" }, "404": { "content": { @@ -17585,8 +26229,8 @@ "schema": { "example": { "code": 404, - "label": "not-found", - "message": "Some notifications not found" + "label": "invalid-code", + "message": "User does not exist" }, "properties": { "code": { @@ -17597,7 +26241,7 @@ }, "label": { "enum": [ - "not-found" + "invalid-code" ], "type": "string" }, @@ -17617,8 +26261,8 @@ "schema": { "example": { "code": 404, - "label": "not-found", - "message": "Some notifications not found" + "label": "invalid-code", + "message": "User does not exist" }, "properties": { "code": { @@ -17629,7 +26273,7 @@ }, "label": { "enum": [ - "not-found" + "invalid-code" ], "type": "string" }, @@ -17646,49 +26290,89 @@ } } }, - "description": "`id` or Some notifications not found (label: `not-found`)" - } - }, - "summary": "Fetch a notification by ID" - } - }, - "/oauth/applications": { - "get": { - "description": " [internal route ID: \"get-oauth-applications\"]\n\nGet all OAuth applications with active account access for a user.", - "responses": { - "200": { + "description": "User does not exist (label: `invalid-code`)\n\nInvalid activation code (label: `invalid-code`)" + }, + "409": { "content": { "application/json": { "schema": { - "items": { - "$ref": "#/components/schemas/OAuthApplication" + "example": { + "code": 409, + "label": "key-exists", + "message": "The given e-mail address is in use." }, - "type": "array" + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "key-exists" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } }, "application/json;charset=utf-8": { "schema": { - "items": { - "$ref": "#/components/schemas/OAuthApplication" + "example": { + "code": 409, + "label": "key-exists", + "message": "The given e-mail address is in use." }, - "type": "array" + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "key-exists" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "OAuth applications found" + "description": "The given e-mail address is in use. (label: `key-exists`)" } }, - "summary": "Get OAuth applications with account access" + "summary": "Register a new user." } }, - "/oauth/applications/{OAuthClientId}": { + "/scim/auth-tokens": { "delete": { - "description": " [internal route ID: \"revoke-oauth-account-access-v6\"]\n\n", + "description": " [internal route ID: \"auth-tokens-delete\"]\n\n", + "operationId": "auth-tokens-delete", "parameters": [ { - "description": "The ID of the OAuth client", - "in": "path", - "name": "OAuthClientId", + "in": "query", + "name": "id", "required": true, "schema": { "format": "uuid", @@ -17698,59 +26382,6 @@ ], "responses": { "204": { - "description": "OAuth application access revoked" - } - }, - "summary": "Revoke account access from an OAuth application" - } - }, - "/oauth/applications/{OAuthClientId}/sessions/{RefreshTokenId}": { - "delete": { - "description": " [internal route ID: \"delete-oauth-refresh-token\"]\n\nRevoke an active OAuth session by providing the refresh token ID.", - "parameters": [ - { - "description": "The ID of the OAuth client", - "in": "path", - "name": "OAuthClientId", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - }, - { - "description": "The ID of the refresh token", - "in": "path", - "name": "RefreshTokenId", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/PasswordReqBody" - } - } - }, - "required": true - }, - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": [], - "items": {}, - "maxItems": 0, - "type": "array" - } - } - }, "description": "" }, "403": { @@ -17759,8 +26390,8 @@ "schema": { "example": { "code": 403, - "label": "access-denied", - "message": "Access denied." + "label": "code-authentication-required", + "message": "Code authentication is required" }, "properties": { "code": { @@ -17771,7 +26402,8 @@ }, "label": { "enum": [ - "access-denied" + "code-authentication-required", + "code-authentication-failed" ], "type": "string" }, @@ -17788,27 +26420,44 @@ } } }, - "description": "Access denied. (label: `access-denied`)" + "description": "Code authentication is required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)" + } + } + }, + "get": { + "description": " [internal route ID: \"auth-tokens-list\"]\n\n", + "operationId": "auth-tokens-list", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ScimTokenList_NjQwNTYxOTAw" + } + } + }, + "description": "" }, - "404": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "not-found", - "message": "OAuth client not found" + "code": 403, + "label": "code-authentication-required", + "message": "Code authentication is required" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "not-found" + "code-authentication-required", + "code-authentication-failed" ], "type": "string" }, @@ -17825,55 +26474,54 @@ } } }, - "description": "`OAuthClientId` or `RefreshTokenId` not found\n\nOAuth client not found (label: `not-found`)" + "description": "Code authentication is required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)" } - }, - "summary": "Revoke an active OAuth session" - } - }, - "/oauth/authorization/codes": { + } + }, "post": { - "description": " [internal route ID: \"create-oauth-auth-code\"]\n\nCurrently only supports the 'code' response type, which corresponds to the authorization code flow.", + "description": " [internal route ID: \"auth-tokens-create\"]\n\n", + "operationId": "auth-tokens-create", "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/CreateOAuthAuthorizationCodeRequest" + "$ref": "#/components/schemas/CreateScimToken_OTY0NjYxMDQ2" } } }, "required": true }, "responses": { - "201": { - "description": "Created", - "headers": { - "Location": { + "200": { + "content": { + "application/json;charset=utf-8": { "schema": { - "type": "string" + "$ref": "#/components/schemas/CreateScimTokenResponse_LTIzOTU2NDU4" } } - } + }, + "description": "" }, - "400": { + "403": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "redirect-url-miss-match", - "message": "The redirect URL does not match the one registered with the client" + "code": 403, + "label": "code-authentication-required", + "message": "Code authentication is required" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "redirect-url-miss-match" + "code-authentication-required", + "code-authentication-failed" ], "type": "string" }, @@ -17888,24 +26536,72 @@ ], "type": "object" } - }, + } + }, + "description": "Code authentication is required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)" + } + } + } + }, + "/scim/auth-tokens/{id}": { + "put": { + "description": " [internal route ID: \"auth-tokens-put-name\"]\n\n", + "operationId": "auth-tokens-put-name", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ScimTokenName_LTgzOTM2OTI4" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + } + }, + "description": "" + }, + "403": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "redirect-url-miss-match", - "message": "The redirect URL does not match the one registered with the client" + "code": 403, + "label": "code-authentication-required", + "message": "Code authentication is required" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "redirect-url-miss-match" + "code-authentication-required", + "code-authentication-failed" ], "type": "string" }, @@ -17922,50 +26618,52 @@ } } }, - "description": "Bad Request\n\nThe redirect URL does not match the one registered with the client (label: `redirect-url-miss-match`) or `body`", - "headers": { - "Location": { - "schema": { - "type": "string" - } - } - } - }, - "403": { - "description": "Forbidden", - "headers": { - "Location": { - "schema": { - "type": "string" - } - } - } - }, - "404": { - "description": "Not Found", - "headers": { - "Location": { - "schema": { - "type": "string" - } - } - } + "description": "Code authentication is required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)" } - }, - "summary": "Create an OAuth authorization code" + } } }, - "/oauth/clients/{OAuthClientId}": { + "/search/contacts": { "get": { - "description": " [internal route ID: \"get-oauth-client\"]\n\n", + "description": " [internal route ID: \"search-contacts\"]\n\n", + "operationId": "search-contacts", "parameters": [ { - "description": "The ID of the OAuth client", - "in": "path", - "name": "OAuthClientId", + "description": "Search query

The search query is normalized: lower-cased and diacritics are removed ('Björn' becomes 'bjorn'). The normalized search query matches accounts that, in this order of priority:

  • are equal to the normalized full handle;
  • are equal to the normalized full user display name;
  • prefix-match the normalized handle;
  • prefix-match the normalized user display name.

NB: '@' Does NOT do anything special, ignoring user display names.

See also: [authoritative ElasticSearch query](https://github.com/wireapp/wire-server/blob/83c25cca6a5e9d2205c102410b452eb78fc50a00/libs/wire-subsystems/src/Wire/IndexedUserStore/ElasticSearch.hs#L251-L288)

", + "in": "query", + "name": "q", "required": true, "schema": { - "format": "uuid", + "type": "string" + } + }, + { + "description": "Searched domain. Note: This is optional only for backwards compatibility, future versions will mandate this.", + "in": "query", + "name": "domain", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Number of results to return (min: 1, max: 500, default 15)", + "in": "query", + "name": "size", + "required": false, + "schema": { + "format": "int32", + "maximum": 500, + "minimum": 1, + "type": "integer" + } + }, + { + "description": "Only user types. Omitted or empty (type=) means no filtering.", + "in": "query", + "name": "type", + "required": false, + "schema": { "type": "string" } } @@ -17973,18 +26671,13 @@ "responses": { "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/OAuthClient" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/OAuthClient" + "$ref": "#/components/schemas/SearchResult_Contact_OTExNzg4MTE0" } } }, - "description": "OAuth client found" + "description": "" }, "403": { "content": { @@ -17992,8 +26685,8 @@ "schema": { "example": { "code": 403, - "label": "forbidden", - "message": "OAuth is disabled" + "label": "insufficient-permissions", + "message": "Insufficient permissions" }, "properties": { "code": { @@ -18004,7 +26697,7 @@ }, "label": { "enum": [ - "forbidden" + "insufficient-permissions" ], "type": "string" }, @@ -18021,27 +26714,64 @@ } } }, - "description": "OAuth is disabled (label: `forbidden`)" + "description": "Insufficient permissions (label: `insufficient-permissions`)" + } + }, + "summary": "Search for users" + } + }, + "/self": { + "delete": { + "description": " [internal route ID: \"delete-self\"]\n\nif the account has a verified identity, a verification code is sent and needs to be confirmed to authorise the deletion. if the account has no verified identity but a password, it must be provided. if password is correct, or if neither a verified identity nor a password exists, account deletion is scheduled immediately.", + "operationId": "delete-self", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DeleteUser_NjE0MjE2Mjkz" + } + } }, - "404": { + "required": true + }, + "responses": { + "200": { + "description": "Deletion is initiated." + }, + "202": { "content": { "application/json": { + "schema": { + "$ref": "#/components/schemas/DeletionCodeTimeout_LTU1MTk0NDI3" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DeletionCodeTimeout_LTU1MTk0NDI3" + } + } + }, + "description": "Deletion is pending verification with a code." + }, + "400": { + "content": { + "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "not-found", - "message": "OAuth client not found" + "code": 400, + "label": "invalid-user", + "message": "Invalid user" }, "properties": { "code": { "enum": [ - 404 + 400 ], "type": "integer" }, "label": { "enum": [ - "not-found" + "invalid-user" ], "type": "string" }, @@ -18056,24 +26786,33 @@ ], "type": "object" } - }, + } + }, + "description": "Invalid `body`\n\nInvalid user (label: `invalid-user`)" + }, + "403": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "not-found", - "message": "OAuth client not found" + "code": 403, + "label": "no-self-delete-for-team-owner", + "message": "Team owners are not allowed to delete themselves; ask a fellow owner" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "not-found" + "no-self-delete-for-team-owner", + "pending-delete", + "missing-auth", + "invalid-credentials", + "invalid-code" ], "type": "string" }, @@ -18090,20 +26829,36 @@ } } }, - "description": "`OAuthClientId` or OAuth client not found (label: `not-found`)\n\nOAuth client not found (label: `not-found`)" + "description": "Team owners are not allowed to delete themselves; ask a fellow owner (label: `no-self-delete-for-team-owner`)\n\nA verification code for account deletion is still pending (label: `pending-delete`)\n\nRe-authentication via password required (label: `missing-auth`)\n\nAuthentication failed (label: `invalid-credentials`)\n\nInvalid verification code (label: `invalid-code`)" } }, - "summary": "Get OAuth client information" - } - }, - "/oauth/revoke": { - "post": { - "description": " [internal route ID: \"revoke-oauth-refresh-token\"]\n\nRevoke an access token.", + "summary": "Initiate account deletion." + }, + "get": { + "description": " [internal route ID: \"get-self\"]\n\n\nOAuth scope: `read:self`", + "operationId": "get-self", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/User_NjA4OTQwMTQ4" + } + } + }, + "description": "" + } + }, + "summary": "Get your own profile" + }, + "put": { + "description": " [internal route ID: \"put-self\"]\n\n", + "operationId": "put-self", "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/OAuthRevokeRefreshTokenRequest" + "$ref": "#/components/schemas/UserUpdate_MjQ4NTEwOTQz" } } }, @@ -18111,26 +26866,28 @@ }, "responses": { "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": [], - "items": {}, - "maxItems": 0, - "type": "array" - } - } - }, - "description": "" + "description": "User updated" + } + }, + "summary": "Update your profile." + } + }, + "/self/email": { + "delete": { + "description": " [internal route ID: \"remove-email\"]\n\nYour email address can only be removed if you also have a phone number.", + "operationId": "remove-email", + "responses": { + "200": { + "description": "Identity Removed" }, "403": { "content": { - "application/json;charset=utf-8": { + "application/json": { "schema": { "example": { "code": 403, - "label": "forbidden", - "message": "Invalid refresh token" + "label": "last-identity", + "message": "The last user identity cannot be removed." }, "properties": { "code": { @@ -18141,7 +26898,8 @@ }, "label": { "enum": [ - "forbidden" + "last-identity", + "no-identity" ], "type": "string" }, @@ -18156,29 +26914,25 @@ ], "type": "object" } - } - }, - "description": "Invalid refresh token (label: `forbidden`)" - }, - "404": { - "content": { + }, "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "not-found", - "message": "OAuth client not found" + "code": 403, + "label": "last-identity", + "message": "The last user identity cannot be removed." }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "not-found" + "last-identity", + "no-identity" ], "type": "string" }, @@ -18195,57 +26949,43 @@ } } }, - "description": "OAuth client not found (label: `not-found`)" - }, - "500": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 500, - "label": "jwt-error", - "message": "Internal error while handling JWT token" - }, - "properties": { - "code": { - "enum": [ - 500 - ], - "type": "integer" - }, - "label": { - "enum": [ - "jwt-error" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } + "description": "The last user identity cannot be removed. (label: `last-identity`)\n\nThe user has no verified email (label: `no-identity`)" + } + }, + "summary": "Remove your email address." + } + }, + "/self/handle": { + "put": { + "description": " [internal route ID: \"change-handle\"]\n\n", + "operationId": "change-handle", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/HandleUpdate_NTI4NDk1OTAx" } - }, - "description": "Internal error while handling JWT token (label: `jwt-error`)" + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Handle Changed" } }, - "summary": "Revoke an OAuth refresh token" + "summary": "Change your handle." } }, - "/oauth/token": { - "post": { - "description": " [internal route ID: \"create-oauth-access-token\"]\n\nObtain a new access token from an authorization code or a refresh token.", + "/self/locale": { + "put": { + "description": " [internal route ID: \"change-locale\"]\n\n", + "operationId": "change-locale", "requestBody": { "content": { - "application/x-www-form-urlencoded": { + "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Either_OAuthAccessTokenRequest_OAuthRefreshAccessTokenRequest" + "$ref": "#/components/schemas/LocaleUpdate_LTgzNjgyOTEw" } } }, @@ -18253,23 +26993,51 @@ }, "responses": { "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/OAuthAccessTokenResponse" - } + "description": "Local Changed" + } + }, + "summary": "Change your locale." + } + }, + "/self/password": { + "head": { + "description": " [internal route ID: \"check-password-exists\"]\n\n", + "operationId": "check-password-exists", + "responses": { + "200": { + "description": "Password is set" + }, + "404": { + "description": "Password is not set" + } + }, + "summary": "Check that your password is set." + }, + "put": { + "description": " [internal route ID: \"change-password\"]\n\n", + "operationId": "change-password", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PasswordChange_MTgzMDM2NTY2" } - }, - "description": "" + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Password Changed" }, "403": { "content": { - "application/json;charset=utf-8": { + "application/json": { "schema": { "example": { "code": 403, - "label": "invalid_grant", - "message": "Invalid grant" + "label": "invalid-credentials", + "message": "Authentication failed" }, "properties": { "code": { @@ -18280,8 +27048,8 @@ }, "label": { "enum": [ - "invalid_grant", - "forbidden" + "invalid-credentials", + "no-identity" ], "type": "string" }, @@ -18296,29 +27064,25 @@ ], "type": "object" } - } - }, - "description": "Invalid grant (label: `invalid_grant`)\n\nInvalid client credentials (label: `forbidden`)\n\nInvalid grant type (label: `forbidden`)\n\nInvalid refresh token (label: `forbidden`)\n\nOAuth is disabled (label: `forbidden`)" - }, - "404": { - "content": { + }, "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "not-found", - "message": "OAuth client not found" + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "not-found" + "invalid-credentials", + "no-identity" ], "type": "string" }, @@ -18335,27 +27099,27 @@ } } }, - "description": "OAuth client not found (label: `not-found`)\n\nOAuth authorization code not found (label: `not-found`)" + "description": "Authentication failed (label: `invalid-credentials`)\n\nThe user has no verified email (label: `no-identity`)" }, - "500": { + "409": { "content": { - "application/json;charset=utf-8": { + "application/json": { "schema": { "example": { - "code": 500, - "label": "jwt-error", - "message": "Internal error while handling JWT token" + "code": 409, + "label": "password-must-differ", + "message": "For password change, new and old password must be different." }, "properties": { "code": { "enum": [ - 500 + 409 ], "type": "integer" }, "label": { "enum": [ - "jwt-error" + "password-must-differ" ], "type": "string" }, @@ -18370,72 +27134,55 @@ ], "type": "object" } - } - }, - "description": "Internal error while handling JWT token (label: `jwt-error`)" - } - }, - "summary": "Create an OAuth access token" - } - }, - "/onboarding/v3": { - "post": { - "deprecated": true, - "description": " [internal route ID: \"onboarding\"]\n\nDEPRECATED: the feature has been turned off, the end-point does nothing and always returns '{\"results\":[],\"auto-connects\":[]}'.", - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Body" - } - } - }, - "required": true - }, - "responses": { - "200": { - "content": { + }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/DeprecatedMatchingResult" + "example": { + "code": 409, + "label": "password-must-differ", + "message": "For password change, new and old password must be different." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "password-must-differ" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "" - } - }, - "summary": "Upload contacts and invoke matching." - } - }, - "/password-reset": { - "post": { - "description": " [internal route ID: \"post-password-reset\"]\n\n", - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/NewPasswordReset" - } - } - }, - "required": true - }, - "responses": { - "201": { - "description": "Password reset code created and sent by email." + "description": "For password change, new and old password must be different. (label: `password-must-differ`)" } }, - "summary": "Initiate a password reset." + "summary": "Change your password." } }, - "/password-reset/complete": { - "post": { - "description": " [internal route ID: \"post-password-reset-complete\"]\n\n", + "/self/supported-protocols": { + "put": { + "description": " [internal route ID: \"change-supported-protocols\"]\n\n", + "operationId": "change-supported-protocols", "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/CompletePasswordReset" + "$ref": "#/components/schemas/SupportedProtocolUpdate_LTE3Njk3MDM4" } } }, @@ -18443,27 +27190,27 @@ }, "responses": { "200": { - "description": "Password reset successful." + "description": "Supported protocols changed" }, - "400": { + "409": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "invalid-code", - "message": "Invalid password reset code." + "code": 409, + "label": "mls-protocol-error", + "message": "MLS protocol cannot be removed" }, "properties": { "code": { "enum": [ - 400 + 409 ], "type": "integer" }, "label": { "enum": [ - "invalid-code" + "mls-protocol-error" ], "type": "string" }, @@ -18480,61 +27227,108 @@ } } }, - "description": "Invalid `body`\n\nInvalid password reset code. (label: `invalid-code`)" + "description": "MLS protocol cannot be removed (label: `mls-protocol-error`)" } }, - "summary": "Complete a password reset." + "summary": "Change your supported protocols" } }, - "/password-reset/{key}": { - "post": { - "deprecated": true, - "description": " [internal route ID: \"post-password-reset-key-deprecated\"]\n\nDEPRECATED: Use 'POST /password-reset/complete'.", + "/services": { + "get": { + "description": " [internal route ID: \"get-services\"]\n\n", + "operationId": "get-services", "parameters": [ { - "description": "An opaque key for a pending password reset.", - "in": "path", - "name": "key", - "required": true, + "in": "query", + "name": "tags", + "required": false, "schema": { + "enum": [ + "audio", + "books", + "business", + "design", + "education", + "entertainment", + "finance", + "fitness", + "food-drink", + "games", + "graphics", + "health", + "integration", + "lifestyle", + "media", + "medical", + "movies", + "music", + "news", + "photography", + "poll", + "productivity", + "quiz", + "rating", + "shopping", + "social", + "sports", + "travel", + "tutorial", + "video", + "weather" + ], "type": "string" } - } - ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/PasswordReset" - } + }, + { + "in": "query", + "name": "start", + "required": false, + "schema": { + "type": "string" } }, - "required": true - }, + { + "in": "query", + "name": "size", + "required": false, + "schema": { + "format": "int32", + "maximum": 100, + "minimum": 10, + "type": "integer" + } + } + ], "responses": { "200": { - "description": "Password reset successful." + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ServiceProfilePage_Njg1NDQ5Njc4" + } + } + }, + "description": "" }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "invalid-code", - "message": "Invalid password reset code." + "code": 403, + "label": "access-denied", + "message": "Access denied." }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "invalid-code", - "invalid-key" + "access-denied" ], "type": "string" }, @@ -18551,28 +27345,46 @@ } } }, - "description": "Invalid `body`\n\nInvalid password reset code. (label: `invalid-code`)\n\nInvalid email or mobile number for password reset. (label: `invalid-key`)" + "description": "Access denied. (label: `access-denied`)" + } + }, + "summary": "List services" + } + }, + "/services/tags": { + "get": { + "description": " [internal route ID: \"get-services-tags\"]\n\n", + "operationId": "get-services-tags", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ServiceTagList" + } + } + }, + "description": "" }, - "409": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 409, - "label": "password-must-differ", - "message": "For password reset, new and old password must be different." + "code": 403, + "label": "access-denied", + "message": "Access denied." }, "properties": { "code": { "enum": [ - 409 + 403 ], "type": "integer" }, "label": { "enum": [ - "password-must-differ", - "code-exists" + "access-denied" ], "type": "string" }, @@ -18589,98 +27401,194 @@ } } }, - "description": "For password reset, new and old password must be different. (label: `password-must-differ`)\n\nA password reset is already in progress. (label: `code-exists`)" + "description": "Access denied. (label: `access-denied`)" } }, - "summary": "Complete a password reset." + "summary": "Get services tags" } }, - "/properties": { - "delete": { - "description": " [internal route ID: \"clear-properties\"]\n\n", + "/sso/finalize-login": { + "post": { + "deprecated": true, + "description": " [internal route ID: \"auth-resp-legacy\"]\n\nDEPRECATED! use /sso/metadata/:tid instead! Details: https://docs.wire.com/understand/single-sign-on/trouble-shooting.html#can-i-use-the-same-sso-login-code-for-multiple-teams", + "operationId": "auth-resp-legacy", "responses": { "200": { - "description": "Properties cleared" + "content": { + "text/plain;charset=utf-8": { + "schema": { + "type": "string" + } + } + }, + "description": "" + } + } + } + }, + "/sso/finalize-login/{team}": { + "post": { + "description": " [internal route ID: \"auth-resp\"]\n\n", + "operationId": "auth-resp", + "parameters": [ + { + "in": "path", + "name": "team", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "text/plain;charset=utf-8": { + "schema": { + "type": "string" + } + } + }, + "description": "" } + } + } + }, + "/sso/get-by-email": { + "post": { + "description": " [internal route ID: \"sso-get-by-email\"]\n\n", + "operationId": "sso-get-by-email", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/GetByEmailReq_LTY4MzE3Njgy" + } + } + }, + "required": true }, - "summary": "Clear all properties" - }, - "get": { - "description": " [internal route ID: \"list-property-keys\"]\n\n", "responses": { "200": { "content": { "application/json": { "schema": { - "items": { - "$ref": "#/components/schemas/ASCII" - }, - "type": "array" + "$ref": "#/components/schemas/GetByEmailResp_LTMxNTY3MjA0" } }, "application/json;charset=utf-8": { "schema": { - "items": { - "$ref": "#/components/schemas/ASCII" - }, - "type": "array" + "$ref": "#/components/schemas/GetByEmailResp_LTMxNTY3MjA0" } } }, - "description": "List of property keys" - } - }, - "summary": "List all property keys" - } - }, - "/properties-values": { - "get": { - "description": " [internal route ID: \"list-properties\"]\n\n", - "responses": { - "200": { + "description": "SSO code found" + }, + "404": { "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetByEmailResp_LTMxNTY3MjA0" + } + }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/PropertyKeysAndValues" + "$ref": "#/components/schemas/GetByEmailResp_LTMxNTY3MjA0" } } }, - "description": "" + "description": "SSO code not found or feature disabled" } - }, - "summary": "List all properties with key and value" + } } }, - "/properties/{key}": { - "delete": { - "description": " [internal route ID: \"delete-property\"]\n\n", + "/sso/initiate-login/{idp}": { + "get": { + "description": " [internal route ID: \"auth-req\"]\n\n", + "operationId": "auth-req", "parameters": [ + { + "in": "query", + "name": "success_redirect", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "error_redirect", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "label", + "required": false, + "schema": { + "type": "string" + } + }, { "in": "path", - "name": "key", + "name": "idp", "required": true, "schema": { - "format": "printable", + "format": "uuid", "type": "string" } } ], "responses": { "200": { - "description": "Property deleted" + "content": { + "text/html": { + "schema": { + "$ref": "#/components/schemas/FormRedirect" + } + } + }, + "description": "" } - }, - "summary": "Delete a property" + } }, - "get": { - "description": " [internal route ID: \"get-property\"]\n\n", + "head": { + "description": " [internal route ID: \"auth-req-precheck\"]\n\n", + "operationId": "auth-req-precheck", "parameters": [ + { + "in": "query", + "name": "success_redirect", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "error_redirect", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "label", + "required": false, + "schema": { + "type": "string" + } + }, { "in": "path", - "name": "key", + "name": "idp", "required": true, "schema": { - "format": "printable", + "format": "uuid", "type": "string" } } @@ -18688,64 +27596,126 @@ "responses": { "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PropertyValue" - } - }, - "application/json;charset=utf-8": { + "text/plain;charset=utf-8": {} + }, + "description": "" + } + } + } + }, + "/sso/metadata": { + "get": { + "deprecated": true, + "description": " [internal route ID: \"sso-metadata\"]\n\nDEPRECATED! use /sso/metadata/:tid instead! Details: https://docs.wire.com/understand/single-sign-on/trouble-shooting.html#can-i-use-the-same-sso-login-code-for-multiple-teams", + "operationId": "sso-metadata", + "responses": { + "200": { + "content": { + "application/xml": { "schema": { - "$ref": "#/components/schemas/PropertyValue" + "type": "string" } } }, - "description": "The property value" - }, - "404": { - "description": "`key` or Property not found(**Note**: This error has an empty body for legacy reasons)" + "description": "" } - }, - "summary": "Get a property value" - }, - "put": { - "description": " [internal route ID: \"set-property\"]\n\n", + } + } + }, + "/sso/metadata/{team}": { + "get": { + "description": " [internal route ID: \"sso-team-metadata\"]\n\n", + "operationId": "sso-team-metadata", "parameters": [ { "in": "path", - "name": "key", + "name": "team", "required": true, "schema": { - "format": "printable", + "format": "uuid", "type": "string" } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/PropertyValue" + "responses": { + "200": { + "content": { + "application/xml": { + "schema": { + "type": "string" + } + } + }, + "description": "" + } + } + } + }, + "/sso/settings": { + "get": { + "description": " [internal route ID: \"sso-settings\"]\n\n", + "operationId": "sso-settings", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/SsoSettings" + } + } + }, + "description": "" + } + } + } + }, + "/system/settings": { + "get": { + "description": " [internal route ID: \"get-system-settings\"]\n\n", + "operationId": "get-system-settings", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/SystemSettings_ODU3MDk5MTA3" + } } - } - }, - "required": true + }, + "description": "" + } }, + "summary": "Returns a curated set of system configuration settings for authorized users." + } + }, + "/system/settings/unauthorized": { + "get": { + "description": " [internal route ID: \"get-system-settings-unauthorized\"]\n\n", + "operationId": "get-system-settings-unauthorized", "responses": { "200": { - "description": "Property set" + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/SystemSettingsPublic_LTgwNTMxNjU2" + } + } + }, + "description": "" } }, - "summary": "Set a user property" + "summary": "Returns a curated set of system configuration settings." } }, - "/provider": { - "delete": { - "description": " [internal route ID: \"provider-delete\"]\n\n", + "/teams/invitations/accept": { + "post": { + "description": " [internal route ID: \"accept-team-invitation\"]\n\n", + "operationId": "accept-team-invitation", "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/DeleteProvider" + "$ref": "#/components/schemas/AcceptTeamInvitation_Nzg5NzI3MjA2" } } }, @@ -18753,7 +27723,7 @@ }, "responses": { "200": { - "description": "" + "description": "Team invitation accepted." }, "403": { "content": { @@ -18761,8 +27731,8 @@ "schema": { "example": { "code": 403, - "label": "invalid-credentials", - "message": "Authentication failed" + "label": "missing-auth", + "message": "Re-authentication via password required" }, "properties": { "code": { @@ -18773,9 +27743,10 @@ }, "label": { "enum": [ + "missing-auth", "invalid-credentials", - "invalid-provider", - "access-denied" + "missing-identity", + "too-many-team-members" ], "type": "string" }, @@ -18792,48 +27763,28 @@ } } }, - "description": "Authentication failed (label: `invalid-credentials`)\n\nThe provider does not exist. (label: `invalid-provider`)\n\nAccess denied. (label: `access-denied`)" - } - }, - "summary": "Delete a provider" - }, - "get": { - "description": " [internal route ID: \"provider-get-account\"]\n\n", - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Provider" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/Provider" - } - } - }, - "description": "" + "description": "Re-authentication via password required (label: `missing-auth`)\n\nAuthentication failed (label: `invalid-credentials`)\n\nUsing an invitation code requires registering the given email. (label: `missing-identity`)\n\nToo many members in this team. (label: `too-many-team-members`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "access-denied", - "message": "Access denied." + "code": 404, + "label": "invalid-code", + "message": "Invalid activation code" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "access-denied" + "invalid-code", + "not-found" ], "type": "string" }, @@ -18850,7 +27801,30 @@ } } }, - "description": "Access denied. (label: `access-denied`)" + "description": "Invalid activation code (label: `invalid-code`)\n\nUser does not exist (label: `invalid-code`)\n\nNo pending invitations exists. (label: `not-found`)" + } + }, + "summary": "Accept a team invitation, changing a personal account into a team member account." + } + }, + "/teams/invitations/by-email": { + "head": { + "description": " [internal route ID: \"head-team-invitations\"]\n\n", + "operationId": "head-team-invitations", + "parameters": [ + { + "description": "Email address", + "in": "query", + "name": "email", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Pending invitation exists." }, "404": { "content": { @@ -18859,7 +27833,7 @@ "example": { "code": 404, "label": "not-found", - "message": "Provider not found." + "message": "No pending invitations exists." }, "properties": { "code": { @@ -18891,7 +27865,7 @@ "example": { "code": 404, "label": "not-found", - "message": "Provider not found." + "message": "No pending invitations exists." }, "properties": { "code": { @@ -18919,47 +27893,59 @@ } } }, - "description": "Provider not found. (label: `not-found`)\n\nProvider not found. (label: `not-found`)" - } - }, - "summary": "Get account" - }, - "put": { - "description": " [internal route ID: \"provider-update\"]\n\n", - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/UpdateProvider" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "" + "description": "No pending invitations exists. (label: `not-found`)" }, - "403": { + "409": { "content": { + "application/json": { + "schema": { + "example": { + "code": 409, + "label": "conflicting-invitations", + "message": "Multiple conflicting invitations to different teams exists." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "conflicting-invitations" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "invalid-provider", - "message": "The provider does not exist." + "code": 409, + "label": "conflicting-invitations", + "message": "Multiple conflicting invitations to different teams exists." }, "properties": { "code": { "enum": [ - 403 + 409 ], "type": "integer" }, "label": { "enum": [ - "invalid-provider", - "access-denied" + "conflicting-invitations" ], "type": "string" }, @@ -18976,25 +27962,19 @@ } } }, - "description": "The provider does not exist. (label: `invalid-provider`)\n\nAccess denied. (label: `access-denied`)" + "description": "Multiple conflicting invitations to different teams exists. (label: `conflicting-invitations`)" } }, - "summary": "Update a provider" + "summary": "Check if there is an invitation pending given an email address." } }, - "/provider/activate": { + "/teams/invitations/info": { "get": { - "description": " [internal route ID: \"provider-activate\"]\n\n", + "description": " [internal route ID: \"get-team-invitation-info\"]\n\n", + "operationId": "get-team-invitation-info", "parameters": [ { - "in": "query", - "name": "key", - "required": true, - "schema": { - "type": "string" - } - }, - { + "description": "Invitation code", "in": "query", "name": "code", "required": true, @@ -19008,40 +27988,36 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ProviderActivationResponse" + "$ref": "#/components/schemas/InvitationUserView_LTUyMTE3Nzkz" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ProviderActivationResponse" + "$ref": "#/components/schemas/InvitationUserView_LTUyMTE3Nzkz" } } }, - "description": "" - }, - "204": { - "description": "" + "description": "Invitation info" }, - "403": { + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "invalid-code", - "message": "Invalid verification code" + "code": 400, + "label": "invalid-invitation-code", + "message": "Invalid invitation code." }, "properties": { "code": { "enum": [ - 403 + 400 ], "type": "integer" }, "label": { "enum": [ - "invalid-code", - "access-denied" + "invalid-invitation-code" ], "type": "string" }, @@ -19058,48 +28034,50 @@ } } }, - "description": "Invalid verification code (label: `invalid-code`)\n\nAccess denied. (label: `access-denied`)" + "description": "Invalid `code`\n\nInvalid invitation code. (label: `invalid-invitation-code`)" } }, - "summary": "Activate a provider" + "summary": "Get invitation info given a code." } }, - "/provider/assets": { - "post": { - "requestBody": { - "content": { - "multipart/mixed": { - "schema": { - "$ref": "#/components/schemas/AssetSource" - } + "/teams/notifications": { + "get": { + "description": " [internal route ID: \"get-team-notifications\"]\n\n

This is a work-around for scalability issues with gundeck user event fan-out. It does not track all team-wide events, but only `member-join`.

Note that `/teams/notifications` behaves differently from `/notifications`:

  • If there is a gap between the notification id requested with `since` and the available data, team queues respond with 200 and the data that could be found. They do NOT respond with status 404, but valid data in the body.\n
  • The notification with the id given via `since` is included in the response if it exists. You should remove this and only use it to decide whether there was a gap between your last request and this one.\n
  • If the notification id does *not* exist, you get the more recent events from the queue (instead of all of them). This can be done because a notification id is a UUIDv1, which is essentially a time stamp.\n
  • There is no corresponding `/last` end-point to get only the most recent event. That end-point was only useful to avoid having to pull the entire queue. In team queues, if you have never requested the queue before and have no prior notification id, just pull with timestamp 'now'.

See also: GET /notifications

", + "operationId": "get-team-notifications", + "parameters": [ + { + "description": "Notification id to start with in the response (UUIDv1)", + "in": "query", + "name": "since", + "required": false, + "schema": { + "format": "uuid", + "type": "string" } }, - "description": "A body with content type `multipart/mixed body`. The first section's content type should be `application/json`. The second section's content type should be always be `application/octet-stream`. Other content types will be ignored by the server." - }, + { + "description": "Maximum number of events to return (1..10000; default: 1000)", + "in": "query", + "name": "size", + "required": false, + "schema": { + "format": "int32", + "maximum": 10000, + "minimum": 1, + "type": "integer" + } + } + ], "responses": { - "201": { + "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Asset" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Asset" + "$ref": "#/components/schemas/QueuedNotificationList_MTU0ODEyNTQ2" } } }, - "description": "Asset posted", - "headers": { - "Location": { - "description": "Asset location", - "schema": { - "format": "url", - "type": "string" - } - } - } + "description": "" }, "400": { "content": { @@ -19107,8 +28085,8 @@ "schema": { "example": { "code": 400, - "label": "invalid-length", - "message": "Invalid content length" + "label": "invalid-notification-id", + "message": "Could not parse notification id (must be UUIDv1)." }, "properties": { "code": { @@ -19119,7 +28097,7 @@ }, "label": { "enum": [ - "invalid-length" + "invalid-notification-id" ], "type": "string" }, @@ -19136,27 +28114,27 @@ } } }, - "description": "Invalid `body`\n\nInvalid content length (label: `invalid-length`)" + "description": "Invalid `size` or `since`\n\nCould not parse notification id (must be UUIDv1). (label: `invalid-notification-id`)" }, - "413": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 413, - "label": "client-error", - "message": "Asset too large" + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 413 + 404 ], "type": "integer" }, "label": { "enum": [ - "client-error" + "no-team" ], "type": "string" }, @@ -19173,84 +28151,63 @@ } } }, - "description": "Asset too large (label: `client-error`)" + "description": "Team not found (label: `no-team`)" } }, - "summary": "Upload an asset" + "summary": "Read recently added team members from team queue" } }, - "/provider/assets/{key}": { - "delete": { + "/teams/{team-id}/services/whitelist": { + "post": { + "description": " [internal route ID: \"post-team-whitelist-by-team-id\"]\n\n", + "operationId": "post-team-whitelist-by-team-id", "parameters": [ { "in": "path", - "name": "key", + "name": "team-id", "required": true, "schema": { + "format": "uuid", "type": "string" } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UpdateServiceWhitelist_LTU5MDAwMTIw" + } + } + }, + "required": true + }, "responses": { "200": { - "description": "Asset deleted" + "description": "UpdateServiceWhitelistRespChanged" }, - "403": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 403, - "label": "unauthorised", - "message": "Unauthorised operation" - }, - "properties": { - "code": { - "enum": [ - 403 - ], - "type": "integer" - }, - "label": { - "enum": [ - "unauthorised" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } - } - }, - "description": "Unauthorised operation (label: `unauthorised`)" + "204": { + "description": "UpdateServiceWhitelistRespUnchanged" }, - "404": { + "409": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "not-found", - "message": "Asset not found" + "code": 409, + "label": "mls-services-not-allowed", + "message": "Services not allowed in MLS" }, "properties": { "code": { "enum": [ - 404 + 409 ], "type": "integer" }, "label": { "enum": [ - "not-found" + "mls-services-not-allowed" ], "type": "string" }, @@ -19267,70 +28224,147 @@ } } }, - "description": "`key` not found\n\nAsset not found (label: `not-found`)" + "description": "Services not allowed in MLS (label: `mls-services-not-allowed`)" } }, - "summary": "Delete an asset" - }, + "summary": "Update service whitelist" + } + }, + "/teams/{team-id}/services/whitelisted": { "get": { + "description": " [internal route ID: \"get-whitelisted-services-by-team-id\"]\n\n", + "operationId": "get-whitelisted-services-by-team-id", "parameters": [ { "in": "path", - "name": "key", + "name": "team-id", "required": true, "schema": { + "format": "uuid", "type": "string" } }, { - "in": "header", - "name": "Asset-Token", + "in": "query", + "name": "prefix", "required": false, "schema": { + "maxLength": 128, + "minLength": 1, "type": "string" } }, { "in": "query", - "name": "asset_token", + "name": "filter_disabled", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "in": "query", + "name": "size", "required": false, "schema": { + "format": "int32", + "maximum": 100, + "minimum": 10, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ServiceProfilePage_Njg1NDQ5Njc4" + } + } + }, + "description": "" + } + }, + "summary": "Get whitelisted services by team id" + } + }, + "/teams/{teamId}/registered-domains": { + "get": { + "description": " [internal route ID: \"get-all-registered-domains\"]\n\n", + "operationId": "get-all-registered-domains", + "parameters": [ + { + "in": "path", + "name": "teamId", + "required": true, + "schema": { + "format": "uuid", "type": "string" } } ], "responses": { - "302": { - "description": "Asset found", - "headers": { - "Location": { - "description": "Asset location", + "200": { + "content": { + "application/json;charset=utf-8": { "schema": { - "format": "url", - "type": "string" + "$ref": "#/components/schemas/RegisteredDomains_V10_NDYwNzYyMTMy" } } + }, + "description": "" + } + }, + "summary": "Get all registered domains" + } + }, + "/teams/{teamId}/registered-domains/{domain}": { + "delete": { + "description": " [internal route ID: \"delete-registered-domain\"]\n\n", + "operationId": "delete-registered-domain", + "parameters": [ + { + "in": "path", + "name": "teamId", + "required": true, + "schema": { + "format": "uuid", + "type": "string" } }, - "404": { + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Deleted" + }, + "402": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "not-found", - "message": "Asset not found" + "code": 402, + "label": "domain-registration-update-payment-required", + "message": "Domain registration updated payment required" }, "properties": { "code": { "enum": [ - 404 + 402 ], "type": "integer" }, "label": { "enum": [ - "not-found" + "domain-registration-update-payment-required" ], "type": "string" }, @@ -19345,24 +28379,29 @@ ], "type": "object" } - }, + } + }, + "description": "Domain registration updated payment required (label: `domain-registration-update-payment-required`)" + }, + "403": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "not-found", - "message": "Asset not found" + "code": 403, + "label": "operation-forbidden-for-domain-registration-state", + "message": "Invalid domain registration state update" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "not-found" + "operation-forbidden-for-domain-registration-state" ], "type": "string" }, @@ -19379,20 +28418,32 @@ } } }, - "description": "`key` or Asset not found (label: `not-found`)" + "description": "Invalid domain registration state update (label: `operation-forbidden-for-domain-registration-state`)" } }, - "summary": "Download an asset" + "summary": "Delete a registered domain" } }, - "/provider/email": { - "put": { - "description": " [internal route ID: \"provider-update-email\"]\n\n", + "/teams/{tid}": { + "delete": { + "description": " [internal route ID: \"delete-team\"]\n\n", + "operationId": "delete-team", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/EmailUpdate" + "$ref": "#/components/schemas/TeamDeleteData_ODI5NTU0ODE5" } } }, @@ -19400,27 +28451,68 @@ }, "responses": { "202": { - "description": "" + "description": "Team is scheduled for removal" }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "invalid-email", - "message": "Invalid e-mail address." + "code": 403, + "label": "code-authentication-required", + "message": "Verification code required" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "code-authentication-required", + "code-authentication-failed", + "access-denied", + "operation-denied", + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Verification code required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nThis operation requires reauthentication (label: `access-denied`)\n\nInsufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (missing DeleteTeam) (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 400 + 404 ], "type": "integer" }, "label": { "enum": [ - "invalid-email" + "no-team" ], "type": "string" }, @@ -19437,28 +28529,27 @@ } } }, - "description": "Invalid `body`\n\nInvalid e-mail address. (label: `invalid-email`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" }, - "403": { + "429": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "invalid-provider", - "message": "The provider does not exist." + "code": 429, + "label": "too-many-requests", + "message": "Please try again later." }, "properties": { "code": { "enum": [ - 403 + 429 ], "type": "integer" }, "label": { "enum": [ - "invalid-provider", - "access-denied" + "too-many-requests" ], "type": "string" }, @@ -19475,27 +28566,27 @@ } } }, - "description": "The provider does not exist. (label: `invalid-provider`)\n\nAccess denied. (label: `access-denied`)" + "description": "Please try again later. (label: `too-many-requests`)" }, - "429": { + "503": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 429, - "label": "too-many-requests", - "message": "Too many request to generate a verification code." + "code": 503, + "label": "queue-full", + "message": "The delete queue is full; no further delete requests can be processed at the moment" }, "properties": { "code": { "enum": [ - 429 + 503 ], "type": "integer" }, "label": { "enum": [ - "too-many-requests" + "queue-full" ], "type": "string" }, @@ -19512,56 +28603,55 @@ } } }, - "description": "Too many request to generate a verification code. (label: `too-many-requests`)" + "description": "The delete queue is full; no further delete requests can be processed at the moment (label: `queue-full`)" } }, - "summary": "Update a provider email" - } - }, - "/provider/login": { - "post": { - "description": " [internal route ID: \"provider-login\"]\n\n", - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ProviderLogin" - } + "summary": "Delete a team" + }, + "get": { + "description": " [internal route ID: \"get-team\"]\n\n", + "operationId": "get-team", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" } - }, - "required": true - }, + } + ], "responses": { "200": { - "description": "OK", - "headers": { - "Set-Cookie": { + "content": { + "application/json;charset=utf-8": { "schema": { - "type": "string" + "$ref": "#/components/schemas/Team_NDg4MjQwOTIw" } } - } + }, + "description": "" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "invalid-credentials", - "message": "Authentication failed" + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "invalid-credentials", - "access-denied" + "no-team" ], "type": "string" }, @@ -19578,20 +28668,30 @@ } } }, - "description": "Authentication failed (label: `invalid-credentials`)\n\nAccess denied. (label: `access-denied`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Login as a provider" - } - }, - "/provider/password": { + "summary": "Get a team by ID" + }, "put": { - "description": " [internal route ID: \"provider-update-password\"]\n\n", + "description": " [internal route ID: \"update-team\"]\n\n", + "operationId": "update-team", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/PasswordChange" + "$ref": "#/components/schemas/TeamUpdateData_LTE0NTM2NTU5" } } }, @@ -19599,7 +28699,7 @@ }, "responses": { "200": { - "description": "" + "description": "Team updated" }, "403": { "content": { @@ -19607,8 +28707,8 @@ "schema": { "example": { "code": 403, - "label": "invalid-credentials", - "message": "Authentication failed" + "label": "operation-denied", + "message": "Insufficient permissions (missing SetTeamData)" }, "properties": { "code": { @@ -19619,8 +28719,8 @@ }, "label": { "enum": [ - "invalid-credentials", - "access-denied" + "operation-denied", + "no-team-member" ], "type": "string" }, @@ -19637,103 +28737,179 @@ } } }, - "description": "Authentication failed (label: `invalid-credentials`)\n\nAccess denied. (label: `access-denied`)" - }, - "409": { + "description": "Insufficient permissions (missing SetTeamData) (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" + } + }, + "summary": "Update team properties" + } + }, + "/teams/{tid}/apps": { + "get": { + "description": " [internal route ID: \"get-apps\"]\n\n", + "operationId": "get-apps", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { "content": { "application/json;charset=utf-8": { "schema": { - "example": { - "code": 409, - "label": "password-must-differ", - "message": "For password reset, new and old password must be different." - }, - "properties": { - "code": { - "enum": [ - 409 - ], - "type": "integer" - }, - "label": { - "enum": [ - "password-must-differ" - ], - "type": "string" - }, - "message": { - "type": "string" - } + "items": { + "$ref": "#/components/schemas/UserProfile_LTQzMTQxMTE1" }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" + "type": "array" } } }, - "description": "For password reset, new and old password must be different. (label: `password-must-differ`)" + "description": "" } }, - "summary": "Update a provider password" + "summary": "Get all apps owned by the given team (not including collaborators)" + }, + "post": { + "description": " [internal route ID: \"create-app\"]\n\n", + "operationId": "create-app", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewApp_LTQwODMwMzQ4" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CreatedApp_LTM3NjUxOTY1" + } + } + }, + "description": "" + } + }, + "summary": "Create a new app" } }, - "/provider/password-reset": { - "post": { - "description": " [internal route ID: \"provider-password-reset\"]\n\n", + "/teams/{tid}/apps/{app}": { + "put": { + "description": " [internal route ID: \"put-app\"]\n\n", + "operationId": "put-app", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "app", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/PasswordReset" + "$ref": "#/components/schemas/PutApp_LTE4MDc1OTM4" } } }, "required": true }, "responses": { - "201": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + } + }, "description": "" + } + }, + "summary": "Update metadata of an existing app" + } + }, + "/teams/{tid}/apps/{app}/cookies": { + "post": { + "description": " [internal route ID: \"refresh-app-cookie\"]\n\n", + "operationId": "refresh-app-cookie", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } }, - "400": { + { + "in": "path", + "name": "app", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/RefreshAppCookieRequest_MjEyMDMyMTk5" + } + } + }, + "required": true + }, + "responses": { + "200": { "content": { "application/json;charset=utf-8": { "schema": { - "example": { - "code": 400, - "label": "invalid-code", - "message": "Invalid password reset code." - }, - "properties": { - "code": { - "enum": [ - 400 - ], - "type": "integer" - }, - "label": { - "enum": [ - "invalid-code", - "invalid-key" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" + "$ref": "#/components/schemas/RefreshAppCookieResponse_LTQ0MjU1NTIw" } } }, - "description": "Invalid `body`\n\nInvalid password reset code. (label: `invalid-code`)\n\nInvalid email or mobile number for password reset. (label: `invalid-key`)" + "description": "" }, "403": { "content": { @@ -19741,8 +28917,8 @@ "schema": { "example": { "code": 403, - "label": "invalid-credentials", - "message": "Authentication failed" + "label": "missing-auth", + "message": "Re-authentication via password required" }, "properties": { "code": { @@ -19753,8 +28929,7 @@ }, "label": { "enum": [ - "invalid-credentials", - "access-denied" + "missing-auth" ], "type": "string" }, @@ -19771,149 +28946,208 @@ } } }, - "description": "Authentication failed (label: `invalid-credentials`)\n\nAccess denied. (label: `access-denied`)" + "description": "Re-authentication via password required (label: `missing-auth`)" + } + }, + "summary": "Get a new app authentication token" + } + }, + "/teams/{tid}/channels/search": { + "get": { + "description": " [internal route ID: \"search-channels\"]\n\n", + "operationId": "search-channels", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } }, - "409": { + { + "description": "Search string", + "in": "query", + "name": "q", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "sort_order", + "required": false, + "schema": { + "enum": [ + "asc", + "desc" + ], + "type": "string" + } + }, + { + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "description": "integer from [1..500]", + "type": "number" + } + }, + { + "description": "`name` of the last seen channel of the current page, used to get the next page.", + "in": "query", + "name": "last_seen_name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "`id` of the last seen channel, used to get the next page, used as a tie breaker. **Must** be sent to get the next page.", + "in": "query", + "name": "last_seen_id", + "required": false, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "allowEmptyValue": true, + "in": "query", + "name": "discoverable", + "schema": { + "default": false, + "type": "boolean" + } + } + ], + "responses": { + "200": { "content": { "application/json;charset=utf-8": { "schema": { - "example": { - "code": 409, - "label": "password-must-differ", - "message": "For password reset, new and old password must be different." - }, - "properties": { - "code": { - "enum": [ - 409 - ], - "type": "integer" - }, - "label": { - "enum": [ - "password-must-differ", - "code-exists" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" + "$ref": "#/components/schemas/ConversationPage_LTIwMDU2NDI3" } } }, - "description": "For password reset, new and old password must be different. (label: `password-must-differ`)\n\nA password reset is already in progress. (label: `code-exists`)\n\nA password reset is already in progress. (label: `code-exists`)" - }, - "429": { + "description": "" + } + }, + "summary": "Search channels" + } + }, + "/teams/{tid}/collaborators": { + "get": { + "description": " [internal route ID: \"get-team-collaborators\"]\n\n", + "operationId": "get-team-collaborators", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { "content": { - "application/json;charset=utf-8": { + "application/json": { "schema": { - "example": { - "code": 429, - "label": "too-many-requests", - "message": "Too many request to generate a verification code." + "items": { + "$ref": "#/components/schemas/TeamCollaborator_LTI3MzM1MTYz" }, - "properties": { - "code": { - "enum": [ - 429 - ], - "type": "integer" - }, - "label": { - "enum": [ - "too-many-requests" - ], - "type": "string" - }, - "message": { - "type": "string" - } + "type": "array" + } + }, + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/TeamCollaborator_LTI3MzM1MTYz" }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" + "type": "array" } } }, - "description": "Too many request to generate a verification code. (label: `too-many-requests`)" + "description": "Return collaborators" } }, - "summary": "Begin a password reset" - } - }, - "/provider/password-reset/complete": { + "summary": "Get all collaborators of the team." + }, "post": { - "description": " [internal route ID: \"provider-password-reset-complete\"]\n\n", + "description": " [internal route ID: \"add-team-collaborator\"]\n\n", + "operationId": "add-team-collaborator", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/CompletePasswordReset" + "$ref": "#/components/schemas/NewTeamCollaborator_LTIxNjEzMTYw" } } - }, - "required": true - }, + }, + "required": true + }, + "responses": { + "200": { + "description": "" + } + }, + "summary": "Add a collaborator to the team." + } + }, + "/teams/{tid}/collaborators/{uid}": { + "delete": { + "description": " [internal route ID: \"remove-team-collaborator\"]\n\n", + "operationId": "remove-team-collaborator", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], "responses": { "200": { "description": "" }, - "400": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 400, - "label": "invalid-code", - "message": "Invalid password reset code." - }, - "properties": { - "code": { - "enum": [ - 400 - ], - "type": "integer" - }, - "label": { - "enum": [ - "invalid-code" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } - } - }, - "description": "Invalid `body`\n\nInvalid password reset code. (label: `invalid-code`)" - }, "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { "code": 403, - "label": "invalid-credentials", - "message": "Authentication failed" + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { @@ -19924,46 +29158,8 @@ }, "label": { "enum": [ - "invalid-credentials", - "invalid-code", - "access-denied" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } - } - }, - "description": "Authentication failed (label: `invalid-credentials`)\n\nInvalid verification code (label: `invalid-code`)\n\nAccess denied. (label: `access-denied`)" - }, - "409": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 409, - "label": "password-must-differ", - "message": "For password reset, new and old password must be different." - }, - "properties": { - "code": { - "enum": [ - 409 - ], - "type": "integer" - }, - "label": { - "enum": [ - "password-must-differ" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -19980,60 +29176,102 @@ } } }, - "description": "For password reset, new and old password must be different. (label: `password-must-differ`)" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" } }, - "summary": "Complete a password reset" - } - }, - "/provider/register": { - "post": { - "description": " [internal route ID: \"provider-register\"]\n\n", + "summary": "Remove a collaborator from the team." + }, + "put": { + "description": " [internal route ID: \"update-team-collaborator\"]\n\n", + "operationId": "update-team-collaborator", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/NewProvider" + "items": { + "$ref": "#/components/schemas/CollaboratorPermission_NDg5NTg2ODgy" + }, + "type": "array", + "uniqueItems": true } } }, "required": true }, "responses": { - "201": { + "200": { + "description": "" + } + }, + "summary": "Update a collaborator permissions from the team." + } + }, + "/teams/{tid}/conversations": { + "get": { + "description": " [internal route ID: \"get-team-conversations\"]\n\n", + "operationId": "get-team-conversations", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NewProviderResponse" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/NewProviderResponse" + "$ref": "#/components/schemas/TeamConversationList_OTI3MzY3NzY0" } } }, "description": "" }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "invalid-email", - "message": "Invalid e-mail address." + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "invalid-email" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -20050,7 +29288,37 @@ } } }, - "description": "Invalid `body`\n\nInvalid e-mail address. (label: `invalid-email`)" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + } + }, + "summary": "Get team conversations" + } + }, + "/teams/{tid}/conversations/roles": { + "get": { + "description": " [internal route ID: \"get-team-conversation-roles\"]\n\n", + "operationId": "get-team-conversation-roles", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationRolesList" + } + } + }, + "description": "" }, "403": { "content": { @@ -20058,8 +29326,8 @@ "schema": { "example": { "code": 403, - "label": "access-denied", - "message": "Access denied." + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { @@ -20070,7 +29338,7 @@ }, "label": { "enum": [ - "access-denied" + "no-team-member" ], "type": "string" }, @@ -20087,27 +29355,61 @@ } } }, - "description": "Access denied. (label: `access-denied`)" + "description": "Requesting user is not a team member (label: `no-team-member`)" + } + }, + "summary": "Get existing roles available for the given team" + } + }, + "/teams/{tid}/conversations/{cid}": { + "delete": { + "description": " [internal route ID: \"delete-team-conversation\"]\n\n", + "operationId": "delete-team-conversation", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } }, - "429": { + { + "in": "path", + "name": "cid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Conversation deleted" + }, + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 429, - "label": "too-many-requests", - "message": "Too many request to generate a verification code." + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 429 + 403 ], "type": "integer" }, "label": { "enum": [ - "too-many-requests" + "no-team-member", + "invalid-op", + "action-denied" ], "type": "string" }, @@ -20124,48 +29426,27 @@ } } }, - "description": "Too many request to generate a verification code. (label: `too-many-requests`)" - } - }, - "summary": "Register a new provider" - } - }, - "/provider/services": { - "get": { - "description": " [internal route ID: \"get-provider-services\"]\n\n", - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "items": { - "$ref": "#/components/schemas/Service" - }, - "type": "array" - } - } - }, - "description": "" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInvalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing delete_conversation) (label: `action-denied`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "access-denied", - "message": "Access denied." + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "access-denied" + "no-conversation" ], "type": "string" }, @@ -20182,58 +29463,65 @@ } } }, - "description": "Access denied. (label: `access-denied`)" + "description": "`tid` or `cid` not found\n\nConversation not found (label: `no-conversation`)" } }, - "summary": "List provider services" + "summary": "Remove a team conversation" }, - "post": { - "description": " [internal route ID: \"post-provider-services\"]\n\n", - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/NewService" - } + "get": { + "description": " [internal route ID: \"get-team-conversation\"]\n\n", + "operationId": "get-team-conversation", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" } }, - "required": true - }, + { + "in": "path", + "name": "cid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], "responses": { - "201": { + "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NewServiceResponse" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/NewServiceResponse" + "$ref": "#/components/schemas/TeamConversation_LTIwNzgyNTEz" } } }, "description": "" }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "invalid-service-key", - "message": "Invalid service key." + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "invalid-service-key" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -20250,27 +29538,27 @@ } } }, - "description": "Invalid `body`\n\nInvalid service key. (label: `invalid-service-key`)" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "access-denied", - "message": "Access denied." + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "access-denied" + "no-conversation" ], "type": "string" }, @@ -20287,19 +29575,20 @@ } } }, - "description": "Access denied. (label: `access-denied`)" + "description": "`tid` or `cid` not found\n\nConversation not found (label: `no-conversation`)" } }, - "summary": "Create a new service" + "summary": "Get one team conversation" } }, - "/provider/services/{service-id}": { - "delete": { - "description": " [internal route ID: \"delete-provider-services-by-service-id\"]\n\n", + "/teams/{tid}/features": { + "get": { + "description": " [internal route ID: \"get-all-feature-configs-for-team\"]\n\nGets feature configs for a team. User must be a member of the team and have permission to view team features.", + "operationId": "get-all-feature-configs-for-team", "parameters": [ { "in": "path", - "name": "service-id", + "name": "tid", "required": true, "schema": { "format": "uuid", @@ -20307,18 +29596,15 @@ } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/DeleteService" - } - } - }, - "required": true - }, "responses": { - "202": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NP_LockableFtur_ghdCnfiSOVsyAvIRqExmDpB_MGwUT2Q_LTM1Mzc0ODgy" + } + } + }, "description": "" }, "403": { @@ -20327,8 +29613,8 @@ "schema": { "example": { "code": 403, - "label": "invalid-credentials", - "message": "Authentication failed" + "label": "operation-denied", + "message": "Insufficient permissions" }, "properties": { "code": { @@ -20339,8 +29625,8 @@ }, "label": { "enum": [ - "invalid-credentials", - "access-denied" + "operation-denied", + "no-team-member" ], "type": "string" }, @@ -20357,7 +29643,7 @@ } } }, - "description": "Authentication failed (label: `invalid-credentials`)\n\nAccess denied. (label: `access-denied`)" + "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" }, "404": { "content": { @@ -20365,8 +29651,8 @@ "schema": { "example": { "code": 404, - "label": "not-found", - "message": "Service not found." + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { @@ -20377,7 +29663,7 @@ }, "label": { "enum": [ - "not-found" + "no-team" ], "type": "string" }, @@ -20394,17 +29680,20 @@ } } }, - "description": "`service-id` not found\n\nService not found. (label: `not-found`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Delete service" - }, + "summary": "Gets feature configs for a team" + } + }, + "/teams/{tid}/features/allowedGlobalOperations": { "get": { - "description": " [internal route ID: \"get-provider-services-by-service-id\"]\n\n", + "description": " [internal route ID: (\"get\", AllowedGlobalOperationsConfig)]\n\n", + "operationId": "get_AllowedGlobalOperationsConfig", "parameters": [ { "in": "path", - "name": "service-id", + "name": "tid", "required": true, "schema": { "format": "uuid", @@ -20417,7 +29706,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Service" + "$ref": "#/components/schemas/LockableFeature_AllowedGlobalOperationsConfig_NjQ1MjA5MDYw" } } }, @@ -20429,8 +29718,8 @@ "schema": { "example": { "code": 403, - "label": "access-denied", - "message": "Access denied." + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { @@ -20441,7 +29730,8 @@ }, "label": { "enum": [ - "access-denied" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -20458,7 +29748,7 @@ } } }, - "description": "Access denied. (label: `access-denied`)" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, "404": { "content": { @@ -20466,8 +29756,8 @@ "schema": { "example": { "code": 404, - "label": "not-found", - "message": "Service not found." + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { @@ -20478,7 +29768,7 @@ }, "label": { "enum": [ - "not-found" + "no-team" ], "type": "string" }, @@ -20495,17 +29785,20 @@ } } }, - "description": "`service-id` not found\n\nService not found. (label: `not-found`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get provider service by service id" - }, - "put": { - "description": " [internal route ID: \"put-provider-services-by-service-id\"]\n\n", + "summary": "Get config for allowedGlobalOperations" + } + }, + "/teams/{tid}/features/appLock": { + "get": { + "description": " [internal route ID: (\"get\", AppLockConfigB)]\n\n", + "operationId": "get_AppLockConfigB", "parameters": [ { "in": "path", - "name": "service-id", + "name": "tid", "required": true, "schema": { "format": "uuid", @@ -20513,19 +29806,16 @@ } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/UpdateService" - } - } - }, - "required": true - }, "responses": { "200": { - "description": "Provider service updated" + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_AppLockConfigB_Bare_Identity_ODgzNDI0OTU5" + } + } + }, + "description": "" }, "403": { "content": { @@ -20533,8 +29823,8 @@ "schema": { "example": { "code": 403, - "label": "access-denied", - "message": "Access denied." + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { @@ -20545,7 +29835,8 @@ }, "label": { "enum": [ - "access-denied" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -20562,7 +29853,7 @@ } } }, - "description": "Access denied. (label: `access-denied`)" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, "404": { "content": { @@ -20570,8 +29861,8 @@ "schema": { "example": { "code": 404, - "label": "not-found", - "message": "Provider not found." + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { @@ -20582,7 +29873,7 @@ }, "label": { "enum": [ - "not-found" + "no-team" ], "type": "string" }, @@ -20599,19 +29890,18 @@ } } }, - "description": "`service-id` not found\n\nProvider not found. (label: `not-found`)\n\nService not found. (label: `not-found`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Update provider service" - } - }, - "/provider/services/{service-id}/connection": { + "summary": "Get config for appLock" + }, "put": { - "description": " [internal route ID: \"put-provider-services-connection-by-service-id\"]\n\n", + "description": " [internal route ID: (\"put\", AppLockConfigB)]\n\n", + "operationId": "put_AppLockConfigB", "parameters": [ { "in": "path", - "name": "service-id", + "name": "tid", "required": true, "schema": { "format": "uuid", @@ -20620,55 +29910,25 @@ } ], "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/UpdateServiceConn" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Provider service connection updated" - }, - "400": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 400, - "label": "invalid-service-key", - "message": "Invalid service key." - }, - "properties": { - "code": { - "enum": [ - 400 - ], - "type": "integer" - }, - "label": { - "enum": [ - "invalid-service-key" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_AppLockConfigB_Bare_Identity_MTAzMjI5NDYy" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_AppLockConfigB_Bare_Identity_ODgzNDI0OTU5" } } }, - "description": "Invalid `body`\n\nInvalid service key. (label: `invalid-service-key`)" + "description": "" }, "403": { "content": { @@ -20676,8 +29936,8 @@ "schema": { "example": { "code": 403, - "label": "invalid-credentials", - "message": "Authentication failed" + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { @@ -20688,8 +29948,8 @@ }, "label": { "enum": [ - "invalid-credentials", - "access-denied" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -20706,7 +29966,7 @@ } } }, - "description": "Authentication failed (label: `invalid-credentials`)\n\nAccess denied. (label: `access-denied`)" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, "404": { "content": { @@ -20714,8 +29974,8 @@ "schema": { "example": { "code": 404, - "label": "not-found", - "message": "Service not found." + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { @@ -20726,7 +29986,7 @@ }, "label": { "enum": [ - "not-found" + "no-team" ], "type": "string" }, @@ -20743,19 +30003,20 @@ } } }, - "description": "`service-id` not found\n\nService not found. (label: `not-found`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Update provider service connection" + "summary": "Put config for appLock" } }, - "/providers/{pid}": { + "/teams/{tid}/features/apps": { "get": { - "description": " [internal route ID: \"provider-get-profile\"]\n\n", + "description": " [internal route ID: (\"get\", AppsConfig)]\n\n", + "operationId": "get_AppsConfig", "parameters": [ { "in": "path", - "name": "pid", + "name": "tid", "required": true, "schema": { "format": "uuid", @@ -20766,38 +30027,34 @@ "responses": { "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Provider" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Provider" + "$ref": "#/components/schemas/LockableFeature_AppsConfig_MzQyNTMxNTk5" } } }, "description": "" }, - "404": { + "403": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "not-found", - "message": "Provider not found." + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "not-found" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -20812,13 +30069,18 @@ ], "type": "object" } - }, + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { "code": 404, - "label": "not-found", - "message": "Provider not found." + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { @@ -20829,7 +30091,7 @@ }, "label": { "enum": [ - "not-found" + "no-team" ], "type": "string" }, @@ -20846,19 +30108,20 @@ } } }, - "description": "`pid` or Provider not found. (label: `not-found`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get profile" + "summary": "Get config for apps" } }, - "/providers/{provider-id}/services": { + "/teams/{tid}/features/assetAuditLog": { "get": { - "description": " [internal route ID: \"get-provider-services-by-provider-id\"]\n\n", + "description": " [internal route ID: (\"get\", AssetAuditLogConfig)]\n\n", + "operationId": "get_AssetAuditLogConfig", "parameters": [ { "in": "path", - "name": "provider-id", + "name": "tid", "required": true, "schema": { "format": "uuid", @@ -20871,10 +30134,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "items": { - "$ref": "#/components/schemas/ServiceProfile" - }, - "type": "array" + "$ref": "#/components/schemas/LockableFeature_AssetAuditLogConfig_NDQ3MzcyMzk2" } } }, @@ -20886,8 +30146,8 @@ "schema": { "example": { "code": 403, - "label": "access-denied", - "message": "Access denied." + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { @@ -20898,7 +30158,8 @@ }, "label": { "enum": [ - "access-denied" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -20915,28 +30176,57 @@ } } }, - "description": "Access denied. (label: `access-denied`)" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get provider services by provider id" + "summary": "Get config for assetAuditLog" } }, - "/providers/{provider-id}/services/{service-id}": { + "/teams/{tid}/features/cells": { "get": { - "description": " [internal route ID: \"get-provider-services-by-provider-id-and-service-id\"]\n\n", + "description": " [internal route ID: (\"get\", CellsConfigB)]\n\n", + "operationId": "get_CellsConfigB", "parameters": [ { "in": "path", - "name": "provider-id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - }, - { - "in": "path", - "name": "service-id", + "name": "tid", "required": true, "schema": { "format": "uuid", @@ -20949,7 +30239,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ServiceProfile" + "$ref": "#/components/schemas/LockableFeature_CellsConfigB_Bare_Identity_LTgzMDA1NjI3" } } }, @@ -20961,8 +30251,8 @@ "schema": { "example": { "code": 403, - "label": "access-denied", - "message": "Access denied." + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { @@ -20973,7 +30263,8 @@ }, "label": { "enum": [ - "access-denied" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -20990,7 +30281,7 @@ } } }, - "description": "Access denied. (label: `access-denied`)" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, "404": { "content": { @@ -20998,8 +30289,8 @@ "schema": { "example": { "code": 404, - "label": "not-found", - "message": "Service not found." + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { @@ -21010,7 +30301,7 @@ }, "label": { "enum": [ - "not-found" + "no-team" ], "type": "string" }, @@ -21027,87 +30318,66 @@ } } }, - "description": "`provider-id` or `service-id` not found\n\nService not found. (label: `not-found`)" - } - }, - "summary": "Get provider service by provider id and service id" - } - }, - "/proxy/giphy/v1/gifs": {}, - "/proxy/googlemaps/api/staticmap": {}, - "/proxy/googlemaps/maps/api/geocode": {}, - "/proxy/youtube/v3": {}, - "/push/tokens": { - "get": { - "description": " [internal route ID: \"get-push-tokens\"]\n\n", - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/PushTokenList" - } - } - }, - "description": "" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "List the user's registered push tokens" + "summary": "Get config for cells" }, - "post": { - "description": " [internal route ID: \"register-push-token\"]\n\n", + "put": { + "description": " [internal route ID: (\"put\", CellsConfigB)]\n\n", + "operationId": "put_CellsConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/PushToken" + "$ref": "#/components/schemas/Feature_CellsConfigB_Bare_Identity_NzU2NjgxNzEw" } } }, "required": true }, "responses": { - "201": { + "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PushToken" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/PushToken" + "$ref": "#/components/schemas/LockableFeature_CellsConfigB_Bare_Identity_LTgzMDA1NjI3" } } }, - "description": "Push token registered", - "headers": { - "Location": { - "schema": { - "type": "string" - } - } - } + "description": "" }, - "400": { + "403": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "apns-voip-not-supported", - "message": "Adding APNS_VOIP tokens is not supported" + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "apns-voip-not-supported" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -21122,24 +30392,29 @@ ], "type": "object" } - }, + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "apns-voip-not-supported", - "message": "Adding APNS_VOIP tokens is not supported" + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 400 + 404 ], "type": "integer" }, "label": { "enum": [ - "apns-voip-not-supported" + "no-team" ], "type": "string" }, @@ -21156,28 +30431,58 @@ } } }, - "description": "Adding APNS_VOIP tokens is not supported (label: `apns-voip-not-supported`) or `body`" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for cells" + } + }, + "/teams/{tid}/features/cellsInternal": { + "get": { + "description": " [internal route ID: (\"get\", CellsInternalConfigB)]\n\n", + "operationId": "get_CellsInternalConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_CsInfigBdy_LTQ3MTU3Mjg0" + } + } + }, + "description": "" }, - "404": { + "403": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "app-not-found", - "message": "App does not exist" + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "app-not-found", - "invalid-token" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -21192,13 +30497,18 @@ ], "type": "object" } - }, + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { "code": 404, - "label": "app-not-found", - "message": "App does not exist" + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { @@ -21209,8 +30519,7 @@ }, "label": { "enum": [ - "app-not-found", - "invalid-token" + "no-team" ], "type": "string" }, @@ -21227,29 +30536,58 @@ } } }, - "description": "App does not exist (label: `app-not-found`)\n\nInvalid push token (label: `invalid-token`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for cellsInternal" + } + }, + "/teams/{tid}/features/channels": { + "get": { + "description": " [internal route ID: (\"get\", ChannelsConfigB)]\n\n", + "operationId": "get_ChannelsConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_ChannelsConfigB_Bare_Identity_NzA2NDEyMDEw" + } + } + }, + "description": "" }, - "413": { + "403": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { - "code": 413, - "label": "sns-thread-budget-reached", - "message": "Too many concurrent calls to SNS; is SNS down?" + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 413 + 403 ], "type": "integer" }, "label": { "enum": [ - "sns-thread-budget-reached", - "token-too-long", - "metadata-too-long" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -21264,26 +30602,29 @@ ], "type": "object" } - }, + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 413, - "label": "sns-thread-budget-reached", - "message": "Too many concurrent calls to SNS; is SNS down?" + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 413 + 404 ], "type": "integer" }, "label": { "enum": [ - "sns-thread-budget-reached", - "token-too-long", - "metadata-too-long" + "no-team" ], "type": "string" }, @@ -21300,49 +30641,66 @@ } } }, - "description": "Too many concurrent calls to SNS; is SNS down? (label: `sns-thread-budget-reached`)\n\nPush token length must be < 8192 for GCM or 400 for APNS (label: `token-too-long`)\n\nTried to add token to endpoint resulting in metadata length > 2048 (label: `metadata-too-long`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Register a native push token" - } - }, - "/push/tokens/{pid}": { - "delete": { - "description": " [internal route ID: \"delete-push-token\"]\n\n", + "summary": "Get config for channels" + }, + "put": { + "description": " [internal route ID: (\"put\", ChannelsConfigB)]\n\n", + "operationId": "put_ChannelsConfigB", "parameters": [ { - "description": "The push token to delete", "in": "path", - "name": "pid", + "name": "tid", "required": true, "schema": { + "format": "uuid", "type": "string" } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_ChannelsConfigB_Bare_Identity_LTU4NTE4MTgx" + } + } + }, + "required": true + }, "responses": { - "204": { - "description": "Push token unregistered" + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_ChannelsConfigB_Bare_Identity_NzA2NDEyMDEw" + } + } + }, + "description": "" }, - "404": { + "403": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "not-found", - "message": "Push token not found" + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "not-found" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -21357,13 +30715,18 @@ ], "type": "object" } - }, + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { "code": 404, - "label": "not-found", - "message": "Push token not found" + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { @@ -21374,7 +30737,7 @@ }, "label": { "enum": [ - "not-found" + "no-team" ], "type": "string" }, @@ -21391,111 +30754,58 @@ } } }, - "description": "`pid` or Push token not found (label: `not-found`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Unregister a native push token" + "summary": "Put config for channels" } }, - "/register": { - "post": { - "description": " [internal route ID: \"register\"]\n\nIf the environment where the registration takes place is private and a registered email address is not whitelisted, a 403 error is returned.Calls federation service brig on send-connection-action", - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/NewUser" - } + "/teams/{tid}/features/chatBubbles": { + "get": { + "description": " [internal route ID: (\"get\", ChatBubblesConfig)]\n\n", + "operationId": "get_ChatBubblesConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" } - }, - "required": true - }, + } + ], "responses": { - "201": { + "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/User" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/User" + "$ref": "#/components/schemas/LockableFeature_ChatBubblesConfig_NDgwMTQzNjI2" } } }, - "description": "User created and pending activation", - "headers": { - "Location": { - "description": "UserId", - "schema": { - "format": "uuid", - "type": "string" - } - }, - "Set-Cookie": { - "description": "Cookie", - "schema": { - "type": "string" - } - } - } + "description": "" }, - "400": { + "403": { "content": { - "application/json": { - "schema": { - "example": { - "code": 400, - "label": "invalid-invitation-code", - "message": "Invalid invitation code." - }, - "properties": { - "code": { - "enum": [ - 400 - ], - "type": "integer" - }, - "label": { - "enum": [ - "invalid-invitation-code", - "invalid-email", - "invalid-phone" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } - }, "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "invalid-invitation-code", - "message": "Invalid invitation code." + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "invalid-invitation-code", - "invalid-email", - "invalid-phone" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -21512,31 +30822,27 @@ } } }, - "description": "Invalid invitation code. (label: `invalid-invitation-code`)\n\nInvalid e-mail address. (label: `invalid-email`)\n\nInvalid mobile phone number (label: `invalid-phone`) or `body`" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, - "403": { + "404": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "unauthorized", - "message": "Unauthorized e-mail address" + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "unauthorized", - "missing-identity", - "blacklisted-email", - "too-many-team-members", - "user-creation-restricted" + "no-team" ], "type": "string" }, @@ -21551,13 +30857,48 @@ ], "type": "object" } - }, + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for chatBubbles" + } + }, + "/teams/{tid}/features/classifiedDomains": { + "get": { + "description": " [internal route ID: (\"get\", ClassifiedDomainsConfig)]\n\n", + "operationId": "get_ClassifiedDomainsConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_ClassifiedDomainsConfig_LTY1ODQwODg1" + } + } + }, + "description": "" + }, + "403": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { "code": 403, - "label": "unauthorized", - "message": "Unauthorized e-mail address" + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { @@ -21568,11 +30909,8 @@ }, "label": { "enum": [ - "unauthorized", - "missing-identity", - "blacklisted-email", - "too-many-team-members", - "user-creation-restricted" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -21589,16 +30927,16 @@ } } }, - "description": "Unauthorized e-mail address (label: `unauthorized`)\n\nUsing an invitation code requires registering the given email. (label: `missing-identity`)\n\nThe given e-mail address has been blacklisted due to a permanent bounce or a complaint. (label: `blacklisted-email`)\n\nToo many members in this team. (label: `too-many-team-members`)\n\nThis instance does not allow creation of personal users or teams. (label: `user-creation-restricted`)" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, "404": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { "code": 404, - "label": "invalid-code", - "message": "User does not exist" + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { @@ -21609,7 +30947,7 @@ }, "label": { "enum": [ - "invalid-code" + "no-team" ], "type": "string" }, @@ -21624,24 +30962,60 @@ ], "type": "object" } - }, + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for classifiedDomains" + } + }, + "/teams/{tid}/features/conferenceCalling": { + "get": { + "description": " [internal route ID: (\"get\", ConferenceCallingConfigB)]\n\n", + "operationId": "get_ConferenceCallingConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_CnfigBIdy_NzY1NDU5MDAy" + } + } + }, + "description": "" + }, + "403": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "invalid-code", - "message": "User does not exist" + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "invalid-code" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -21658,27 +31032,27 @@ } } }, - "description": "User does not exist (label: `invalid-code`)\n\nInvalid activation code (label: `invalid-code`)" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, - "409": { + "404": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { - "code": 409, - "label": "key-exists", - "message": "The given e-mail address is in use." + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 409 + 404 ], "type": "integer" }, "label": { "enum": [ - "key-exists" + "no-team" ], "type": "string" }, @@ -21693,24 +31067,68 @@ ], "type": "object" } - }, + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for conferenceCalling" + }, + "put": { + "description": " [internal route ID: (\"put\", ConferenceCallingConfigB)]\n\n", + "operationId": "put_ConferenceCallingConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_ConferenceCallingConfigB_Bare_Identity_Njc2NTcxNTI3" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_CnfigBIdy_NzY1NDU5MDAy" + } + } + }, + "description": "" + }, + "403": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 409, - "label": "key-exists", - "message": "The given e-mail address is in use." + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 409 + 403 ], "type": "integer" }, "label": { "enum": [ - "key-exists" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -21727,50 +31145,27 @@ } } }, - "description": "The given e-mail address is in use. (label: `key-exists`)" - } - }, - "summary": "Register a new user." - } - }, - "/scim/auth-tokens": { - "delete": { - "parameters": [ - { - "in": "query", - "name": "id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "code-authentication-required", - "message": "Code authentication is required" + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "code-authentication-required", - "code-authentication-failed", - "password-authentication-failed" + "no-team" ], "type": "string" }, @@ -21787,17 +31182,33 @@ } } }, - "description": "Code authentication is required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nPassword authentication failed. (label: `password-authentication-failed`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } - } - }, + }, + "summary": "Put config for conferenceCalling" + } + }, + "/teams/{tid}/features/consumableNotifications": { "get": { + "description": " [internal route ID: (\"get\", ConsumableNotificationsConfig)]\n\n", + "operationId": "get_ConsumableNotificationsConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ScimTokenList" + "$ref": "#/components/schemas/LockableFeature_ConsumableNotificationsConfig_MjUxMjczMjM0" } } }, @@ -21809,8 +31220,8 @@ "schema": { "example": { "code": 403, - "label": "code-authentication-required", - "message": "Code authentication is required" + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { @@ -21821,9 +31232,8 @@ }, "label": { "enum": [ - "code-authentication-required", - "code-authentication-failed", - "password-authentication-failed" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -21840,53 +31250,27 @@ } } }, - "description": "Code authentication is required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nPassword authentication failed. (label: `password-authentication-failed`)" - } - } - }, - "post": { - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/CreateScimToken" - } - } - }, - "required": true - }, - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/CreateScimTokenResponse" - } - } - }, - "description": "" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "code-authentication-required", - "message": "Code authentication is required" + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "code-authentication-required", - "code-authentication-failed", - "password-authentication-failed" + "no-team" ], "type": "string" }, @@ -21903,44 +31287,25 @@ } } }, - "description": "Code authentication is required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nPassword authentication failed. (label: `password-authentication-failed`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } - } + }, + "summary": "Get config for consumableNotifications" } }, - "/search/contacts": { + "/teams/{tid}/features/conversationGuestLinks": { "get": { - "description": " [internal route ID: \"search-contacts\"]\n\nCalls federation service brig on search-users
Calls federation service brig on get-users-by-ids", + "description": " [internal route ID: (\"get\", GuestLinksConfig)]\n\n", + "operationId": "get_GuestLinksConfig", "parameters": [ { - "description": "Search query", - "in": "query", - "name": "q", + "in": "path", + "name": "tid", "required": true, "schema": { + "format": "uuid", "type": "string" } - }, - { - "description": "Searched domain. Note: This is optional only for backwards compatibility, future versions will mandate this.", - "in": "query", - "name": "domain", - "required": false, - "schema": { - "type": "string" - } - }, - { - "description": "Number of results to return (min: 1, max: 500, default 15)", - "in": "query", - "name": "size", - "required": false, - "schema": { - "format": "int32", - "maximum": 500, - "minimum": 1, - "type": "integer" - } } ], "responses": { @@ -21948,67 +31313,32 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/SearchResult" + "$ref": "#/components/schemas/LockableFeature_GuestLinksConfig_LTcwNjU0NDMw" } } }, "description": "" - } - }, - "summary": "Search for users" - } - }, - "/self": { - "delete": { - "description": " [internal route ID: \"delete-self\"]\n\nif the account has a verified identity, a verification code is sent and needs to be confirmed to authorise the deletion. if the account has no verified identity but a password, it must be provided. if password is correct, or if neither a verified identity nor a password exists, account deletion is scheduled immediately.Calls federation service brig on send-connection-action", - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/DeleteUser" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Deletion is initiated." - }, - "202": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeletionCodeTimeout" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/DeletionCodeTimeout" - } - } - }, - "description": "Deletion is pending verification with a code." }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "invalid-user", - "message": "Invalid user" + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "invalid-user" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -22025,31 +31355,27 @@ } } }, - "description": "Invalid `body`\n\nInvalid user (label: `invalid-user`)" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "no-self-delete-for-team-owner", - "message": "Team owners are not allowed to delete themselves; ask a fellow owner" + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "no-self-delete-for-team-owner", - "pending-delete", - "missing-auth", - "invalid-credentials", - "invalid-code" + "no-team" ], "type": "string" }, @@ -22066,34 +31392,30 @@ } } }, - "description": "Team owners are not allowed to delete themselves; ask a fellow owner (label: `no-self-delete-for-team-owner`)\n\nA verification code for account deletion is still pending (label: `pending-delete`)\n\nRe-authentication via password required (label: `missing-auth`)\n\nAuthentication failed (label: `invalid-credentials`)\n\nInvalid verification code (label: `invalid-code`)" - } - }, - "summary": "Initiate account deletion." - }, - "get": { - "description": " [internal route ID: \"get-self\"]\n\n\nOAuth scope: `read:self`", - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/User" - } - } - }, - "description": "" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get your own profile" + "summary": "Get config for conversationGuestLinks" }, "put": { - "description": " [internal route ID: \"put-self\"]\n\nCalls federation service brig on send-connection-action", + "description": " [internal route ID: (\"put\", GuestLinksConfig)]\n\n", + "operationId": "put_GuestLinksConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/UserUpdate" + "$ref": "#/components/schemas/Feature_GuestLinksConfig_NjQyMDMxNjg3" } } }, @@ -22101,27 +31423,23 @@ }, "responses": { "200": { - "description": "User updated" - } - }, - "summary": "Update your profile." - } - }, - "/self/email": { - "delete": { - "description": " [internal route ID: \"remove-email\"]\n\nYour email address can only be removed if you also have a phone number.Calls federation service brig on send-connection-action", - "responses": { - "200": { - "description": "Identity Removed" + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_GuestLinksConfig_LTcwNjU0NDMw" + } + } + }, + "description": "" }, "403": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { "code": 403, - "label": "last-identity", - "message": "The last user identity cannot be removed." + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { @@ -22132,9 +31450,8 @@ }, "label": { "enum": [ - "last-identity", - "no-password", - "no-identity" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -22149,26 +31466,29 @@ ], "type": "object" } - }, + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "last-identity", - "message": "The last user identity cannot be removed." + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "last-identity", - "no-password", - "no-identity" + "no-team" ], "type": "string" }, @@ -22185,91 +31505,46 @@ } } }, - "description": "The last user identity cannot be removed. (label: `last-identity`)\n\nThe user has no password. (label: `no-password`)\n\nThe user has no verified email (label: `no-identity`)" - } - }, - "summary": "Remove your email address." - } - }, - "/self/handle": { - "put": { - "description": " [internal route ID: \"change-handle\"]\n\nCalls federation service brig on send-connection-action
Calls federation service brig on send-connection-action", - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/HandleUpdate" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Handle Changed" - } - }, - "summary": "Change your handle." - } - }, - "/self/locale": { - "put": { - "description": " [internal route ID: \"change-locale\"]\n\nCalls federation service brig on send-connection-action", - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/LocaleUpdate" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Local Changed" - } - }, - "summary": "Change your locale." - } - }, - "/self/password": { - "head": { - "description": " [internal route ID: \"check-password-exists\"]\n\n", - "responses": { - "200": { - "description": "Password is set" - }, - "404": { - "description": "Password is not set" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Check that your password is set." - }, - "put": { - "description": " [internal route ID: \"change-password\"]\n\n", - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/PasswordChange" - } + "summary": "Put config for conversationGuestLinks" + } + }, + "/teams/{tid}/features/digitalSignatures": { + "get": { + "description": " [internal route ID: (\"get\", DigitalSignaturesConfig)]\n\n", + "operationId": "get_DigitalSignaturesConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" } - }, - "required": true - }, + } + ], "responses": { "200": { - "description": "Password Changed" + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_DigitalSignaturesConfig_ODM2MDA2NDU4" + } + } + }, + "description": "" }, "403": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { "code": 403, - "label": "invalid-credentials", - "message": "Authentication failed" + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { @@ -22280,8 +31555,8 @@ }, "label": { "enum": [ - "invalid-credentials", - "no-identity" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -22296,25 +31571,29 @@ ], "type": "object" } - }, + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "invalid-credentials", - "message": "Authentication failed" + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "invalid-credentials", - "no-identity" + "no-team" ], "type": "string" }, @@ -22331,27 +31610,58 @@ } } }, - "description": "Authentication failed (label: `invalid-credentials`)\n\nThe user has no verified email (label: `no-identity`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for digitalSignatures" + } + }, + "/teams/{tid}/features/domainRegistration": { + "get": { + "description": " [internal route ID: (\"get\", DomainRegistrationConfig)]\n\n", + "operationId": "get_DomainRegistrationConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_DomainRegistrationConfig_NzU0NjczNTE0" + } + } + }, + "description": "" }, - "409": { + "403": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { - "code": 409, - "label": "password-must-differ", - "message": "For password change, new and old password must be different." + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 409 + 403 ], "type": "integer" }, "label": { "enum": [ - "password-must-differ" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -22366,24 +31676,29 @@ ], "type": "object" } - }, + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 409, - "label": "password-must-differ", - "message": "For password change, new and old password must be different." + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 409 + 404 ], "type": "integer" }, "label": { "enum": [ - "password-must-differ" + "no-team" ], "type": "string" }, @@ -22400,96 +31715,25 @@ } } }, - "description": "For password change, new and old password must be different. (label: `password-must-differ`)" - } - }, - "summary": "Change your password." - } - }, - "/self/supported-protocols": { - "put": { - "description": " [internal route ID: \"change-supported-protocols\"]\n\n", - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/SupportedProtocolUpdate" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Supported protocols changed" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Change your supported protocols" + "summary": "Get config for domainRegistration" } }, - "/services": { + "/teams/{tid}/features/enforceFileDownloadLocation": { "get": { - "description": " [internal route ID: \"get-services\"]\n\n", + "description": " [internal route ID: (\"get\", EnforceFileDownloadLocationConfigB)]\n\n

Custom feature: only supported on some dedicated on-prem systems.

", + "operationId": "get_EnforceFileDownloadLocationConfigB", "parameters": [ { - "in": "query", - "name": "tags", - "required": false, - "schema": { - "enum": [ - "audio", - "books", - "business", - "design", - "education", - "entertainment", - "finance", - "fitness", - "food-drink", - "games", - "graphics", - "health", - "integration", - "lifestyle", - "media", - "medical", - "movies", - "music", - "news", - "photography", - "poll", - "productivity", - "quiz", - "rating", - "shopping", - "social", - "sports", - "travel", - "tutorial", - "video", - "weather" - ], - "type": "string" - } - }, - { - "in": "query", - "name": "start", - "required": false, + "in": "path", + "name": "tid", + "required": true, "schema": { + "format": "uuid", "type": "string" } - }, - { - "in": "query", - "name": "size", - "required": false, - "schema": { - "format": "int32", - "maximum": 100, - "minimum": 10, - "type": "integer" - } } ], "responses": { @@ -22497,7 +31741,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ServiceProfile" + "$ref": "#/components/schemas/LockableFtur_EnfiDwdCgBIy_ODA5OTA5MTQ4" } } }, @@ -22509,8 +31753,8 @@ "schema": { "example": { "code": 403, - "label": "access-denied", - "message": "Access denied." + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { @@ -22521,7 +31765,8 @@ }, "label": { "enum": [ - "access-denied" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -22538,36 +31783,55 @@ } } }, - "description": "Access denied. (label: `access-denied`)" - } - }, - "summary": "List services" - } - }, - "/sso/finalize-login": { - "post": { - "deprecated": true, - "description": "DEPRECATED! use /sso/metadata/:tid instead! Details: https://docs.wire.com/understand/single-sign-on/trouble-shooting.html#can-i-use-the-same-sso-login-code-for-multiple-teams", - "responses": { - "200": { + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { "content": { - "text/plain;charset=utf-8": { + "application/json;charset=utf-8": { "schema": { - "type": "string" + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } - } - } - }, - "/sso/finalize-login/{team}": { - "post": { + }, + "summary": "Get config for enforceFileDownloadLocation" + }, + "put": { + "description": " [internal route ID: (\"put\", EnforceFileDownloadLocationConfigB)]\n\n

Custom feature: only supported on some dedicated on-prem systems.

", + "operationId": "put_EnforceFileDownloadLocationConfigB", "parameters": [ { "in": "path", - "name": "team", + "name": "tid", "required": true, "schema": { "format": "uuid", @@ -22575,124 +31839,114 @@ } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Featur_EnfocilDwdLCgBIy_MjcxMzc1NDA5" + } + } + }, + "required": true + }, "responses": { "200": { "content": { - "text/plain;charset=utf-8": { + "application/json;charset=utf-8": { "schema": { - "type": "string" + "$ref": "#/components/schemas/LockableFtur_EnfiDwdCgBIy_ODA5OTA5MTQ4" } } }, "description": "" - } - } - } - }, - "/sso/initiate-login/{idp}": { - "get": { - "parameters": [ - { - "in": "query", - "name": "success_redirect", - "required": false, - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "error_redirect", - "required": false, - "schema": { - "type": "string" - } }, - { - "in": "path", - "name": "idp", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { + "403": { "content": { - "text/html": { + "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/FormRedirect" + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "" - } - } - }, - "head": { - "parameters": [ - { - "in": "query", - "name": "success_redirect", - "required": false, - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "error_redirect", - "required": false, - "schema": { - "type": "string" - } + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, - { - "in": "path", - "name": "idp", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "text/plain;charset=utf-8": {} - }, - "description": "" - } - } - } - }, - "/sso/metadata": { - "get": { - "deprecated": true, - "description": "DEPRECATED! use /sso/metadata/:tid instead! Details: https://docs.wire.com/understand/single-sign-on/trouble-shooting.html#can-i-use-the-same-sso-login-code-for-multiple-teams", - "responses": { - "200": { + "404": { "content": { - "application/xml": { + "application/json;charset=utf-8": { "schema": { - "type": "string" + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } - } + }, + "summary": "Put config for enforceFileDownloadLocation" } }, - "/sso/metadata/{team}": { + "/teams/{tid}/features/exposeInvitationURLsToTeamAdmin": { "get": { + "description": " [internal route ID: (\"get\", ExposeInvitationURLsToTeamAdminConfig)]\n\n", + "operationId": "get_ExposeInvitationURLsToTeamAdminConfig", "parameters": [ { "in": "path", - "name": "team", + "name": "tid", "required": true, "schema": { "format": "uuid", @@ -22700,109 +31954,150 @@ } } ], - "responses": { - "200": { - "content": { - "application/xml": { - "schema": { - "type": "string" - } - } - }, - "description": "" - } - } - } - }, - "/sso/settings": { - "get": { "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/SsoSettings" + "$ref": "#/components/schemas/LockableFtur_ExpsInviURTmAdCfg_LTQzMzU2OTY1" } } }, "description": "" - } - } - } - }, - "/system/settings": { - "get": { - "description": " [internal route ID: \"get-system-settings\"]\n\n", - "responses": { - "200": { + }, + "403": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/SystemSettings" + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } - }, - "description": "" - } - }, - "summary": "Returns a curated set of system configuration settings for authorized users." - } - }, - "/system/settings/unauthorized": { - "get": { - "description": " [internal route ID: \"get-system-settings-unauthorized\"]\n\n", - "responses": { - "200": { + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/SystemSettingsPublic" + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Returns a curated set of system configuration settings." - } - }, - "/teams/invitations/by-email": { - "head": { - "description": " [internal route ID: \"head-team-invitations\"]\n\n", + "summary": "Get config for exposeInvitationURLsToTeamAdmin" + }, + "put": { + "description": " [internal route ID: (\"put\", ExposeInvitationURLsToTeamAdminConfig)]\n\n", + "operationId": "put_ExposeInvitationURLsToTeamAdminConfig", "parameters": [ { - "description": "Email address", - "in": "query", - "name": "email", + "in": "path", + "name": "tid", "required": true, "schema": { + "format": "uuid", "type": "string" } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_ExposeInvitationURLsToTeamAdminConfig_LTY5NzY2Mzg5" + } + } + }, + "required": true + }, "responses": { "200": { - "description": "Pending invitation exists." + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_ExpsInviURTmAdCfg_LTQzMzU2OTY1" + } + } + }, + "description": "" }, - "404": { + "403": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "not-found", - "message": "No pending invitations exists." + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "not-found" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -22817,13 +32112,18 @@ ], "type": "object" } - }, + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { "code": 404, - "label": "not-found", - "message": "No pending invitations exists." + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { @@ -22834,7 +32134,7 @@ }, "label": { "enum": [ - "not-found" + "no-team" ], "type": "string" }, @@ -22851,27 +32151,58 @@ } } }, - "description": "No pending invitations exists. (label: `not-found`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for exposeInvitationURLsToTeamAdmin" + } + }, + "/teams/{tid}/features/fileSharing": { + "get": { + "description": " [internal route ID: (\"get\", FileSharingConfig)]\n\n", + "operationId": "get_FileSharingConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_FileSharingConfig_MjgwNjIzODEz" + } + } + }, + "description": "" }, - "409": { + "403": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { "example": { - "code": 409, - "label": "conflicting-invitations", - "message": "Multiple conflicting invitations to different teams exists." + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 409 + 403 ], "type": "integer" }, "label": { "enum": [ - "conflicting-invitations" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -22886,24 +32217,29 @@ ], "type": "object" } - }, + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 409, - "label": "conflicting-invitations", - "message": "Multiple conflicting invitations to different teams exists." + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 409 + 404 ], "type": "integer" }, "label": { "enum": [ - "conflicting-invitations" + "no-team" ], "type": "string" }, @@ -22920,61 +32256,103 @@ } } }, - "description": "Multiple conflicting invitations to different teams exists. (label: `conflicting-invitations`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Check if there is an invitation pending given an email address." - } - }, - "/teams/invitations/info": { - "get": { - "description": " [internal route ID: \"get-team-invitation-info\"]\n\n", + "summary": "Get config for fileSharing" + }, + "put": { + "description": " [internal route ID: (\"put\", FileSharingConfig)]\n\n", + "operationId": "put_FileSharingConfig", "parameters": [ { - "description": "Invitation code", - "in": "query", - "name": "code", + "in": "path", + "name": "tid", "required": true, "schema": { + "format": "uuid", "type": "string" } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_FileSharingConfig_LTUyNjkxMzM4" + } + } + }, + "required": true + }, "responses": { "200": { "content": { - "application/json": { + "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Invitation" + "$ref": "#/components/schemas/LockableFeature_FileSharingConfig_MjgwNjIzODEz" } - }, + } + }, + "description": "" + }, + "403": { + "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Invitation" + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "Invitation info" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, - "400": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "invalid-invitation-code", - "message": "Invalid invitation code." + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 400 + 404 ], "type": "integer" }, "label": { "enum": [ - "invalid-invitation-code" + "no-team" ], "type": "string" }, @@ -22991,37 +32369,25 @@ } } }, - "description": "Invalid `code`\n\nInvalid invitation code. (label: `invalid-invitation-code`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get invitation info given a code." + "summary": "Put config for fileSharing" } }, - "/teams/notifications": { + "/teams/{tid}/features/legalhold": { "get": { - "description": " [internal route ID: \"get-team-notifications\"]\n\nThis is a work-around for scalability issues with gundeck user event fan-out. It does not track all team-wide events, but only `member-join`.\nNote that `/teams/notifications` behaves differently from `/notifications`:\n- If there is a gap between the notification id requested with `since` and the available data, team queues respond with 200 and the data that could be found. They do NOT respond with status 404, but valid data in the body.\n- The notification with the id given via `since` is included in the response if it exists. You should remove this and only use it to decide whether there was a gap between your last request and this one.\n- If the notification id does *not* exist, you get the more recent events from the queue (instead of all of them). This can be done because a notification id is a UUIDv1, which is essentially a time stamp.\n- There is no corresponding `/last` end-point to get only the most recent event. That end-point was only useful to avoid having to pull the entire queue. In team queues, if you have never requested the queue before and have no prior notification id, just pull with timestamp 'now'.", + "description": " [internal route ID: (\"get\", LegalholdConfig)]\n\n", + "operationId": "get_LegalholdConfig", "parameters": [ { - "description": "Notification id to start with in the response (UUIDv1)", - "in": "query", - "name": "since", - "required": false, + "in": "path", + "name": "tid", + "required": true, "schema": { "format": "uuid", "type": "string" } - }, - { - "description": "Maximum number of events to return (1..10000; default: 1000)", - "in": "query", - "name": "size", - "required": false, - "schema": { - "format": "int32", - "maximum": 10000, - "minimum": 1, - "type": "integer" - } } ], "responses": { @@ -23029,31 +32395,32 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/QueuedNotificationList" + "$ref": "#/components/schemas/LockableFeature_LegalholdConfig_LTc5MTk5OTIw" } } }, "description": "" }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "invalid-notification-id", - "message": "Could not parse notification id (must be UUIDv1)." + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "invalid-notification-id" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -23070,7 +32437,7 @@ } } }, - "description": "Invalid `size` or `since`\n\nCould not parse notification id (must be UUIDv1). (label: `invalid-notification-id`)" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, "404": { "content": { @@ -23107,19 +32474,18 @@ } } }, - "description": "Team not found (label: `no-team`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Read recently added team members from team queue" - } - }, - "/teams/{team-id}/services/whitelist": { - "post": { - "description": " [internal route ID: \"post-team-whitelist-by-team-id\"]\n\n", + "summary": "Get config for legalhold" + }, + "put": { + "description": " [internal route ID: (\"put\", LegalholdConfig)]\n\n", + "operationId": "put_LegalholdConfig", "parameters": [ { "in": "path", - "name": "team-id", + "name": "tid", "required": true, "schema": { "format": "uuid", @@ -23131,108 +32497,59 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/UpdateServiceWhitelist" + "$ref": "#/components/schemas/Feature_LegalholdConfig_NjM3MTkxNjYw" } } }, "required": true }, - "responses": { - "200": { - "description": "UpdateServiceWhitelistRespChanged" - }, - "204": { - "description": "UpdateServiceWhitelistRespUnchanged" - } - }, - "summary": "Update service whitelist" - } - }, - "/teams/{team-id}/services/whitelisted": { - "get": { - "description": " [internal route ID: \"get-whitelisted-services-by-team-id\"]\n\n", - "parameters": [ - { - "in": "path", - "name": "team-id", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - }, - { - "in": "query", - "name": "prefix", - "required": false, - "schema": { - "maxLength": 1, - "minLength": 128, - "type": "string" - } - }, - { - "in": "query", - "name": "filter_disabled", - "required": false, - "schema": { - "type": "boolean" - } - }, - { - "in": "query", - "name": "size", - "required": false, - "schema": { - "format": "int32", - "maximum": 100, - "minimum": 10, - "type": "integer" - } - } - ], "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ServiceProfile" + "$ref": "#/components/schemas/LockableFeature_LegalholdConfig_LTc5MTk5OTIw" } } }, "description": "" - } - }, - "summary": "Get whitelisted services by team id" - } - }, - "/teams/{tid}": { - "delete": { - "description": " [internal route ID: \"delete-team\"]\n\n", - "parameters": [ - { - "in": "path", - "name": "tid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/TeamDeleteData" - } - } }, - "required": true - }, - "responses": { - "202": { - "description": "Team is scheduled for removal" + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "legalhold-not-registered", + "message": "legal hold service has not been registered for this team" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-not-registered" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nlegal hold service has not been registered for this team (label: `legalhold-not-registered`)" }, "403": { "content": { @@ -23240,8 +32557,8 @@ "schema": { "example": { "code": 403, - "label": "code-authentication-required", - "message": "Verification code required" + "label": "legalhold-disable-unimplemented", + "message": "legal hold cannot be disabled for whitelisted teams" }, "properties": { "code": { @@ -23252,11 +32569,12 @@ }, "label": { "enum": [ - "code-authentication-required", - "code-authentication-failed", - "access-denied", - "operation-denied", - "no-team-member" + "legalhold-disable-unimplemented", + "legalhold-not-enabled", + "too-large-team-for-legalhold", + "action-denied", + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -23273,7 +32591,7 @@ } } }, - "description": "Verification code required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nThis operation requires reauthentication (label: `access-denied`)\n\nInsufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (missing DeleteTeam) (label: `operation-denied`)" + "description": "legal hold cannot be disabled for whitelisted teams (label: `legalhold-disable-unimplemented`)\n\nlegal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nCannot enable legalhold on large teams (reason: for removing LH from team, we need to iterate over all members, which is only supported for teams with less than 2k members) (label: `too-large-team-for-legalhold`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, "404": { "content": { @@ -23312,25 +32630,26 @@ }, "description": "`tid` not found\n\nTeam not found (label: `no-team`)" }, - "503": { + "500": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 503, - "label": "queue-full", - "message": "The delete queue is full; no further delete requests can be processed at the moment" + "code": 500, + "label": "legalhold-internal", + "message": "legal hold service: could not block connections when resolving policy conflicts." }, "properties": { "code": { "enum": [ - 503 + 500 ], "type": "integer" }, "label": { "enum": [ - "queue-full" + "legalhold-internal", + "legalhold-illegal-op" ], "type": "string" }, @@ -23347,13 +32666,16 @@ } } }, - "description": "The delete queue is full; no further delete requests can be processed at the moment (label: `queue-full`)" + "description": "legal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)\n\ninternal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)" } }, - "summary": "Delete a team" - }, + "summary": "Put config for legalhold" + } + }, + "/teams/{tid}/features/limitedEventFanout": { "get": { - "description": " [internal route ID: \"get-team\"]\n\n", + "description": " [internal route ID: (\"get\", LimitedEventFanoutConfig)]\n\n", + "operationId": "get_LimitedEventFanoutConfig", "parameters": [ { "in": "path", @@ -23370,31 +32692,32 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Team" + "$ref": "#/components/schemas/LockableFeature_LimitedEventFanoutConfig_MTg3ODM0NzU0" } } }, "description": "" }, - "404": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-team", - "message": "Team not found" + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "no-team" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -23411,58 +32734,27 @@ } } }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" - } - }, - "summary": "Get a team by ID" - }, - "put": { - "description": " [internal route ID: \"update-team\"]\n\n", - "parameters": [ - { - "in": "path", - "name": "tid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/TeamUpdateData" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Team updated" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "operation-denied", - "message": "Insufficient permissions (missing SetTeamData)" + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "operation-denied", - "no-team-member" + "no-team" ], "type": "string" }, @@ -23479,15 +32771,16 @@ } } }, - "description": "Insufficient permissions (missing SetTeamData) (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Update team properties" + "summary": "Get config for limitedEventFanout" } }, - "/teams/{tid}/conversations": { + "/teams/{tid}/features/meetings": { "get": { - "description": " [internal route ID: \"get-team-conversations\"]\n\n", + "description": " [internal route ID: (\"get\", MeetingsConfig)]\n\n", + "operationId": "get_MeetingsConfig", "parameters": [ { "in": "path", @@ -23504,7 +32797,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/TeamConversationList" + "$ref": "#/components/schemas/LockableFeature_MeetingsConfig_LTE0OTQ5Nzcw" } } }, @@ -23547,142 +32840,6 @@ } }, "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" - } - }, - "summary": "Get team conversations" - } - }, - "/teams/{tid}/conversations/roles": { - "get": { - "description": " [internal route ID: \"get-team-conversation-roles\"]\n\n", - "parameters": [ - { - "in": "path", - "name": "tid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ConversationRolesList" - } - } - }, - "description": "" - }, - "403": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" - }, - "properties": { - "code": { - "enum": [ - 403 - ], - "type": "integer" - }, - "label": { - "enum": [ - "no-team-member" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } - } - }, - "description": "Requesting user is not a team member (label: `no-team-member`)" - } - }, - "summary": "Get existing roles available for the given team" - } - }, - "/teams/{tid}/conversations/{cid}": { - "delete": { - "description": " [internal route ID: \"delete-team-conversation\"]\n\nCalls federation service brig on get-users-by-ids
Calls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated", - "parameters": [ - { - "in": "path", - "name": "tid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - }, - { - "in": "path", - "name": "cid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Conversation deleted" - }, - "403": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" - }, - "properties": { - "code": { - "enum": [ - 403 - ], - "type": "integer" - }, - "label": { - "enum": [ - "no-team-member", - "invalid-op", - "action-denied" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } - } - }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInvalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing delete_conversation) (label: `action-denied`)" }, "404": { "content": { @@ -23690,8 +32847,8 @@ "schema": { "example": { "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { @@ -23702,7 +32859,7 @@ }, "label": { "enum": [ - "no-conversation" + "no-team" ], "type": "string" }, @@ -23719,13 +32876,14 @@ } } }, - "description": "`tid` or `cid` not found\n\nConversation not found (label: `no-conversation`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Remove a team conversation" + "summary": "Get config for meetings" }, - "get": { - "description": " [internal route ID: \"get-team-conversation\"]\n\n", + "put": { + "description": " [internal route ID: (\"put\", MeetingsConfig)]\n\n", + "operationId": "put_MeetingsConfig", "parameters": [ { "in": "path", @@ -23735,23 +32893,24 @@ "format": "uuid", "type": "string" } - }, - { - "in": "path", - "name": "cid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_MeetingsConfig_NDc2MzM0MDE1" + } + } + }, + "required": true + }, "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/TeamConversation" + "$ref": "#/components/schemas/LockableFeature_MeetingsConfig_LTE0OTQ5Nzcw" } } }, @@ -23801,8 +32960,8 @@ "schema": { "example": { "code": 404, - "label": "no-conversation", - "message": "Conversation not found" + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { @@ -23813,7 +32972,7 @@ }, "label": { "enum": [ - "no-conversation" + "no-team" ], "type": "string" }, @@ -23830,15 +32989,16 @@ } } }, - "description": "`tid` or `cid` not found\n\nConversation not found (label: `no-conversation`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get one team conversation" + "summary": "Put config for meetings" } }, - "/teams/{tid}/features": { + "/teams/{tid}/features/mls": { "get": { - "description": " [internal route ID: \"get-all-feature-configs-for-team\"]\n\nGets feature configs for a team. User must be a member of the team and have permission to view team features.", + "description": " [internal route ID: (\"get\", MLSConfigB)]\n\n", + "operationId": "get_MLSConfigB", "parameters": [ { "in": "path", @@ -23855,7 +33015,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/AllTeamFeatures" + "$ref": "#/components/schemas/LockableFeature_MLSConfigB_Bare_Identity_MTg1MTc0NTEw" } } }, @@ -23867,8 +33027,8 @@ "schema": { "example": { "code": 403, - "label": "operation-denied", - "message": "Insufficient permissions" + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { @@ -23879,8 +33039,8 @@ }, "label": { "enum": [ - "operation-denied", - "no-team-member" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -23897,7 +33057,7 @@ } } }, - "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, "404": { "content": { @@ -23937,12 +33097,11 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Gets feature configs for a team" - } - }, - "/teams/{tid}/features/appLock": { - "get": { - "description": " [internal route ID: (\"get\", AppLockConfig)]\n\n", + "summary": "Get config for mls" + }, + "put": { + "description": " [internal route ID: (\"put\", MLSConfigB)]\n\n", + "operationId": "put_MLSConfigB", "parameters": [ { "in": "path", @@ -23954,12 +33113,22 @@ } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_MLSConfigB_Bare_Identity_LTI5MjA3MDYy" + } + } + }, + "required": true + }, "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/AppLockConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFeature_MLSConfigB_Bare_Identity_MTg1MTc0NTEw" } } }, @@ -24041,10 +33210,13 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get config for appLock" - }, - "put": { - "description": " [internal route ID: (\"put\", AppLockConfig)]\n\n", + "summary": "Put config for mls" + } + }, + "/teams/{tid}/features/mlsE2EId": { + "get": { + "description": " [internal route ID: (\"get\", MlsE2EIdConfigB)]\n\n", + "operationId": "get_MlsE2EIdConfigB", "parameters": [ { "in": "path", @@ -24056,22 +33228,12 @@ } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/AppLockConfig.Feature" - } - } - }, - "required": true - }, "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/AppLockConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFeature_MlsE2EIdConfigB_Bare_Identity_MTU2ODkyMDc4" } } }, @@ -24153,12 +33315,11 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Put config for appLock" - } - }, - "/teams/{tid}/features/classifiedDomains": { - "get": { - "description": " [internal route ID: (\"get\", ClassifiedDomainsConfig)]\n\n", + "summary": "Get config for mlsE2EId" + }, + "put": { + "description": " [internal route ID: (\"put\", MlsE2EIdConfigB)]\n\n", + "operationId": "put_MlsE2EIdConfigB", "parameters": [ { "in": "path", @@ -24170,12 +33331,22 @@ } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_MlsE2EIdConfigB_Bare_Identity_LTUxODYzODEx" + } + } + }, + "required": true + }, "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ClassifiedDomainsConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFeature_MlsE2EIdConfigB_Bare_Identity_MTU2ODkyMDc4" } } }, @@ -24257,12 +33428,13 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get config for classifiedDomains" + "summary": "Put config for mlsE2EId" } }, - "/teams/{tid}/features/conferenceCalling": { + "/teams/{tid}/features/mlsMigration": { "get": { - "description": " [internal route ID: (\"get\", ConferenceCallingConfig)]\n\n", + "description": " [internal route ID: (\"get\", MlsMigrationConfigB)]\n\n", + "operationId": "get_MlsMigrationConfigB", "parameters": [ { "in": "path", @@ -24279,7 +33451,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ConferenceCallingConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFtur_MsignCfBIdy_LTE1NjAxNjU2" } } }, @@ -24361,10 +33533,11 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get config for conferenceCalling" + "summary": "Get config for mlsMigration" }, "put": { - "description": " [internal route ID: (\"put\", ConferenceCallingConfig)]\n\n", + "description": " [internal route ID: (\"put\", MlsMigrationConfigB)]\n\n", + "operationId": "put_MlsMigrationConfigB", "parameters": [ { "in": "path", @@ -24380,7 +33553,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ConferenceCallingConfig.Feature" + "$ref": "#/components/schemas/Feature_MlsMigrationConfigB_Bare_Identity_LTQyMDAxMTkz" } } }, @@ -24391,7 +33564,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ConferenceCallingConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFtur_MsignCfBIdy_LTE1NjAxNjU2" } } }, @@ -24473,12 +33646,13 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Put config for conferenceCalling" + "summary": "Put config for mlsMigration" } }, - "/teams/{tid}/features/conversationGuestLinks": { + "/teams/{tid}/features/outlookCalIntegration": { "get": { - "description": " [internal route ID: (\"get\", GuestLinksConfig)]\n\n", + "description": " [internal route ID: (\"get\", OutlookCalIntegrationConfig)]\n\n", + "operationId": "get_OutlookCalIntegrationConfig", "parameters": [ { "in": "path", @@ -24495,7 +33669,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/GuestLinksConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFeature_OutlookCalIntegrationConfig_NjQ0MzMyMzY0" } } }, @@ -24577,10 +33751,11 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get config for conversationGuestLinks" + "summary": "Get config for outlookCalIntegration" }, "put": { - "description": " [internal route ID: (\"put\", GuestLinksConfig)]\n\n", + "description": " [internal route ID: (\"put\", OutlookCalIntegrationConfig)]\n\n", + "operationId": "put_OutlookCalIntegrationConfig", "parameters": [ { "in": "path", @@ -24596,7 +33771,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/GuestLinksConfig.Feature" + "$ref": "#/components/schemas/Feature_OutlookCalIntegrationConfig_LTg0MjIxNTMx" } } }, @@ -24607,7 +33782,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/GuestLinksConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFeature_OutlookCalIntegrationConfig_NjQ0MzMyMzY0" } } }, @@ -24689,12 +33864,13 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Put config for conversationGuestLinks" + "summary": "Put config for outlookCalIntegration" } }, - "/teams/{tid}/features/digitalSignatures": { + "/teams/{tid}/features/preventAdminlessGroups": { "get": { - "description": " [internal route ID: (\"get\", DigitalSignaturesConfig)]\n\n", + "description": " [internal route ID: (\"get\", PreventAdminlessGroupsConfigB)]\n\n", + "operationId": "get_PreventAdminlessGroupsConfigB", "parameters": [ { "in": "path", @@ -24711,7 +33887,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/DigitalSignaturesConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFtur_PvnAdmisGpCfgBIy_MTQxOTU4Mzgw" } } }, @@ -24793,12 +33969,11 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get config for digitalSignatures" - } - }, - "/teams/{tid}/features/enforceFileDownloadLocation": { - "get": { - "description": " [internal route ID: (\"get\", EnforceFileDownloadLocationConfig)]\n\n

Custom feature: only supported on some dedicated on-prem systems.

", + "summary": "Get config for preventAdminlessGroups" + }, + "put": { + "description": " [internal route ID: \"put-PreventAdminlessGroupsConfig@v16\"]\n\n", + "operationId": "put-PreventAdminlessGroupsConfig@v16", "parameters": [ { "in": "path", @@ -24810,12 +33985,22 @@ } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Featur_Vsiond_16PvAmlGpCfgBIy_MjY0MDMyNDA1V16" + } + } + }, + "required": true + }, "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/EnforceFileDownloadLocation.LockableFeature" + "$ref": "#/components/schemas/LockableFtur_PvnAdmisGpCfgBIy_MTQxOTU4Mzgw" } } }, @@ -24897,10 +34082,13 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get config for enforceFileDownloadLocation" - }, - "put": { - "description": " [internal route ID: (\"put\", EnforceFileDownloadLocationConfig)]\n\n

Custom feature: only supported on some dedicated on-prem systems.

", + "summary": "Put config for preventAdminlessGroups" + } + }, + "/teams/{tid}/features/searchVisibility": { + "get": { + "description": " [internal route ID: (\"get\", SearchVisibilityAvailableConfig)]\n\n", + "operationId": "get_SearchVisibilityAvailableConfig", "parameters": [ { "in": "path", @@ -24912,22 +34100,12 @@ } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/EnforceFileDownloadLocation.Feature" - } - } - }, - "required": true - }, "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/EnforceFileDownloadLocation.LockableFeature" + "$ref": "#/components/schemas/LockableFeature_SearchVisibilityAvailableConfig_LTkxMTA5ODk5" } } }, @@ -25009,12 +34187,11 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Put config for enforceFileDownloadLocation" - } - }, - "/teams/{tid}/features/exposeInvitationURLsToTeamAdmin": { - "get": { - "description": " [internal route ID: (\"get\", ExposeInvitationURLsToTeamAdminConfig)]\n\n", + "summary": "Get config for searchVisibility" + }, + "put": { + "description": " [internal route ID: (\"put\", SearchVisibilityAvailableConfig)]\n\n", + "operationId": "put_SearchVisibilityAvailableConfig", "parameters": [ { "in": "path", @@ -25026,12 +34203,22 @@ } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_SearchVisibilityAvailableConfig_LTMzNTkxODI1" + } + } + }, + "required": true + }, "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ExposeInvitationURLsToTeamAdminConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFeature_SearchVisibilityAvailableConfig_LTkxMTA5ODk5" } } }, @@ -25113,10 +34300,13 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get config for exposeInvitationURLsToTeamAdmin" - }, - "put": { - "description": " [internal route ID: (\"put\", ExposeInvitationURLsToTeamAdminConfig)]\n\n", + "summary": "Put config for searchVisibility" + } + }, + "/teams/{tid}/features/searchVisibilityInbound": { + "get": { + "description": " [internal route ID: (\"get\", SearchVisibilityInboundConfig)]\n\n", + "operationId": "get_SearchVisibilityInboundConfig", "parameters": [ { "in": "path", @@ -25128,22 +34318,12 @@ } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ExposeInvitationURLsToTeamAdminConfig.Feature" - } - } - }, - "required": true - }, "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ExposeInvitationURLsToTeamAdminConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFeature_SearchVisibilityInboundConfig_NzA5NzczNTgy" } } }, @@ -25225,12 +34405,11 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Put config for exposeInvitationURLsToTeamAdmin" - } - }, - "/teams/{tid}/features/fileSharing": { - "get": { - "description": " [internal route ID: (\"get\", FileSharingConfig)]\n\n", + "summary": "Get config for searchVisibilityInbound" + }, + "put": { + "description": " [internal route ID: (\"put\", SearchVisibilityInboundConfig)]\n\n", + "operationId": "put_SearchVisibilityInboundConfig", "parameters": [ { "in": "path", @@ -25242,12 +34421,22 @@ } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_SearchVisibilityInboundConfig_MTI1NzQxODY2" + } + } + }, + "required": true + }, "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/FileSharingConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFeature_SearchVisibilityInboundConfig_NzA5NzczNTgy" } } }, @@ -25329,10 +34518,13 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get config for fileSharing" - }, - "put": { - "description": " [internal route ID: (\"put\", FileSharingConfig)]\n\n", + "summary": "Put config for searchVisibilityInbound" + } + }, + "/teams/{tid}/features/selfDeletingMessages": { + "get": { + "description": " [internal route ID: (\"get\", SelfDeletingMessagesConfigB)]\n\n", + "operationId": "get_SelfDeletingMessagesConfigB", "parameters": [ { "in": "path", @@ -25344,22 +34536,12 @@ } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/FileSharingConfig.Feature" - } - } - }, - "required": true - }, "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/FileSharingConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFtur_SfDingMsCBIdy_LTg5MTEwNTA2" } } }, @@ -25441,12 +34623,11 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Put config for fileSharing" - } - }, - "/teams/{tid}/features/legalhold": { - "get": { - "description": " [internal route ID: (\"get\", LegalholdConfig)]\n\n", + "summary": "Get config for selfDeletingMessages" + }, + "put": { + "description": " [internal route ID: (\"put\", SelfDeletingMessagesConfigB)]\n\n", + "operationId": "put_SelfDeletingMessagesConfigB", "parameters": [ { "in": "path", @@ -25458,12 +34639,22 @@ } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Featur_SlfDingMsCoBIdy_LTg2MzYzNjc2" + } + } + }, + "required": true + }, "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/LegalholdConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFtur_SfDingMsCBIdy_LTg5MTEwNTA2" } } }, @@ -25545,10 +34736,13 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get config for legalhold" - }, - "put": { - "description": " [internal route ID: (\"put\", LegalholdConfig)]\n\n", + "summary": "Put config for selfDeletingMessages" + } + }, + "/teams/{tid}/features/simplifiedUserConnectionRequestQRCode": { + "get": { + "description": " [internal route ID: (\"get\", SimplifiedUserConnectionRequestQRCodeConfig)]\n\n", + "operationId": "get_SimplifiedUserConnectionRequestQRCodeConfig", "parameters": [ { "in": "path", @@ -25560,46 +34754,37 @@ } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/LegalholdConfig.Feature" - } - } - }, - "required": true - }, "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/LegalholdConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFtur_SimpfdUsCnRqQg_Njk5NjU4OTgy" } } }, "description": "" }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "legalhold-not-registered", - "message": "legal hold service has not been registered for this team" + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "legalhold-not-registered" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -25616,32 +34801,27 @@ } } }, - "description": "Invalid `body`\n\nlegal hold service has not been registered for this team (label: `legalhold-not-registered`)" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "legalhold-disable-unimplemented", - "message": "legal hold cannot be disabled for whitelisted teams" + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "legalhold-disable-unimplemented", - "legalhold-not-enabled", - "too-large-team-for-legalhold", - "action-denied", - "no-team-member", - "operation-denied" + "no-team" ], "type": "string" }, @@ -25658,27 +34838,58 @@ } } }, - "description": "legal hold cannot be disabled for whitelisted teams (label: `legalhold-disable-unimplemented`)\n\nlegal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nCannot enable legalhold on large teams (reason: for removing LH from team, we need to iterate over all members, which is only supported for teams with less than 2k members) (label: `too-large-team-for-legalhold`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for simplifiedUserConnectionRequestQRCode" + } + }, + "/teams/{tid}/features/sndFactorPasswordChallenge": { + "get": { + "description": " [internal route ID: (\"get\", SndFactorPasswordChallengeConfig)]\n\n", + "operationId": "get_SndFactorPasswordChallengeConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_SndFactorPasswordChallengeConfig_MjQ3NzQ2ODgx" + } + } + }, + "description": "" }, - "404": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-team", - "message": "Team not found" + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "no-team" + "no-team-member", + "operation-denied" ], "type": "string" }, @@ -25695,28 +34906,27 @@ } } }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" }, - "500": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 500, - "label": "legalhold-internal", - "message": "legal hold service: could not block connections when resolving policy conflicts." + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 500 + 404 ], "type": "integer" }, "label": { "enum": [ - "legalhold-internal", - "legalhold-illegal-op" + "no-team" ], "type": "string" }, @@ -25733,15 +34943,14 @@ } } }, - "description": "legal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)\n\ninternal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Put config for legalhold" - } - }, - "/teams/{tid}/features/limitedEventFanout": { - "get": { - "description": " [internal route ID: (\"get\", LimitedEventFanoutConfig)]\n\n", + "summary": "Get config for sndFactorPasswordChallenge" + }, + "put": { + "description": " [internal route ID: (\"put\", SndFactorPasswordChallengeConfig)]\n\n", + "operationId": "put_SndFactorPasswordChallengeConfig", "parameters": [ { "in": "path", @@ -25753,12 +34962,22 @@ } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_SndFactorPasswordChallengeConfig_NDc0MzUyMzQz" + } + } + }, + "required": true + }, "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/LimitedEventFanoutConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFeature_SndFactorPasswordChallengeConfig_MjQ3NzQ2ODgx" } } }, @@ -25840,12 +35059,13 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get config for limitedEventFanout" + "summary": "Put config for sndFactorPasswordChallenge" } }, - "/teams/{tid}/features/mls": { + "/teams/{tid}/features/sso": { "get": { - "description": " [internal route ID: (\"get\", MLSConfig)]\n\n", + "description": " [internal route ID: (\"get\", SSOConfig)]\n\n", + "operationId": "get_SSOConfig", "parameters": [ { "in": "path", @@ -25862,7 +35082,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/MLSConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFeature_SSOConfig_NjcyMjU4MDY2" } } }, @@ -25944,10 +35164,13 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get config for mls" - }, - "put": { - "description": " [internal route ID: (\"put\", MLSConfig)]\n\n", + "summary": "Get config for sso" + } + }, + "/teams/{tid}/features/stealthUsers": { + "get": { + "description": " [internal route ID: (\"get\", StealthUsersConfig)]\n\n", + "operationId": "get_StealthUsersConfig", "parameters": [ { "in": "path", @@ -25959,22 +35182,12 @@ } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/MLSConfig.Feature" - } - } - }, - "required": true - }, "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/MLSConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFeature_StealthUsersConfig_LTE1MTk2NzIz" } } }, @@ -26056,12 +35269,13 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Put config for mls" + "summary": "Get config for stealthUsers" } }, - "/teams/{tid}/features/mlsE2EId": { + "/teams/{tid}/features/validateSAMLemails": { "get": { - "description": " [internal route ID: (\"get\", MlsE2EIdConfig)]\n\n", + "description": " [internal route ID: (\"get\", RequireExternalEmailVerificationConfig)]\n\n

Controls whether externally managed email addresses (from SAML or SCIM) must be verified by the user, or are auto-activated.

The external feature name is kept as validateSAMLemails for backward compatibility. That name is misleading because the feature also applies to SCIM-managed users, and it controls email ownership verification rather than generic email validation.

", + "operationId": "get_RequireExternalEmailVerificationConfig", "parameters": [ { "in": "path", @@ -26078,7 +35292,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/MlsE2EIdConfig.LockableFeature" + "$ref": "#/components/schemas/LockableFtur_RqiExnmVfCg_NjUyMzgzNzY5" } } }, @@ -26160,10 +35374,13 @@ "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get config for mlsE2EId" - }, - "put": { - "description": " [internal route ID: (\"put\", MlsE2EIdConfig)]\n\n", + "summary": "Get config for validateSAMLemails" + } + }, + "/teams/{tid}/get-members-by-ids-using-post": { + "post": { + "description": " [internal route ID: \"get-team-members-by-ids\"]\n\nThe `has_more` field in the response body is always `false`.", + "operationId": "get-team-members-by-ids", "parameters": [ { "in": "path", @@ -26173,13 +35390,25 @@ "format": "uuid", "type": "string" } + }, + { + "description": "Maximum results to be returned", + "in": "query", + "name": "maxResults", + "required": false, + "schema": { + "format": "int32", + "maximum": 2000, + "minimum": 1, + "type": "integer" + } } ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/MlsE2EIdConfig.Feature" + "$ref": "#/components/schemas/UserIdList_MzA1MTI1Njgx" } } }, @@ -26190,32 +35419,31 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/MlsE2EIdConfig.LockableFeature" + "$ref": "#/components/schemas/TeamMemberList_Optional_LTM1ODE2MzM0" } } }, "description": "" }, - "403": { + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "code": 400, + "label": "too-many-uids", + "message": "Can only process 2000 user ids per request." }, "properties": { "code": { "enum": [ - 403 + 400 ], "type": "integer" }, "label": { "enum": [ - "no-team-member", - "operation-denied" + "too-many-uids" ], "type": "string" }, @@ -26232,27 +35460,27 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + "description": "Invalid `body` or `maxResults`\n\nCan only process 2000 user ids per request. (label: `too-many-uids`)" }, - "404": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-team", - "message": "Team not found" + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "no-team" + "no-team-member" ], "type": "string" }, @@ -26269,15 +35497,16 @@ } } }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + "description": "Requesting user is not a team member (label: `no-team-member`)" } }, - "summary": "Put config for mlsE2EId" + "summary": "Get team members by user id list" } }, - "/teams/{tid}/features/mlsMigration": { + "/teams/{tid}/invitations": { "get": { - "description": " [internal route ID: (\"get\", MlsMigrationConfig)]\n\n", + "description": " [internal route ID: \"get-team-invitations\"]\n\n", + "operationId": "get-team-invitations", "parameters": [ { "in": "path", @@ -26287,18 +35516,45 @@ "format": "uuid", "type": "string" } + }, + { + "description": "Invitation id to start from (ascending).", + "in": "query", + "name": "start", + "required": false, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "description": "Number of results to return (default 100, max 500).", + "in": "query", + "name": "size", + "required": false, + "schema": { + "format": "int32", + "maximum": 500, + "minimum": 1, + "type": "integer" + } } ], "responses": { "200": { "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvitationList_ODk4NTQxODc3" + } + }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/MlsMigration.LockableFeature" + "$ref": "#/components/schemas/InvitationList_ODk4NTQxODc3" } } }, - "description": "" + "description": "List of sent invitations" }, "403": { "content": { @@ -26306,8 +35562,8 @@ "schema": { "example": { "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "label": "insufficient-permissions", + "message": "Insufficient team permissions" }, "properties": { "code": { @@ -26318,45 +35574,7 @@ }, "label": { "enum": [ - "no-team-member", - "operation-denied" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } - } - }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" - }, - "404": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 404, - "label": "no-team", - "message": "Team not found" - }, - "properties": { - "code": { - "enum": [ - 404 - ], - "type": "integer" - }, - "label": { - "enum": [ - "no-team" + "insufficient-permissions" ], "type": "string" }, @@ -26373,13 +35591,14 @@ } } }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + "description": "Insufficient team permissions (label: `insufficient-permissions`)" } }, - "summary": "Get config for mlsMigration" + "summary": "List the sent team invitations" }, - "put": { - "description": " [internal route ID: (\"put\", MlsMigrationConfig)]\n\n", + "post": { + "description": " [internal route ID: \"send-team-invitation\"]\n\nInvitations are sent by email. The maximum allowed number of pending team invitations is equal to the team size.", + "operationId": "send-team-invitation", "parameters": [ { "in": "path", @@ -26395,22 +35614,73 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/MlsMigration.Feature" + "$ref": "#/components/schemas/InvitationRequest_LTcyMDIzNDc0" } } }, "required": true }, "responses": { - "200": { + "201": { "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Invitation_NTkzMDYwODc1" + } + }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/MlsMigration.LockableFeature" + "$ref": "#/components/schemas/Invitation_NTkzMDYwODc1" } } }, - "description": "" + "description": "Invitation was created and sent.", + "headers": { + "Location": { + "schema": { + "format": "url", + "type": "string" + } + } + } + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-invitation-code", + "message": "Invalid invitation code." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-invitation-code", + "invalid-email" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid invitation code. (label: `invalid-invitation-code`)\n\nInvalid e-mail address. (label: `invalid-email`)" }, "403": { "content": { @@ -26418,8 +35688,8 @@ "schema": { "example": { "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "label": "insufficient-permissions", + "message": "Insufficient team permissions" }, "properties": { "code": { @@ -26430,8 +35700,11 @@ }, "label": { "enum": [ - "no-team-member", - "operation-denied" + "insufficient-permissions", + "too-many-team-invitations", + "blacklisted-email", + "no-identity", + "no-email" ], "type": "string" }, @@ -26448,27 +35721,59 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + "description": "Insufficient team permissions (label: `insufficient-permissions`)\n\nToo many team invitations for this team (label: `too-many-team-invitations`)\n\nThe given e-mail address has been blacklisted due to a permanent bounce or a complaint. (label: `blacklisted-email`)\n\nThe user has no verified email (label: `no-identity`)\n\nThis operation requires the user to have a verified email address. (label: `no-email`)" + } + }, + "summary": "Create and send a new team invitation." + } + }, + "/teams/{tid}/invitations/{iid}": { + "delete": { + "description": " [internal route ID: \"delete-team-invitation\"]\n\n", + "operationId": "delete-team-invitation", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } }, - "404": { + { + "in": "path", + "name": "iid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Invitation deleted" + }, + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-team", - "message": "Team not found" + "code": 403, + "label": "insufficient-permissions", + "message": "Insufficient team permissions" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "no-team" + "insufficient-permissions" ], "type": "string" }, @@ -26485,15 +35790,14 @@ } } }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + "description": "Insufficient team permissions (label: `insufficient-permissions`)" } }, - "summary": "Put config for mlsMigration" - } - }, - "/teams/{tid}/features/outlookCalIntegration": { + "summary": "Delete a pending team invitation by ID." + }, "get": { - "description": " [internal route ID: (\"get\", OutlookCalIntegrationConfig)]\n\n", + "description": " [internal route ID: \"get-team-invitation\"]\n\n", + "operationId": "get-team-invitation", "parameters": [ { "in": "path", @@ -26503,18 +35807,32 @@ "format": "uuid", "type": "string" } + }, + { + "in": "path", + "name": "iid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } } ], "responses": { "200": { "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Invitation_NTkzMDYwODc1" + } + }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/OutlookCalIntegrationConfig.LockableFeature" + "$ref": "#/components/schemas/Invitation_NTkzMDYwODc1" } } }, - "description": "" + "description": "Invitation" }, "403": { "content": { @@ -26522,8 +35840,8 @@ "schema": { "example": { "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "label": "insufficient-permissions", + "message": "Insufficient team permissions" }, "properties": { "code": { @@ -26534,8 +35852,7 @@ }, "label": { "enum": [ - "no-team-member", - "operation-denied" + "insufficient-permissions" ], "type": "string" }, @@ -26552,16 +35869,16 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + "description": "Insufficient team permissions (label: `insufficient-permissions`)" }, "404": { "content": { - "application/json;charset=utf-8": { + "application/json": { "schema": { "example": { "code": 404, - "label": "no-team", - "message": "Team not found" + "label": "not-found", + "message": "Notification not found." }, "properties": { "code": { @@ -26572,7 +35889,7 @@ }, "label": { "enum": [ - "no-team" + "not-found" ], "type": "string" }, @@ -26587,67 +35904,24 @@ ], "type": "object" } - } - }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" - } - }, - "summary": "Get config for outlookCalIntegration" - }, - "put": { - "description": " [internal route ID: (\"put\", OutlookCalIntegrationConfig)]\n\n", - "parameters": [ - { - "in": "path", - "name": "tid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/OutlookCalIntegrationConfig.Feature" - } - } - }, - "required": true - }, - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/OutlookCalIntegrationConfig.LockableFeature" - } - } - }, - "description": "" - }, - "403": { - "content": { + }, "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "code": 404, + "label": "not-found", + "message": "Notification not found." }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { - "enum": [ - "no-team-member", - "operation-denied" + "enum": [ + "not-found" ], "type": "string" }, @@ -26664,27 +35938,27 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + "description": "`tid` or `iid` or Notification not found. (label: `not-found`)" }, - "404": { + "409": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-team", - "message": "Team not found" + "code": 409, + "label": "duplicate-entry", + "message": "Entry already exists" }, "properties": { "code": { "enum": [ - 404 + 409 ], "type": "integer" }, "label": { "enum": [ - "no-team" + "duplicate-entry" ], "type": "string" }, @@ -26701,15 +35975,16 @@ } } }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + "description": "Entry already exists (label: `duplicate-entry`)" } }, - "summary": "Put config for outlookCalIntegration" + "summary": "Get a pending team invitation by ID." } }, - "/teams/{tid}/features/searchVisibility": { - "get": { - "description": " [internal route ID: (\"get\", SearchVisibilityAvailableConfig)]\n\n", + "/teams/{tid}/legalhold/consent": { + "post": { + "description": " [internal route ID: \"consent-to-legal-hold\"]\n\n", + "operationId": "consent-to-legal-hold", "parameters": [ { "in": "path", @@ -26722,36 +35997,69 @@ } ], "responses": { - "200": { + "201": { + "description": "Grant consent successful" + }, + "204": { + "description": "Consent already granted" + }, + "403": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/SearchVisibilityAvailableConfig.LockableFeature" + "example": { + "code": 403, + "label": "invalid-op", + "message": "Invalid operation" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-op", + "action-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "" + "description": "Invalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, + "code": 404, "label": "no-team-member", - "message": "Requesting user is not a team member" + "message": "Team member not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "no-team-member", - "operation-denied" + "no-team-member" ], "type": "string" }, @@ -26768,27 +36076,28 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + "description": "`tid` not found\n\nTeam member not found (label: `no-team-member`)" }, - "404": { + "500": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-team", - "message": "Team not found" + "code": 500, + "label": "legalhold-internal", + "message": "legal hold service: could not block connections when resolving policy conflicts." }, "properties": { "code": { "enum": [ - 404 + 500 ], "type": "integer" }, "label": { "enum": [ - "no-team" + "legalhold-internal", + "legalhold-illegal-op" ], "type": "string" }, @@ -26805,13 +36114,16 @@ } } }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + "description": "legal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)\n\ninternal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)" } }, - "summary": "Get config for searchVisibility" - }, - "put": { - "description": " [internal route ID: (\"put\", SearchVisibilityAvailableConfig)]\n\n", + "summary": "Consent to legal hold" + } + }, + "/teams/{tid}/legalhold/settings": { + "delete": { + "description": " [internal route ID: \"delete-legal-hold-settings\"]\n\nThis endpoint can lead to the following events being sent:\n- ClientRemoved event to members with a legalhold client (via brig)\n- UserLegalHoldDisabled event to contacts of members with a legalhold client (via brig)", + "operationId": "delete-legal-hold-settings", "parameters": [ { "in": "path", @@ -26827,43 +36139,35 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/SearchVisibilityAvailableConfig.Feature" + "$ref": "#/components/schemas/RemoveLegalHoldSettingsRequest_NzMzMzMyMDAz" } } }, "required": true }, "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/SearchVisibilityAvailableConfig.LockableFeature" - } - } - }, - "description": "" + "204": { + "description": "Legal hold service settings deleted" }, - "403": { + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "code": 400, + "label": "legalhold-not-registered", + "message": "legal hold service has not been registered for this team" }, "properties": { "code": { "enum": [ - 403 + 400 ], "type": "integer" }, "label": { "enum": [ - "no-team-member", - "operation-denied" + "legalhold-not-registered" ], "type": "string" }, @@ -26880,27 +36184,35 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + "description": "Invalid `body`\n\nlegal hold service has not been registered for this team (label: `legalhold-not-registered`)" }, - "404": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-team", - "message": "Team not found" + "code": 403, + "label": "legalhold-disable-unimplemented", + "message": "legal hold cannot be disabled for whitelisted teams" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "no-team" + "legalhold-disable-unimplemented", + "legalhold-not-enabled", + "invalid-op", + "action-denied", + "no-team-member", + "operation-denied", + "code-authentication-required", + "code-authentication-failed", + "access-denied" ], "type": "string" }, @@ -26917,57 +36229,27 @@ } } }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" - } - }, - "summary": "Put config for searchVisibility" - } - }, - "/teams/{tid}/features/searchVisibilityInbound": { - "get": { - "description": " [internal route ID: (\"get\", SearchVisibilityInboundConfig)]\n\n", - "parameters": [ - { - "in": "path", - "name": "tid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/SearchVisibilityInboundConfig.LockableFeature" - } - } - }, - "description": "" + "description": "legal hold cannot be disabled for whitelisted teams (label: `legalhold-disable-unimplemented`)\n\nlegal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nInvalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)\n\nVerification code required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nThis operation requires reauthentication (label: `access-denied`)" }, - "403": { + "429": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "code": 429, + "label": "too-many-requests", + "message": "Please try again later." }, "properties": { "code": { "enum": [ - 403 + 429 ], "type": "integer" }, "label": { "enum": [ - "no-team-member", - "operation-denied" + "too-many-requests" ], "type": "string" }, @@ -26984,27 +36266,28 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + "description": "Please try again later. (label: `too-many-requests`)" }, - "404": { + "500": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-team", - "message": "Team not found" + "code": 500, + "label": "legalhold-internal", + "message": "legal hold service: could not block connections when resolving policy conflicts." }, "properties": { "code": { "enum": [ - 404 + 500 ], "type": "integer" }, "label": { "enum": [ - "no-team" + "legalhold-internal", + "legalhold-illegal-op" ], "type": "string" }, @@ -27021,13 +36304,14 @@ } } }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + "description": "legal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)\n\ninternal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)" } }, - "summary": "Get config for searchVisibilityInbound" + "summary": "Delete legal hold service settings" }, - "put": { - "description": " [internal route ID: (\"put\", SearchVisibilityInboundConfig)]\n\n", + "get": { + "description": " [internal route ID: \"get-legal-hold-settings\"]\n\n", + "operationId": "get-legal-hold-settings", "parameters": [ { "in": "path", @@ -27039,22 +36323,12 @@ } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/SearchVisibilityInboundConfig.Feature" - } - } - }, - "required": true - }, "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/SearchVisibilityInboundConfig.LockableFeature" + "$ref": "#/components/schemas/ViewLegalHoldService_LTE3MzQzNDkw" } } }, @@ -27066,8 +36340,8 @@ "schema": { "example": { "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "label": "operation-denied", + "message": "Insufficient permissions" }, "properties": { "code": { @@ -27078,45 +36352,8 @@ }, "label": { "enum": [ - "no-team-member", - "operation-denied" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } - } - }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" - }, - "404": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 404, - "label": "no-team", - "message": "Team not found" - }, - "properties": { - "code": { - "enum": [ - 404 - ], - "type": "integer" - }, - "label": { - "enum": [ - "no-team" + "operation-denied", + "no-team-member" ], "type": "string" }, @@ -27133,15 +36370,14 @@ } } }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" } }, - "summary": "Put config for searchVisibilityInbound" - } - }, - "/teams/{tid}/features/selfDeletingMessages": { - "get": { - "description": " [internal route ID: (\"get\", SelfDeletingMessagesConfig)]\n\n", + "summary": "Get legal hold service settings" + }, + "post": { + "description": " [internal route ID: \"create-legal-hold-settings\"]\n\n", + "operationId": "create-legal-hold-settings", "parameters": [ { "in": "path", @@ -27153,37 +36389,52 @@ } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewLegalHoldService_Mzg0ODQ5NDU1" + } + } + }, + "required": true + }, "responses": { - "200": { + "201": { "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ViewLegalHoldService_LTE3MzQzNDkw" + } + }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/SelfDeletingMessagesConfig.LockableFeature" + "$ref": "#/components/schemas/ViewLegalHoldService_LTE3MzQzNDkw" } } }, - "description": "" + "description": "Legal hold service settings created" }, - "403": { + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "code": 400, + "label": "legalhold-status-bad", + "message": "legal hold service: invalid response" }, "properties": { "code": { "enum": [ - 403 + 400 ], "type": "integer" }, "label": { "enum": [ - "no-team-member", - "operation-denied" + "legalhold-status-bad", + "legalhold-invalid-key" ], "type": "string" }, @@ -27200,27 +36451,29 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + "description": "Invalid `body`\n\nlegal hold service: invalid response (label: `legalhold-status-bad`)\n\nlegal hold service pubkey is invalid (label: `legalhold-invalid-key`)" }, - "404": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-team", - "message": "Team not found" + "code": 403, + "label": "legalhold-not-enabled", + "message": "legal hold is not enabled for this team" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "no-team" + "legalhold-not-enabled", + "operation-denied", + "no-team-member" ], "type": "string" }, @@ -27237,13 +36490,16 @@ } } }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + "description": "legal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nInsufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" } }, - "summary": "Get config for selfDeletingMessages" - }, - "put": { - "description": " [internal route ID: (\"put\", SelfDeletingMessagesConfig)]\n\n", + "summary": "Create legal hold service settings" + } + }, + "/teams/{tid}/legalhold/{uid}": { + "delete": { + "description": " [internal route ID: \"disable-legal-hold-for-user\"]\n\nThis endpoint can lead to the following events being sent:\n- ClientRemoved event to the user owning the client (via brig)\n- UserLegalHoldDisabled event to contacts of the user owning the client (via brig)", + "operationId": "disable-legal-hold-for-user", "parameters": [ { "in": "path", @@ -27253,13 +36509,22 @@ "format": "uuid", "type": "string" } + }, + { + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } } ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/SelfDeletingMessagesConfig.Feature" + "$ref": "#/components/schemas/DisableLegalHoldForUserRequest_LTYyMDYxOTEy" } } }, @@ -27267,35 +36532,30 @@ }, "responses": { "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/SelfDeletingMessagesConfig.LockableFeature" - } - } - }, - "description": "" + "description": "Disable legal hold successful" }, - "403": { + "204": { + "description": "Legal hold was not enabled" + }, + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "code": 400, + "label": "legalhold-not-registered", + "message": "legal hold service has not been registered for this team" }, "properties": { "code": { "enum": [ - 403 + 400 ], "type": "integer" }, "label": { "enum": [ - "no-team-member", - "operation-denied" + "legalhold-not-registered" ], "type": "string" }, @@ -27312,27 +36572,32 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + "description": "Invalid `body`\n\nlegal hold service has not been registered for this team (label: `legalhold-not-registered`)" }, - "404": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-team", - "message": "Team not found" + "code": 403, + "label": "operation-denied", + "message": "Insufficient permissions" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "no-team" + "operation-denied", + "no-team-member", + "action-denied", + "code-authentication-required", + "code-authentication-failed", + "access-denied" ], "type": "string" }, @@ -27349,57 +36614,27 @@ } } }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" - } - }, - "summary": "Put config for selfDeletingMessages" - } - }, - "/teams/{tid}/features/sndFactorPasswordChallenge": { - "get": { - "description": " [internal route ID: (\"get\", SndFactorPasswordChallengeConfig)]\n\n", - "parameters": [ - { - "in": "path", - "name": "tid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/SndFactorPasswordChallengeConfig.LockableFeature" - } - } - }, - "description": "" + "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)\n\nVerification code required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nThis operation requires reauthentication (label: `access-denied`)" }, - "403": { + "429": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "code": 429, + "label": "too-many-requests", + "message": "Please try again later." }, "properties": { "code": { "enum": [ - 403 + 429 ], "type": "integer" }, "label": { "enum": [ - "no-team-member", - "operation-denied" + "too-many-requests" ], "type": "string" }, @@ -27416,27 +36651,28 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + "description": "Please try again later. (label: `too-many-requests`)" }, - "404": { + "500": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-team", - "message": "Team not found" + "code": 500, + "label": "legalhold-internal", + "message": "legal hold service: could not block connections when resolving policy conflicts." }, "properties": { "code": { "enum": [ - 404 + 500 ], "type": "integer" }, "label": { "enum": [ - "no-team" + "legalhold-internal", + "legalhold-illegal-op" ], "type": "string" }, @@ -27453,13 +36689,14 @@ } } }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + "description": "legal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)\n\ninternal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)" } }, - "summary": "Get config for sndFactorPasswordChallenge" + "summary": "Disable legal hold for user" }, - "put": { - "description": " [internal route ID: (\"put\", SndFactorPasswordChallengeConfig)]\n\n", + "get": { + "description": " [internal route ID: \"get-legal-hold\"]\n\n", + "operationId": "get-legal-hold", "parameters": [ { "in": "path", @@ -27469,49 +36706,47 @@ "format": "uuid", "type": "string" } + }, + { + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/SndFactorPasswordChallengeConfig.Feature" - } - } - }, - "required": true - }, "responses": { "200": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/SndFactorPasswordChallengeConfig.LockableFeature" + "$ref": "#/components/schemas/UserLegalHoldStatusResponse_LTQ1MzUxMTE3" } } }, "description": "" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, + "code": 404, "label": "no-team-member", - "message": "Requesting user is not a team member" + "message": "Team member not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "no-team-member", - "operation-denied" + "no-team-member" ], "type": "string" }, @@ -27528,27 +36763,61 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + "description": "`tid` or `uid` not found\n\nTeam member not found (label: `no-team-member`)" + } + }, + "summary": "Get legal hold status" + }, + "post": { + "description": " [internal route ID: \"request-legal-hold-device\"]\n\nThis endpoint can lead to the following events being sent:\n- LegalHoldClientRequested event to contacts of the user the device is requested for, if they didn't already have a legalhold client (via brig)", + "operationId": "request-legal-hold-device", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } }, - "404": { + { + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "201": { + "description": "Request device successful" + }, + "204": { + "description": "Request device already pending" + }, + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-team", - "message": "Team not found" + "code": 400, + "label": "legalhold-not-registered", + "message": "legal hold service has not been registered for this team" }, "properties": { "code": { "enum": [ - 404 + 400 ], "type": "integer" }, "label": { "enum": [ - "no-team" + "legalhold-not-registered", + "legalhold-status-bad" ], "type": "string" }, @@ -27565,36 +36834,7 @@ } } }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" - } - }, - "summary": "Put config for sndFactorPasswordChallenge" - } - }, - "/teams/{tid}/features/sso": { - "get": { - "description": " [internal route ID: (\"get\", SSOConfig)]\n\n", - "parameters": [ - { - "in": "path", - "name": "tid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/SSOConfig.LockableFeature" - } - } - }, - "description": "" + "description": "legal hold service has not been registered for this team (label: `legalhold-not-registered`)\n\nlegal hold service: invalid response (label: `legalhold-status-bad`)" }, "403": { "content": { @@ -27602,8 +36842,8 @@ "schema": { "example": { "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "label": "legalhold-not-enabled", + "message": "legal hold is not enabled for this team" }, "properties": { "code": { @@ -27614,8 +36854,10 @@ }, "label": { "enum": [ + "legalhold-not-enabled", + "operation-denied", "no-team-member", - "operation-denied" + "action-denied" ], "type": "string" }, @@ -27632,7 +36874,7 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + "description": "legal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nInsufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)" }, "404": { "content": { @@ -27640,8 +36882,8 @@ "schema": { "example": { "code": 404, - "label": "no-team", - "message": "Team not found" + "label": "no-team-member", + "message": "Team member not found" }, "properties": { "code": { @@ -27652,7 +36894,7 @@ }, "label": { "enum": [ - "no-team" + "no-team-member" ], "type": "string" }, @@ -27669,57 +36911,29 @@ } } }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" - } - }, - "summary": "Get config for sso" - } - }, - "/teams/{tid}/features/validateSAMLemails": { - "get": { - "description": " [internal route ID: (\"get\", ValidateSAMLEmailsConfig)]\n\n", - "parameters": [ - { - "in": "path", - "name": "tid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ValidateSAMLEmailsConfig.LockableFeature" - } - } - }, - "description": "" + "description": "`tid` or `uid` not found\n\nTeam member not found (label: `no-team-member`)" }, - "403": { + "409": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "code": 409, + "label": "mls-legal-hold-not-allowed", + "message": "A user who is under legal-hold may not participate in MLS conversations" }, "properties": { "code": { "enum": [ - 403 + 409 ], "type": "integer" }, "label": { "enum": [ - "no-team-member", - "operation-denied" + "mls-legal-hold-not-allowed", + "legalhold-no-consent", + "legalhold-already-enabled" ], "type": "string" }, @@ -27736,27 +36950,28 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + "description": "A user who is under legal-hold may not participate in MLS conversations (label: `mls-legal-hold-not-allowed`)\n\nuser has not given consent to using legal hold (label: `legalhold-no-consent`)\n\nlegal hold is already enabled for this user (label: `legalhold-already-enabled`)" }, - "404": { + "500": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-team", - "message": "Team not found" + "code": 500, + "label": "legalhold-illegal-op", + "message": "internal server error: inconsistent change of user's legalhold state" }, "properties": { "code": { "enum": [ - 404 + 500 ], "type": "integer" }, "label": { "enum": [ - "no-team" + "legalhold-illegal-op", + "legalhold-internal" ], "type": "string" }, @@ -27773,15 +36988,16 @@ } } }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + "description": "internal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)\n\nlegal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)" } }, - "summary": "Get config for validateSAMLemails" + "summary": "Request legal hold device" } }, - "/teams/{tid}/get-members-by-ids-using-post": { - "post": { - "description": " [internal route ID: \"get-team-members-by-ids\"]\n\nThe `has_more` field in the response body is always `false`.", + "/teams/{tid}/legalhold/{uid}/approve": { + "put": { + "description": " [internal route ID: \"approve-legal-hold-device\"]\n\nThis endpoint can lead to the following events being sent:\n- ClientAdded event to the user owning the client (via brig)\n- UserLegalHoldEnabled event to contacts of the user owning the client (via brig)\n- ClientRemoved event to the user, if removing old client due to max number (via brig)", + "operationId": "approve-legal-hold-device", "parameters": [ { "in": "path", @@ -27793,15 +37009,12 @@ } }, { - "description": "Maximum results to be returned", - "in": "query", - "name": "maxResults", - "required": false, + "in": "path", + "name": "uid", + "required": true, "schema": { - "format": "int32", - "maximum": 2000, - "minimum": 1, - "type": "integer" + "format": "uuid", + "type": "string" } } ], @@ -27809,7 +37022,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/UserIdList" + "$ref": "#/components/schemas/ApproveLegalHoldForUserRequest_NjEyNzYyMTIx" } } }, @@ -27817,14 +37030,7 @@ }, "responses": { "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/TeamMemberList" - } - } - }, - "description": "" + "description": "Legal hold approved" }, "400": { "content": { @@ -27832,8 +37038,8 @@ "schema": { "example": { "code": 400, - "label": "too-many-uids", - "message": "Can only process 2000 user ids per request." + "label": "legalhold-not-registered", + "message": "legal hold service has not been registered for this team" }, "properties": { "code": { @@ -27844,7 +37050,7 @@ }, "label": { "enum": [ - "too-many-uids" + "legalhold-not-registered" ], "type": "string" }, @@ -27861,7 +37067,7 @@ } } }, - "description": "Invalid `body` or `maxResults`\n\nCan only process 2000 user ids per request. (label: `too-many-uids`)" + "description": "Invalid `body`\n\nlegal hold service has not been registered for this team (label: `legalhold-not-registered`)" }, "403": { "content": { @@ -27869,8 +37075,8 @@ "schema": { "example": { "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "label": "legalhold-not-enabled", + "message": "legal hold is not enabled for this team" }, "properties": { "code": { @@ -27881,7 +37087,12 @@ }, "label": { "enum": [ - "no-team-member" + "legalhold-not-enabled", + "no-team-member", + "action-denied", + "access-denied", + "code-authentication-required", + "code-authentication-failed" ], "type": "string" }, @@ -27898,83 +37109,27 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)" - } - }, - "summary": "Get team members by user id list" - } - }, - "/teams/{tid}/invitations": { - "get": { - "description": " [internal route ID: \"get-team-invitations\"]\n\n", - "parameters": [ - { - "in": "path", - "name": "tid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - }, - { - "description": "Invitation id to start from (ascending).", - "in": "query", - "name": "start", - "required": false, - "schema": { - "format": "uuid", - "type": "string" - } - }, - { - "description": "Number of results to return (default 100, max 500).", - "in": "query", - "name": "size", - "required": false, - "schema": { - "format": "int32", - "maximum": 500, - "minimum": 1, - "type": "integer" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvitationList" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/InvitationList" - } - } - }, - "description": "List of sent invitations" + "description": "legal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)\n\nYou do not have permission to access this resource (label: `access-denied`)\n\nVerification code required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nThis operation requires reauthentication (label: `access-denied`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "insufficient-permissions", - "message": "Insufficient team permissions" + "code": 404, + "label": "legalhold-no-device-allocated", + "message": "no legal hold device is registered for this user. POST /teams/:tid/legalhold/:uid/ to start the flow." }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "insufficient-permissions" + "legalhold-no-device-allocated" ], "type": "string" }, @@ -27991,77 +37146,64 @@ } } }, - "description": "Insufficient team permissions (label: `insufficient-permissions`)" - } - }, - "summary": "List the sent team invitations" - }, - "post": { - "description": " [internal route ID: \"send-team-invitation\"]\n\nInvitations are sent by email. The maximum allowed number of pending team invitations is equal to the team size.", - "parameters": [ - { - "in": "path", - "name": "tid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/InvitationRequest" - } - } + "description": "`tid` or `uid` not found\n\nno legal hold device is registered for this user. POST /teams/:tid/legalhold/:uid/ to start the flow. (label: `legalhold-no-device-allocated`)" }, - "required": true - }, - "responses": { - "201": { + "409": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Invitation" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Invitation" + "example": { + "code": 409, + "label": "legalhold-already-enabled", + "message": "legal hold is already enabled for this user" + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-already-enabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "Invitation was created and sent.", - "headers": { - "Location": { - "schema": { - "format": "url", - "type": "string" - } - } - } + "description": "legal hold is already enabled for this user (label: `legalhold-already-enabled`)" }, - "400": { + "412": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "invalid-email", - "message": "Invalid e-mail address." + "code": 412, + "label": "legalhold-not-pending", + "message": "legal hold cannot be approved without being in a pending state" }, "properties": { "code": { "enum": [ - 400 + 412 ], "type": "integer" }, "label": { "enum": [ - "invalid-email" + "legalhold-not-pending" ], "type": "string" }, @@ -28078,31 +37220,27 @@ } } }, - "description": "Invalid `body`\n\nInvalid e-mail address. (label: `invalid-email`)" + "description": "legal hold cannot be approved without being in a pending state (label: `legalhold-not-pending`)" }, - "403": { + "429": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "insufficient-permissions", - "message": "Insufficient team permissions" + "code": 429, + "label": "too-many-requests", + "message": "Please try again later." }, "properties": { "code": { "enum": [ - 403 + 429 ], "type": "integer" }, "label": { "enum": [ - "insufficient-permissions", - "too-many-team-invitations", - "blacklisted-email", - "no-identity", - "no-email" + "too-many-requests" ], "type": "string" }, @@ -28119,58 +37257,28 @@ } } }, - "description": "Insufficient team permissions (label: `insufficient-permissions`)\n\nToo many team invitations for this team (label: `too-many-team-invitations`)\n\nThe given e-mail address has been blacklisted due to a permanent bounce or a complaint. (label: `blacklisted-email`)\n\nThe user has no verified email (label: `no-identity`)\n\nThis operation requires the user to have a verified email address. (label: `no-email`)" - } - }, - "summary": "Create and send a new team invitation." - } - }, - "/teams/{tid}/invitations/{iid}": { - "delete": { - "description": " [internal route ID: \"delete-team-invitation\"]\n\n", - "parameters": [ - { - "in": "path", - "name": "tid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - }, - { - "in": "path", - "name": "iid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Invitation deleted" + "description": "Please try again later. (label: `too-many-requests`)" }, - "403": { + "500": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "insufficient-permissions", - "message": "Insufficient team permissions" + "code": 500, + "label": "legalhold-internal", + "message": "legal hold service: could not block connections when resolving policy conflicts." }, "properties": { "code": { "enum": [ - 403 + 500 ], "type": "integer" }, "label": { "enum": [ - "insufficient-permissions" + "legalhold-internal", + "legalhold-illegal-op" ], "type": "string" }, @@ -28187,13 +37295,16 @@ } } }, - "description": "Insufficient team permissions (label: `insufficient-permissions`)" + "description": "legal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)\n\ninternal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)" } }, - "summary": "Delete a pending team invitation by ID." - }, + "summary": "Approve legal hold device" + } + }, + "/teams/{tid}/members": { "get": { - "description": " [internal route ID: \"get-team-invitation\"]\n\n", + "description": " [internal route ID: \"get-team-members\"]\n\n", + "operationId": "get-team-members", "parameters": [ { "in": "path", @@ -28205,11 +37316,23 @@ } }, { - "in": "path", - "name": "iid", - "required": true, + "description": "Maximum results to be returned", + "in": "query", + "name": "maxResults", + "required": false, + "schema": { + "format": "int32", + "maximum": 2000, + "minimum": 1, + "type": "integer" + } + }, + { + "description": "Optional, when not specified, the first page will be returned.Every returned page contains a `pagingState`, this should be supplied to retrieve the next page.", + "in": "query", + "name": "pagingState", + "required": false, "schema": { - "format": "uuid", "type": "string" } } @@ -28217,18 +37340,13 @@ "responses": { "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Invitation" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/Invitation" + "$ref": "#/components/schemas/TeamMembersPage_NzYwNDIxODgx" } } }, - "description": "Invitation" + "description": "" }, "403": { "content": { @@ -28236,8 +37354,8 @@ "schema": { "example": { "code": 403, - "label": "insufficient-permissions", - "message": "Insufficient team permissions" + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { @@ -28248,76 +37366,7 @@ }, "label": { "enum": [ - "insufficient-permissions" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } - } - }, - "description": "Insufficient team permissions (label: `insufficient-permissions`)" - }, - "404": { - "content": { - "application/json": { - "schema": { - "example": { - "code": 404, - "label": "not-found", - "message": "Notification not found." - }, - "properties": { - "code": { - "enum": [ - 404 - ], - "type": "integer" - }, - "label": { - "enum": [ - "not-found" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } - }, - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 404, - "label": "not-found", - "message": "Notification not found." - }, - "properties": { - "code": { - "enum": [ - 404 - ], - "type": "integer" - }, - "label": { - "enum": [ - "not-found" + "no-team-member" ], "type": "string" }, @@ -28334,15 +37383,14 @@ } } }, - "description": "`tid` or `iid` or Notification not found. (label: `not-found`)" + "description": "Requesting user is not a team member (label: `no-team-member`)" } }, - "summary": "Get a pending team invitation by ID." - } - }, - "/teams/{tid}/legalhold/consent": { - "post": { - "description": " [internal route ID: \"consent-to-legal-hold\"]\n\nCalls federation service brig on get-users-by-ids
Calls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated", + "summary": "Get team members" + }, + "put": { + "description": " [internal route ID: \"update-team-member\"]\n\n", + "operationId": "update-team-member", "parameters": [ { "in": "path", @@ -28354,12 +37402,19 @@ } } ], - "responses": { - "201": { - "description": "Grant consent successful" + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewTeamMember_Required_LTg2NjU5OTI2" + } + } }, - "204": { - "description": "Consent already granted" + "required": true + }, + "responses": { + "200": { + "description": "" }, "403": { "content": { @@ -28367,8 +37422,8 @@ "schema": { "example": { "code": 403, - "label": "invalid-op", - "message": "Invalid operation" + "label": "operation-denied", + "message": "Insufficient permissions" }, "properties": { "code": { @@ -28379,8 +37434,11 @@ }, "label": { "enum": [ - "invalid-op", - "action-denied" + "operation-denied", + "no-team-member", + "too-many-team-admins", + "invalid-permissions", + "access-denied" ], "type": "string" }, @@ -28397,7 +37455,7 @@ } } }, - "description": "Invalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)" + "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nMaximum number of admins per team reached (label: `too-many-team-admins`)\n\nThe specified permissions are invalid (label: `invalid-permissions`)\n\nYou do not have permission to access this resource (label: `access-denied`)" }, "404": { "content": { @@ -28417,7 +37475,8 @@ }, "label": { "enum": [ - "no-team-member" + "no-team-member", + "no-team" ], "type": "string" }, @@ -28434,28 +37493,53 @@ } } }, - "description": "`tid` not found\n\nTeam member not found (label: `no-team-member`)" + "description": "`tid` not found\n\nTeam member not found (label: `no-team-member`)\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Update an existing team member" + } + }, + "/teams/{tid}/members/csv": { + "get": { + "description": " [internal route ID: \"get-team-members-csv\"]\n\nThe endpoint returns data in chunked transfer encoding. Internal server errors might result in a failed transfer instead of a 500 response.", + "operationId": "get-team-members-csv", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "text/csv": {} + }, + "description": "CSV of team members" }, - "500": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 500, - "label": "legalhold-internal", - "message": "legal hold service: could not block connections when resolving policy conflicts." + "code": 403, + "label": "access-denied", + "message": "You do not have permission to access this resource" }, "properties": { "code": { "enum": [ - 500 + 403 ], "type": "integer" }, "label": { "enum": [ - "legalhold-internal", - "legalhold-illegal-op" + "access-denied" ], "type": "string" }, @@ -28472,15 +37556,16 @@ } } }, - "description": "legal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)\n\ninternal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)" + "description": "You do not have permission to access this resource (label: `access-denied`)" } }, - "summary": "Consent to legal hold" + "summary": "Get all members of the team as a CSV file" } }, - "/teams/{tid}/legalhold/settings": { + "/teams/{tid}/members/{uid}": { "delete": { - "description": " [internal route ID: \"delete-legal-hold-settings\"]\n\nThis endpoint can lead to the following events being sent:\n- ClientRemoved event to members with a legalhold client (via brig)\n- UserLegalHoldDisabled event to contacts of members with a legalhold client (via brig)
Calls federation service brig on get-users-by-ids
Calls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated", + "description": " [internal route ID: \"delete-team-member\"]\n\n", + "operationId": "delete-team-member", "parameters": [ { "in": "path", @@ -28490,41 +37575,57 @@ "format": "uuid", "type": "string" } + }, + { + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } } ], "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/RemoveLegalHoldSettingsRequest" + "$ref": "#/components/schemas/TeamMemberDeleteData_LTg2OTEyOTI4" } } }, "required": true }, "responses": { - "204": { - "description": "Legal hold service settings deleted" + "200": { + "description": "" }, - "400": { + "202": { + "description": "Team member scheduled for deletion" + }, + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "legalhold-not-registered", - "message": "legal hold service has not been registered for this team" + "code": 403, + "label": "operation-denied", + "message": "Insufficient permissions" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "legalhold-not-registered" + "operation-denied", + "no-team-member", + "access-denied", + "code-authentication-required", + "code-authentication-failed" ], "type": "string" }, @@ -28541,35 +37642,28 @@ } } }, - "description": "Invalid `body`\n\nlegal hold service has not been registered for this team (label: `legalhold-not-registered`)" + "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nYou do not have permission to access this resource (label: `access-denied`)\n\nVerification code required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nThis operation requires reauthentication (label: `access-denied`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "legalhold-disable-unimplemented", - "message": "legal hold cannot be disabled for whitelisted teams" + "code": 404, + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "legalhold-disable-unimplemented", - "legalhold-not-enabled", - "invalid-op", - "action-denied", - "no-team-member", - "operation-denied", - "code-authentication-required", - "code-authentication-failed", - "access-denied" + "no-team", + "no-team-member" ], "type": "string" }, @@ -28586,28 +37680,27 @@ } } }, - "description": "legal hold cannot be disabled for whitelisted teams (label: `legalhold-disable-unimplemented`)\n\nlegal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nInvalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)\n\nVerification code required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nThis operation requires reauthentication (label: `access-denied`)" + "description": "`tid` or `uid` not found\n\nTeam not found (label: `no-team`)\n\nTeam member not found (label: `no-team-member`)" }, - "500": { + "429": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 500, - "label": "legalhold-internal", - "message": "legal hold service: could not block connections when resolving policy conflicts." + "code": 429, + "label": "too-many-requests", + "message": "Please try again later." }, "properties": { "code": { "enum": [ - 500 + 429 ], "type": "integer" }, "label": { "enum": [ - "legalhold-internal", - "legalhold-illegal-op" + "too-many-requests" ], "type": "string" }, @@ -28624,13 +37717,14 @@ } } }, - "description": "legal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)\n\ninternal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)" + "description": "Please try again later. (label: `too-many-requests`)" } }, - "summary": "Delete legal hold service settings" + "summary": "Remove an existing team member" }, "get": { - "description": " [internal route ID: \"get-legal-hold-settings\"]\n\n", + "description": " [internal route ID: \"get-team-member\"]\n\n", + "operationId": "get-team-member", "parameters": [ { "in": "path", @@ -28640,66 +37734,10 @@ "format": "uuid", "type": "string" } - } - ], - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/ViewLegalHoldService" - } - } - }, - "description": "" }, - "403": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 403, - "label": "operation-denied", - "message": "Insufficient permissions" - }, - "properties": { - "code": { - "enum": [ - 403 - ], - "type": "integer" - }, - "label": { - "enum": [ - "operation-denied", - "no-team-member" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } - } - }, - "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" - } - }, - "summary": "Get legal hold service settings" - }, - "post": { - "description": " [internal route ID: \"create-legal-hold-settings\"]\n\n", - "parameters": [ { "in": "path", - "name": "tid", + "name": "uid", "required": true, "schema": { "format": "uuid", @@ -28707,52 +37745,36 @@ } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/NewLegalHoldService" - } - } - }, - "required": true - }, "responses": { - "201": { + "200": { "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ViewLegalHoldService" - } - }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ViewLegalHoldService" + "$ref": "#/components/schemas/TeamMember_Optional_NTU0MDcyNzI1" } } }, - "description": "Legal hold service settings created" + "description": "" }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "legalhold-status-bad", - "message": "legal hold service: invalid response" + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "legalhold-status-bad", - "legalhold-invalid-key" + "no-team-member" ], "type": "string" }, @@ -28769,28 +37791,26 @@ } } }, - "description": "Invalid `body`\n\nlegal hold service: invalid response (label: `legalhold-status-bad`)\n\nlegal hold service pubkey is invalid (label: `legalhold-invalid-key`)" + "description": "Requesting user is not a team member (label: `no-team-member`)" }, - "403": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "legalhold-not-enabled", - "message": "legal hold is not enabled for this team" + "code": 404, + "label": "no-team-member", + "message": "Team member not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "legalhold-not-enabled", - "operation-denied", "no-team-member" ], "type": "string" @@ -28808,15 +37828,16 @@ } } }, - "description": "legal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nInsufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" + "description": "`tid` or `uid` not found\n\nTeam member not found (label: `no-team-member`)" } }, - "summary": "Create legal hold service settings" + "summary": "Get single team member" } }, - "/teams/{tid}/legalhold/{uid}": { - "delete": { - "description": " [internal route ID: \"disable-legal-hold-for-user\"]\n\nThis endpoint can lead to the following events being sent:\n- ClientRemoved event to the user owning the client (via brig)\n- UserLegalHoldDisabled event to contacts of the user owning the client (via brig)
Calls federation service brig on get-users-by-ids
Calls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated", + "/teams/{tid}/search": { + "get": { + "description": " [internal route ID: \"browse-team\"]\n\n", + "operationId": "browse-team", "parameters": [ { "in": "path", @@ -28827,9 +37848,135 @@ "type": "string" } }, + { + "description": "Search expression", + "in": "query", + "name": "q", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Role filter, eg. `member,partner`. Empty list means do not filter.", + "in": "query", + "name": "frole", + "required": false, + "schema": { + "items": { + "enum": [ + "owner", + "admin", + "member", + "partner" + ], + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Can be one of name, handle, email, saml_idp, managed_by, role, created_at.", + "in": "query", + "name": "sortby", + "required": false, + "schema": { + "enum": [ + "name", + "handle", + "email", + "saml_idp", + "managed_by", + "role", + "created_at" + ], + "type": "string" + } + }, + { + "description": "Can be one of asc, desc.", + "in": "query", + "name": "sortorder", + "required": false, + "schema": { + "enum": [ + "asc", + "desc" + ], + "type": "string" + } + }, + { + "description": "Number of results to return (min: 1, max: 500, default: 15)", + "in": "query", + "name": "size", + "required": false, + "schema": { + "maximum": 500, + "minimum": 1, + "type": "integer" + } + }, + { + "description": "Optional, when not specified, the first page will be returned. Every returned page contains a `paging_state`, this should be supplied to retrieve the next page.", + "in": "query", + "name": "pagingState", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter for (un-)verified email", + "in": "query", + "name": "email", + "required": false, + "schema": { + "enum": [ + "unverified", + "verified" + ], + "type": "string" + } + }, + { + "description": "Optional, return only non-searchable members when false.", + "in": "query", + "name": "searchable", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SearchResult_TeamContact_LTE0NjQ0NzMw" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/SearchResult_TeamContact_LTE0NjQ0NzMw" + } + } + }, + "description": "Search results" + } + }, + "summary": "Browse team for members (requires add-user permission)" + } + }, + "/teams/{tid}/search-visibility": { + "get": { + "description": " [internal route ID: \"get-search-visibility\"]\n\n", + "operationId": "get-search-visibility", + "parameters": [ { "in": "path", - "name": "uid", + "name": "tid", "required": true, "schema": { "format": "uuid", @@ -28837,59 +37984,16 @@ } } ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/DisableLegalHoldForUserRequest" - } - } - }, - "required": true - }, "responses": { "200": { - "description": "Disable legal hold successful" - }, - "204": { - "description": "Legal hold was not enabled" - }, - "400": { "content": { "application/json;charset=utf-8": { "schema": { - "example": { - "code": 400, - "label": "legalhold-not-registered", - "message": "legal hold service has not been registered for this team" - }, - "properties": { - "code": { - "enum": [ - 400 - ], - "type": "integer" - }, - "label": { - "enum": [ - "legalhold-not-registered" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" + "$ref": "#/components/schemas/TeamSearchVisibilityView_Mzg3MzMzMTk3" } } }, - "description": "Invalid `body`\n\nlegal hold service has not been registered for this team (label: `legalhold-not-registered`)" + "description": "" }, "403": { "content": { @@ -28910,11 +38014,7 @@ "label": { "enum": [ "operation-denied", - "no-team-member", - "action-denied", - "code-authentication-required", - "code-authentication-failed", - "access-denied" + "no-team-member" ], "type": "string" }, @@ -28931,28 +38031,60 @@ } } }, - "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)\n\nVerification code required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nThis operation requires reauthentication (label: `access-denied`)" + "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" + } + }, + "summary": "Shows the value for search visibility" + }, + "put": { + "description": " [internal route ID: \"set-search-visibility\"]\n\n", + "operationId": "set-search-visibility", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/TeamSearchVisibilityView_Mzg3MzMzMTk3" + } + } }, - "500": { + "required": true + }, + "responses": { + "204": { + "description": "Search visibility set" + }, + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 500, - "label": "legalhold-internal", - "message": "legal hold service: could not block connections when resolving policy conflicts." + "code": 403, + "label": "team-search-visibility-not-enabled", + "message": "Custom search is not available for this team" }, "properties": { "code": { "enum": [ - 500 + 403 ], "type": "integer" }, "label": { "enum": [ - "legalhold-internal", - "legalhold-illegal-op" + "team-search-visibility-not-enabled", + "operation-denied", + "no-team-member" ], "type": "string" }, @@ -28969,43 +38101,7 @@ } } }, - "description": "legal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)\n\ninternal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)" - } - }, - "summary": "Disable legal hold for user" - }, - "get": { - "description": " [internal route ID: \"get-legal-hold\"]\n\n", - "parameters": [ - { - "in": "path", - "name": "tid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - }, - { - "in": "path", - "name": "uid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/UserLegalHoldStatusResponse" - } - } - }, - "description": "" + "description": "Custom search is not available for this team (label: `team-search-visibility-not-enabled`)\n\nInsufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" }, "404": { "content": { @@ -29013,8 +38109,8 @@ "schema": { "example": { "code": 404, - "label": "no-team-member", - "message": "Team member not found" + "label": "no-team", + "message": "Team not found" }, "properties": { "code": { @@ -29025,7 +38121,7 @@ }, "label": { "enum": [ - "no-team-member" + "no-team" ], "type": "string" }, @@ -29042,13 +38138,16 @@ } } }, - "description": "`tid` or `uid` not found\n\nTeam member not found (label: `no-team-member`)" + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" } }, - "summary": "Get legal hold status" - }, - "post": { - "description": " [internal route ID: \"request-legal-hold-device\"]\n\nThis endpoint can lead to the following events being sent:\n- LegalHoldClientRequested event to contacts of the user the device is requested for, if they didn't already have a legalhold client (via brig)
Calls federation service brig on get-users-by-ids
Calls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated", + "summary": "Sets the search visibility for the whole team" + } + }, + "/teams/{tid}/size": { + "get": { + "description": " [internal route ID: \"get-team-size\"]\n\nCan be out of sync by roughly the `refresh_interval` of the ES index.", + "operationId": "get-team-size", "parameters": [ { "in": "path", @@ -29058,23 +38157,23 @@ "format": "uuid", "type": "string" } - }, - { - "in": "path", - "name": "uid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } } ], "responses": { - "201": { - "description": "Request device successful" - }, - "204": { - "description": "Request device already pending" + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamSize_LTMzMzk2MTk1" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/TeamSize_LTMzMzk2MTk1" + } + } + }, + "description": "Number of team members" }, "400": { "content": { @@ -29082,8 +38181,8 @@ "schema": { "example": { "code": 400, - "label": "legalhold-not-registered", - "message": "legal hold service has not been registered for this team" + "label": "invalid-invitation-code", + "message": "Invalid invitation code." }, "properties": { "code": { @@ -29094,8 +38193,7 @@ }, "label": { "enum": [ - "legalhold-not-registered", - "legalhold-status-bad" + "invalid-invitation-code" ], "type": "string" }, @@ -29112,16 +38210,69 @@ } } }, - "description": "legal hold service has not been registered for this team (label: `legalhold-not-registered`)\n\nlegal hold service: invalid response (label: `legalhold-status-bad`)" + "description": "Invalid invitation code. (label: `invalid-invitation-code`)" + } + }, + "summary": "Get the number of team members as an integer" + } + }, + "/time": { + "get": { + "description": " [internal route ID: \"get-server-time\"]\n\nReturns the current server time in UTC with seconds precision.", + "operationId": "get-server-time", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ServerTime_LTM4NTI3MzIx" + } + } + }, + "description": "" + } + }, + "summary": "Get the current server time" + } + }, + "/upgrade-personal-to-team": { + "post": { + "description": " [internal route ID: \"upgrade-personal-to-team\"]\n\n", + "operationId": "upgrade-personal-to-team", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/BindingNewTeamUser_LTY0MDQxMDEw" + } + } }, - "403": { + "required": true + }, + "responses": { + "200": { "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateUserTeam_MzI4NDQ1Mzkw" + } + }, "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CreateUserTeam_MzI4NDQ1Mzkw" + } + } + }, + "description": "Team created" + }, + "403": { + "content": { + "application/json": { "schema": { "example": { "code": 403, - "label": "legalhold-not-enabled", - "message": "legal hold is not enabled for this team" + "label": "user-already-in-a-team", + "message": "Switching teams is not allowed" }, "properties": { "code": { @@ -29132,10 +38283,7 @@ }, "label": { "enum": [ - "legalhold-not-enabled", - "operation-denied", - "no-team-member", - "action-denied" + "user-already-in-a-team" ], "type": "string" }, @@ -29150,29 +38298,24 @@ ], "type": "object" } - } - }, - "description": "legal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nInsufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)" - }, - "404": { - "content": { + }, "application/json;charset=utf-8": { "schema": { "example": { - "code": 404, - "label": "no-team-member", - "message": "Team member not found" + "code": 403, + "label": "user-already-in-a-team", + "message": "Switching teams is not allowed" }, "properties": { "code": { "enum": [ - 404 + 403 ], "type": "integer" }, "label": { "enum": [ - "no-team-member" + "user-already-in-a-team" ], "type": "string" }, @@ -29189,28 +38332,27 @@ } } }, - "description": "`tid` or `uid` not found\n\nTeam member not found (label: `no-team-member`)" + "description": "Switching teams is not allowed (label: `user-already-in-a-team`)" }, - "409": { + "404": { "content": { - "application/json;charset=utf-8": { + "application/json": { "schema": { "example": { - "code": 409, - "label": "legalhold-no-consent", - "message": "user has not given consent to using legal hold" + "code": 404, + "label": "not-found", + "message": "User not found" }, "properties": { "code": { "enum": [ - 409 + 404 ], "type": "integer" }, "label": { "enum": [ - "legalhold-no-consent", - "legalhold-already-enabled" + "not-found" ], "type": "string" }, @@ -29225,30 +38367,24 @@ ], "type": "object" } - } - }, - "description": "user has not given consent to using legal hold (label: `legalhold-no-consent`)\n\nlegal hold is already enabled for this user (label: `legalhold-already-enabled`)" - }, - "500": { - "content": { + }, "application/json;charset=utf-8": { "schema": { "example": { - "code": 500, - "label": "legalhold-illegal-op", - "message": "internal server error: inconsistent change of user's legalhold state" + "code": 404, + "label": "not-found", + "message": "User not found" }, "properties": { "code": { "enum": [ - 500 + 404 ], "type": "integer" }, "label": { "enum": [ - "legalhold-illegal-op", - "legalhold-internal" + "not-found" ], "type": "string" }, @@ -29265,40 +38401,131 @@ } } }, - "description": "internal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)\n\nlegal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)" + "description": "User not found (label: `not-found`)" } }, - "summary": "Request legal hold device" + "summary": "Upgrade personal user to team owner" } }, - "/teams/{tid}/legalhold/{uid}/approve": { - "put": { - "description": " [internal route ID: \"approve-legal-hold-device\"]\n\nThis endpoint can lead to the following events being sent:\n- ClientAdded event to the user owning the client (via brig)\n- UserLegalHoldEnabled event to contacts of the user owning the client (via brig)\n- ClientRemoved event to the user, if removing old client due to max number (via brig)
Calls federation service brig on get-users-by-ids
Calls federation service galley on on-mls-message-sent
Calls federation service galley on on-conversation-updated", + "/user-groups": { + "get": { + "description": " [internal route ID: \"get-user-groups\"]\n\n", + "operationId": "get-user-groups", "parameters": [ { - "in": "path", - "name": "tid", - "required": true, + "description": "Search string", + "in": "query", + "name": "q", + "required": false, "schema": { - "format": "uuid", "type": "string" } }, { - "in": "path", - "name": "uid", - "required": true, + "in": "query", + "name": "sort_by", + "required": false, + "schema": { + "enum": [ + "name", + "created_at" + ], + "type": "string" + } + }, + { + "in": "query", + "name": "sort_order", + "required": false, + "schema": { + "enum": [ + "asc", + "desc" + ], + "type": "string" + } + }, + { + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "description": "integer from [1..500]", + "type": "number" + } + }, + { + "description": "`name` of the last seen user group, used to get the next page when sorting by name.", + "in": "query", + "name": "last_seen_name", + "required": false, + "schema": { + "maxLength": 4000, + "minLength": 1, + "type": "string" + } + }, + { + "description": "`created_at` field of the last seen user group, used to get the next page when sorting by created_at.", + "in": "query", + "name": "last_seen_created_at", + "required": false, + "schema": { + "format": "yyyy-mm-ddThh:MM:ssZ", + "type": "string" + } + }, + { + "description": "`id` of the last seen group, used to get the next page. **Must** be sent to get the next page.", + "in": "query", + "name": "last_seen_id", + "required": false, "schema": { "format": "uuid", "type": "string" } + }, + { + "allowEmptyValue": true, + "in": "query", + "name": "include_channels", + "schema": { + "default": false, + "type": "boolean" + } + }, + { + "allowEmptyValue": true, + "in": "query", + "name": "include_member_count", + "schema": { + "default": false, + "type": "boolean" + } } ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserGroupPage_UserGroup_Const_LTMxNDg5MDAy" + } + } + }, + "description": "" + } + }, + "summary": "Fetch groups accessible to the logged-in user" + }, + "post": { + "description": " [internal route ID: \"create-user-group\"]\n\n", + "operationId": "create-user-group", "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ApproveLegalHoldForUserRequest" + "$ref": "#/components/schemas/NewUserGroup_MzYxODU0OTU1" } } }, @@ -29306,7 +38533,14 @@ }, "responses": { "200": { - "description": "Legal hold approved" + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserGroup_Identity_NTg4MTY1MjEx" + } + } + }, + "description": "" }, "400": { "content": { @@ -29314,8 +38548,8 @@ "schema": { "example": { "code": 400, - "label": "legalhold-not-registered", - "message": "legal hold service has not been registered for this team" + "label": "user-group-invalid", + "message": "Only team members of the same team can be added to a user group." }, "properties": { "code": { @@ -29326,7 +38560,7 @@ }, "label": { "enum": [ - "legalhold-not-registered" + "user-group-invalid" ], "type": "string" }, @@ -29343,7 +38577,7 @@ } } }, - "description": "Invalid `body`\n\nlegal hold service has not been registered for this team (label: `legalhold-not-registered`)" + "description": "Invalid `body`\n\nOnly team members of the same team can be added to a user group. (label: `user-group-invalid`)" }, "403": { "content": { @@ -29351,8 +38585,8 @@ "schema": { "example": { "code": 403, - "label": "legalhold-not-enabled", - "message": "legal hold is not enabled for this team" + "label": "user-group-write-forbidden", + "message": "Only team admins can create, update, or delete user groups." }, "properties": { "code": { @@ -29363,12 +38597,7 @@ }, "label": { "enum": [ - "legalhold-not-enabled", - "no-team-member", - "action-denied", - "access-denied", - "code-authentication-required", - "code-authentication-failed" + "user-group-write-forbidden" ], "type": "string" }, @@ -29385,101 +38614,83 @@ } } }, - "description": "legal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)\n\nYou do not have permission to access this resource (label: `access-denied`)\n\nVerification code required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nThis operation requires reauthentication (label: `access-denied`)" + "description": "Only team admins can create, update, or delete user groups. (label: `user-group-write-forbidden`)" + } + } + } + }, + "/user-groups/check-name": { + "post": { + "description": " [internal route ID: \"check-user-group-name-available\"]\n\n", + "operationId": "check-user-group-name-available", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CheckUserGroupName_LTg0ODU1OTk1" + } + } }, - "404": { + "required": true + }, + "responses": { + "200": { "content": { - "application/json;charset=utf-8": { + "application/json": { "schema": { - "example": { - "code": 404, - "label": "legalhold-no-device-allocated", - "message": "no legal hold device is registered for this user. POST /teams/:tid/legalhold/:uid/ to start the flow." - }, - "properties": { - "code": { - "enum": [ - 404 - ], - "type": "integer" - }, - "label": { - "enum": [ - "legalhold-no-device-allocated" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" + "$ref": "#/components/schemas/UserGroupNameAvailability_LTYzMDE1NTk4" } - } - }, - "description": "`tid` or `uid` not found\n\nno legal hold device is registered for this user. POST /teams/:tid/legalhold/:uid/ to start the flow. (label: `legalhold-no-device-allocated`)" - }, - "409": { - "content": { + }, "application/json;charset=utf-8": { "schema": { - "example": { - "code": 409, - "label": "legalhold-already-enabled", - "message": "legal hold is already enabled for this user" - }, - "properties": { - "code": { - "enum": [ - 409 - ], - "type": "integer" - }, - "label": { - "enum": [ - "legalhold-already-enabled" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" + "$ref": "#/components/schemas/UserGroupNameAvailability_LTYzMDE1NTk4" } } }, - "description": "legal hold is already enabled for this user (label: `legalhold-already-enabled`)" + "description": "OK" + } + }, + "summary": "[STUB] Check if a user group name is available" + } + }, + "/user-groups/{gid}": { + "delete": { + "description": " [internal route ID: \"delete-user-group\"]\n\n", + "operationId": "delete-user-group", + "parameters": [ + { + "in": "path", + "name": "gid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "User group deleted" }, - "412": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 412, - "label": "legalhold-not-pending", - "message": "legal hold cannot be approved without being in a pending state" + "code": 403, + "label": "user-group-write-forbidden", + "message": "Only team admins can create, update, or delete user groups." }, "properties": { "code": { "enum": [ - 412 + 403 ], "type": "integer" }, "label": { "enum": [ - "legalhold-not-pending" + "user-group-write-forbidden" ], "type": "string" }, @@ -29496,28 +38707,27 @@ } } }, - "description": "legal hold cannot be approved without being in a pending state (label: `legalhold-not-pending`)" + "description": "Only team admins can create, update, or delete user groups. (label: `user-group-write-forbidden`)" }, - "500": { + "404": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 500, - "label": "legalhold-internal", - "message": "legal hold service: could not block connections when resolving policy conflicts." + "code": 404, + "label": "user-group-not-found", + "message": "User group not found" }, "properties": { "code": { "enum": [ - 500 + 404 ], "type": "integer" }, "label": { "enum": [ - "legalhold-internal", - "legalhold-illegal-op" + "user-group-not-found" ], "type": "string" }, @@ -29534,19 +38744,17 @@ } } }, - "description": "legal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)\n\ninternal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)" + "description": "`gid` not found\n\nUser group not found (label: `user-group-not-found`)" } - }, - "summary": "Approve legal hold device" - } - }, - "/teams/{tid}/members": { + } + }, "get": { - "description": " [internal route ID: \"get-team-members\"]\n\n", + "description": " [internal route ID: \"get-user-group\"]\n\n", + "operationId": "get-user-group", "parameters": [ { "in": "path", - "name": "tid", + "name": "gid", "required": true, "schema": { "format": "uuid", @@ -29554,57 +38762,82 @@ } }, { - "description": "Maximum results to be returned", - "in": "query", - "name": "maxResults", - "required": false, - "schema": { - "format": "int32", - "maximum": 2000, - "minimum": 1, - "type": "integer" - } - }, - { - "description": "Optional, when not specified, the first page will be returned.Every returned page contains a `pagingState`, this should be supplied to retrieve the next page.", + "allowEmptyValue": true, "in": "query", - "name": "pagingState", - "required": false, + "name": "include_channels", "schema": { - "type": "string" + "default": false, + "type": "boolean" } } ], "responses": { "200": { "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserGroup_Identity_NTg4MTY1MjEx" + } + }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/TeamMembersPage" + "$ref": "#/components/schemas/UserGroup_Identity_NTg4MTY1MjEx" } } }, - "description": "" + "description": "User Group Found" }, - "403": { + "404": { "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "user-group-not-found", + "message": "User group not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "code": 404, + "label": "user-group-not-found", + "message": "User group not found" }, "properties": { "code": { "enum": [ - 403 + 404 ], "type": "integer" }, "label": { "enum": [ - "no-team-member" + "user-group-not-found" ], "type": "string" }, @@ -29621,17 +38854,18 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)" + "description": "`gid` or User group not found (label: `user-group-not-found`)\n\nUser group not found (label: `user-group-not-found`)" } }, - "summary": "Get team members" + "summary": "Fetch a group accessible to the logged-in user" }, "put": { - "description": " [internal route ID: \"update-team-member\"]\n\n", + "description": " [internal route ID: \"update-user-group\"]\n\n", + "operationId": "update-user-group", "parameters": [ { "in": "path", - "name": "tid", + "name": "gid", "required": true, "schema": { "format": "uuid", @@ -29643,7 +38877,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/NewTeamMember" + "$ref": "#/components/schemas/UserGroupUpdate_MjUyNTA3Mjgy" } } }, @@ -29651,7 +38885,7 @@ }, "responses": { "200": { - "description": "" + "description": "User added updated" }, "403": { "content": { @@ -29659,8 +38893,8 @@ "schema": { "example": { "code": 403, - "label": "operation-denied", - "message": "Insufficient permissions" + "label": "user-group-write-forbidden", + "message": "Only team admins can create, update, or delete user groups." }, "properties": { "code": { @@ -29671,11 +38905,7 @@ }, "label": { "enum": [ - "operation-denied", - "no-team-member", - "too-many-team-admins", - "invalid-permissions", - "access-denied" + "user-group-write-forbidden" ], "type": "string" }, @@ -29692,7 +38922,7 @@ } } }, - "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nMaximum number of admins per team reached (label: `too-many-team-admins`)\n\nThe specified permissions are invalid (label: `invalid-permissions`)\n\nYou do not have permission to access this resource (label: `access-denied`)" + "description": "Only team admins can create, update, or delete user groups. (label: `user-group-write-forbidden`)" }, "404": { "content": { @@ -29700,8 +38930,8 @@ "schema": { "example": { "code": 404, - "label": "no-team-member", - "message": "Team member not found" + "label": "user-group-not-found", + "message": "User group not found" }, "properties": { "code": { @@ -29712,70 +38942,7 @@ }, "label": { "enum": [ - "no-team-member", - "no-team" - ], - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "code", - "label", - "message" - ], - "type": "object" - } - } - }, - "description": "`tid` not found\n\nTeam member not found (label: `no-team-member`)\n\nTeam not found (label: `no-team`)" - } - }, - "summary": "Update an existing team member" - } - }, - "/teams/{tid}/members/csv": { - "get": { - "description": " [internal route ID: \"get-team-members-csv\"]\n\nThe endpoint returns data in chunked transfer encoding. Internal server errors might result in a failed transfer instead of a 500 response.", - "parameters": [ - { - "in": "path", - "name": "tid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "text/csv": {} - }, - "description": "CSV of team members" - }, - "403": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "example": { - "code": 403, - "label": "access-denied", - "message": "You do not have permission to access this resource" - }, - "properties": { - "code": { - "enum": [ - 403 - ], - "type": "integer" - }, - "label": { - "enum": [ - "access-denied" + "user-group-not-found" ], "type": "string" }, @@ -29792,19 +38959,19 @@ } } }, - "description": "You do not have permission to access this resource (label: `access-denied`)" - } - }, - "summary": "Get all members of the team as a CSV file" + "description": "`gid` not found\n\nUser group not found (label: `user-group-not-found`)" + } + } } }, - "/teams/{tid}/members/{uid}": { - "delete": { - "description": " [internal route ID: \"delete-team-member\"]\n\n", + "/user-groups/{gid}/channels": { + "put": { + "description": " [internal route ID: \"update-user-group-channels\"]\n\n", + "operationId": "update-user-group-channels", "parameters": [ { "in": "path", - "name": "tid", + "name": "gid", "required": true, "schema": { "format": "uuid", @@ -29812,12 +38979,12 @@ } }, { - "in": "path", - "name": "uid", - "required": true, + "allowEmptyValue": true, + "in": "query", + "name": "append_only", "schema": { - "format": "uuid", - "type": "string" + "default": false, + "type": "boolean" } } ], @@ -29825,7 +38992,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/TeamMemberDeleteData" + "$ref": "#/components/schemas/UpdateUserGroupChannels_LTIyMjcwMTMx" } } }, @@ -29833,10 +39000,7 @@ }, "responses": { "200": { - "description": "" - }, - "202": { - "description": "Team member scheduled for deletion" + "description": "User group channels updated" }, "403": { "content": { @@ -29844,8 +39008,8 @@ "schema": { "example": { "code": 403, - "label": "operation-denied", - "message": "Insufficient permissions" + "label": "user-group-write-forbidden", + "message": "Only team admins can create, update, or delete user groups." }, "properties": { "code": { @@ -29856,11 +39020,7 @@ }, "label": { "enum": [ - "operation-denied", - "no-team-member", - "access-denied", - "code-authentication-required", - "code-authentication-failed" + "user-group-write-forbidden" ], "type": "string" }, @@ -29877,7 +39037,7 @@ } } }, - "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nYou do not have permission to access this resource (label: `access-denied`)\n\nVerification code required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nThis operation requires reauthentication (label: `access-denied`)" + "description": "Only team admins can create, update, or delete user groups. (label: `user-group-write-forbidden`)" }, "404": { "content": { @@ -29885,8 +39045,8 @@ "schema": { "example": { "code": 404, - "label": "no-team", - "message": "Team not found" + "label": "user-group-not-found", + "message": "User group not found" }, "properties": { "code": { @@ -29897,8 +39057,7 @@ }, "label": { "enum": [ - "no-team", - "no-team-member" + "user-group-not-found" ], "type": "string" }, @@ -29915,26 +39074,20 @@ } } }, - "description": "`tid` or `uid` not found\n\nTeam not found (label: `no-team`)\n\nTeam member not found (label: `no-team-member`)" + "description": "`gid` not found\n\nUser group not found (label: `user-group-not-found`)" } }, - "summary": "Remove an existing team member" - }, - "get": { - "description": " [internal route ID: \"get-team-member\"]\n\n", + "summary": "Replaces the channels with the given list." + } + }, + "/user-groups/{gid}/users": { + "post": { + "description": " [internal route ID: \"add-users-to-group-bulk\"]\n\n", + "operationId": "add-users-to-group-bulk", "parameters": [ { "in": "path", - "name": "tid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - }, - { - "in": "path", - "name": "uid", + "name": "gid", "required": true, "schema": { "format": "uuid", @@ -29942,16 +39095,56 @@ } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserGroupAddUsers_LTgzOTYzNzk0" + } + } + }, + "required": true + }, "responses": { - "200": { + "204": { + "description": "Users added to group" + }, + "400": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/TeamMember" + "example": { + "code": 400, + "label": "user-group-invalid", + "message": "Only team members of the same team can be added to a user group." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-invalid" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" } } }, - "description": "" + "description": "Invalid `body`\n\nOnly team members of the same team can be added to a user group. (label: `user-group-invalid`)" }, "403": { "content": { @@ -29959,8 +39152,8 @@ "schema": { "example": { "code": 403, - "label": "no-team-member", - "message": "Requesting user is not a team member" + "label": "user-group-write-forbidden", + "message": "Only team admins can create, update, or delete user groups." }, "properties": { "code": { @@ -29971,7 +39164,7 @@ }, "label": { "enum": [ - "no-team-member" + "user-group-write-forbidden" ], "type": "string" }, @@ -29988,7 +39181,7 @@ } } }, - "description": "Requesting user is not a team member (label: `no-team-member`)" + "description": "Only team admins can create, update, or delete user groups. (label: `user-group-write-forbidden`)" }, "404": { "content": { @@ -29996,8 +39189,8 @@ "schema": { "example": { "code": 404, - "label": "no-team-member", - "message": "Team member not found" + "label": "user-group-not-found", + "message": "User group not found" }, "properties": { "code": { @@ -30008,7 +39201,7 @@ }, "label": { "enum": [ - "no-team-member" + "user-group-not-found" ], "type": "string" }, @@ -30025,132 +39218,59 @@ } } }, - "description": "`tid` or `uid` not found\n\nTeam member not found (label: `no-team-member`)" + "description": "`gid` not found\n\nUser group not found (label: `user-group-not-found`)" } - }, - "summary": "Get single team member" - } - }, - "/teams/{tid}/search": { - "get": { - "description": " [internal route ID: \"browse-team\"]\n\n", + } + }, + "put": { + "description": " [internal route ID: \"update-user-group-members\"]\n\n", + "operationId": "update-user-group-members", "parameters": [ { "in": "path", - "name": "tid", + "name": "gid", "required": true, "schema": { "format": "uuid", "type": "string" } - }, - { - "description": "Search expression", - "in": "query", - "name": "q", - "required": false, - "schema": { - "type": "string" - } - }, - { - "description": "Role filter, eg. `member,partner`. Empty list means do not filter.", - "in": "query", - "name": "frole", - "required": false, - "schema": { - "items": { - "enum": [ - "owner", - "admin", - "member", - "partner" - ], - "type": "string" - }, - "type": "array" - } - }, - { - "description": "Can be one of name, handle, email, saml_idp, managed_by, role, created_at.", - "in": "query", - "name": "sortby", - "required": false, - "schema": { - "enum": [ - "name", - "handle", - "email", - "saml_idp", - "managed_by", - "role", - "created_at" - ], - "type": "string" - } - }, - { - "description": "Can be one of asc, desc.", - "in": "query", - "name": "sortorder", - "required": false, - "schema": { - "enum": [ - "asc", - "desc" - ], - "type": "string" - } - }, - { - "description": "Number of results to return (min: 1, max: 500, default: 15)", - "in": "query", - "name": "size", - "required": false, - "schema": { - "format": "int32", - "maximum": 500, - "minimum": 1, - "type": "integer" - } - }, - { - "description": "Optional, when not specified, the first page will be returned. Every returned page contains a `paging_state`, this should be supplied to retrieve the next page.", - "in": "query", - "name": "pagingState", - "required": false, - "schema": { - "type": "string" - } } ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UpdateUserGroupMembers_LTg1MzQ2NDY3" + } + } + }, + "required": true + }, "responses": { "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SearchResult" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/SearchResult" - } - } - }, - "description": "Search results" + "description": "User group members updated" } }, - "summary": "Browse team for members (requires add-user permission)" + "summary": "[STUB] Update user group members. Replaces the users with the given list." } }, - "/teams/{tid}/search-visibility": { - "get": { - "description": " [internal route ID: \"get-search-visibility\"]\n\n", + "/user-groups/{gid}/users/{uid}": { + "delete": { + "description": " [internal route ID: \"remove-user-from-group\"]\n\n", + "operationId": "remove-user-from-group", "parameters": [ { "in": "path", - "name": "tid", + "name": "gid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "uid", "required": true, "schema": { "format": "uuid", @@ -30159,36 +39279,28 @@ } ], "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/TeamSearchVisibilityView" - } - } - }, - "description": "" + "204": { + "description": "User removed from group" }, - "403": { + "400": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 403, - "label": "operation-denied", - "message": "Insufficient permissions" + "code": 400, + "label": "user-group-invalid", + "message": "Only team members of the same team can be added to a user group." }, "properties": { "code": { "enum": [ - 403 + 400 ], "type": "integer" }, "label": { "enum": [ - "operation-denied", - "no-team-member" + "user-group-invalid" ], "type": "string" }, @@ -30205,37 +39317,7 @@ } } }, - "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" - } - }, - "summary": "Shows the value for search visibility" - }, - "put": { - "description": " [internal route ID: \"set-search-visibility\"]\n\n", - "parameters": [ - { - "in": "path", - "name": "tid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/TeamSearchVisibilityView" - } - } - }, - "required": true - }, - "responses": { - "204": { - "description": "Search visibility set" + "description": "Only team members of the same team can be added to a user group. (label: `user-group-invalid`)" }, "403": { "content": { @@ -30243,8 +39325,8 @@ "schema": { "example": { "code": 403, - "label": "team-search-visibility-not-enabled", - "message": "Custom search is not available for this team" + "label": "user-group-write-forbidden", + "message": "Only team admins can create, update, or delete user groups." }, "properties": { "code": { @@ -30255,9 +39337,7 @@ }, "label": { "enum": [ - "team-search-visibility-not-enabled", - "operation-denied", - "no-team-member" + "user-group-write-forbidden" ], "type": "string" }, @@ -30274,7 +39354,7 @@ } } }, - "description": "Custom search is not available for this team (label: `team-search-visibility-not-enabled`)\n\nInsufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" + "description": "Only team admins can create, update, or delete user groups. (label: `user-group-write-forbidden`)" }, "404": { "content": { @@ -30282,8 +39362,8 @@ "schema": { "example": { "code": 404, - "label": "no-team", - "message": "Team not found" + "label": "user-group-not-found", + "message": "User group not found" }, "properties": { "code": { @@ -30294,7 +39374,7 @@ }, "label": { "enum": [ - "no-team" + "user-group-not-found" ], "type": "string" }, @@ -30311,19 +39391,26 @@ } } }, - "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + "description": "`gid` or `uid` not found\n\nUser group not found (label: `user-group-not-found`)" } - }, - "summary": "Sets the search visibility for the whole team" - } - }, - "/teams/{tid}/size": { - "get": { - "description": " [internal route ID: \"get-team-size\"]\n\nCan be out of sync by roughly the `refresh_interval` of the ES index.", + } + }, + "post": { + "description": " [internal route ID: \"add-user-to-group\"]\n\n", + "operationId": "add-user-to-group", "parameters": [ { "in": "path", - "name": "tid", + "name": "gid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "uid", "required": true, "schema": { "format": "uuid", @@ -30332,20 +39419,8 @@ } ], "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TeamSize" - } - }, - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/TeamSize" - } - } - }, - "description": "Number of team members" + "204": { + "description": "User added to group" }, "400": { "content": { @@ -30353,8 +39428,8 @@ "schema": { "example": { "code": 400, - "label": "invalid-invitation-code", - "message": "Invalid invitation code." + "label": "user-group-invalid", + "message": "Only team members of the same team can be added to a user group." }, "properties": { "code": { @@ -30365,7 +39440,7 @@ }, "label": { "enum": [ - "invalid-invitation-code" + "user-group-invalid" ], "type": "string" }, @@ -30382,105 +39457,27 @@ } } }, - "description": "Invalid invitation code. (label: `invalid-invitation-code`)" - } - }, - "summary": "Get the number of team members as an integer" - } - }, - "/users/handles": { - "post": { - "description": " [internal route ID: \"check-user-handles\"]\n\n", - "requestBody": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "$ref": "#/components/schemas/CheckHandles" - } - } - }, - "required": true - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/Handle" - }, - "type": "array" - } - }, - "application/json;charset=utf-8": { - "schema": { - "items": { - "$ref": "#/components/schemas/Handle" - }, - "type": "array" - } - } - }, - "description": "List of free handles" - } - }, - "summary": "Check availability of user handles" - } - }, - "/users/handles/{handle}": { - "head": { - "description": " [internal route ID: \"check-user-handle\"]\n\n", - "parameters": [ - { - "in": "path", - "name": "handle", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "example": [], - "items": {}, - "maxItems": 0, - "type": "array" - } - }, - "application/json;charset=utf-8": { - "schema": { - "example": [], - "items": {}, - "maxItems": 0, - "type": "array" - } - } - }, - "description": "Handle is taken" + "description": "Only team members of the same team can be added to a user group. (label: `user-group-invalid`)" }, - "400": { + "403": { "content": { "application/json;charset=utf-8": { "schema": { "example": { - "code": 400, - "label": "invalid-handle", - "message": "The given handle is invalid (less than 2 or more than 256 characters; chars not in \"a-z0-9_.-\"; or on the blocklist)" + "code": 403, + "label": "user-group-write-forbidden", + "message": "Only team admins can create, update, or delete user groups." }, "properties": { "code": { "enum": [ - 400 + 403 ], "type": "integer" }, "label": { "enum": [ - "invalid-handle" + "user-group-write-forbidden" ], "type": "string" }, @@ -30497,7 +39494,7 @@ } } }, - "description": "The given handle is invalid (less than 2 or more than 256 characters; chars not in \"a-z0-9_.-\"; or on the blocklist) (label: `invalid-handle`)" + "description": "Only team admins can create, update, or delete user groups. (label: `user-group-write-forbidden`)" }, "404": { "content": { @@ -30505,8 +39502,8 @@ "schema": { "example": { "code": 404, - "label": "not-found", - "message": "Handle not found" + "label": "user-group-not-found", + "message": "User group not found" }, "properties": { "code": { @@ -30517,7 +39514,7 @@ }, "label": { "enum": [ - "not-found" + "user-group-not-found" ], "type": "string" }, @@ -30534,15 +39531,15 @@ } } }, - "description": "`handle` not found\n\nHandle not found (label: `not-found`)" + "description": "`gid` or `uid` not found\n\nUser group not found (label: `user-group-not-found`)" } - }, - "summary": "Check whether a user handle can be taken" + } } }, "/users/list-clients": { "post": { - "description": " [internal route ID: \"list-clients-bulk@v2\"]\n\nIf a backend is unreachable, the clients from that backend will be omitted from the responseCalls federation service brig on get-user-clients", + "description": " [internal route ID: \"list-clients-bulk@v2\"]\n\nIf a backend is unreachable, the clients from that backend will be omitted from the response", + "operationId": "list-clients-bulk@v2", "requestBody": { "content": { "application/json;charset=utf-8": { @@ -30575,7 +39572,8 @@ }, "/users/list-prekeys": { "post": { - "description": " [internal route ID: \"get-multi-user-prekey-bundle-qualified\"]\n\nYou can't request information for more users than maximum conversation size.Calls federation service brig on claim-multi-prekey-bundle", + "description": " [internal route ID: \"get-multi-user-prekey-bundle-qualified\"]\n\nYou can't request information for more users than maximum conversation size.", + "operationId": "get-multi-user-prekey-bundle-qualified", "requestBody": { "content": { "application/json;charset=utf-8": { @@ -30591,7 +39589,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/QualifiedUserClientPrekeyMapV4" + "$ref": "#/components/schemas/QualifiedUserClientPrekeyMapV4_MzcxOTAxMTYy" } } }, @@ -30603,7 +39601,8 @@ }, "/users/{uid_domain}/{uid}": { "get": { - "description": " [internal route ID: \"get-user-qualified\"]\n\nCalls federation service brig on get-users-by-ids", + "description": " [internal route ID: \"get-user-qualified\"]\n\n", + "operationId": "get-user-qualified", "parameters": [ { "in": "path", @@ -30629,12 +39628,12 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UserProfile" + "$ref": "#/components/schemas/UserProfile_LTQzMTQxMTE1" } }, "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/UserProfile" + "$ref": "#/components/schemas/UserProfile_LTQzMTQxMTE1" } } }, @@ -30713,50 +39712,10 @@ "summary": "Get a user by Domain and UserId" } }, - "/users/{uid_domain}/{uid}/clients": { - "get": { - "description": " [internal route ID: \"get-user-clients-qualified\"]\n\nCalls federation service brig on get-user-clients", - "parameters": [ - { - "in": "path", - "name": "uid_domain", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "User Id", - "in": "path", - "name": "uid", - "required": true, - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json;charset=utf-8": { - "schema": { - "items": { - "$ref": "#/components/schemas/PubClient" - }, - "type": "array" - } - } - }, - "description": "" - } - }, - "summary": "Get all of a user's clients" - } - }, "/users/{uid_domain}/{uid}/clients/{client}": { "get": { - "description": " [internal route ID: \"get-user-client-qualified\"]\n\nCalls federation service brig on get-user-clients", + "description": " [internal route ID: \"get-user-client-qualified\"]\n\nHint: to list all clients of one or more users, use POST /users/list-clients.", + "operationId": "get-user-client-qualified", "parameters": [ { "in": "path", @@ -30803,7 +39762,8 @@ }, "/users/{uid_domain}/{uid}/prekeys": { "get": { - "description": " [internal route ID: \"get-users-prekey-bundle-qualified\"]\n\nCalls federation service brig on claim-prekey-bundle", + "description": " [internal route ID: \"get-users-prekey-bundle-qualified\"]\n\n", + "operationId": "get-users-prekey-bundle-qualified", "parameters": [ { "in": "path", @@ -30829,7 +39789,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/PrekeyBundle" + "$ref": "#/components/schemas/PrekeyBundle_MzgzOTk4MjYz" } } }, @@ -30841,7 +39801,8 @@ }, "/users/{uid_domain}/{uid}/prekeys/{client}": { "get": { - "description": " [internal route ID: \"get-users-prekeys-client-qualified\"]\n\nCalls federation service brig on claim-prekey", + "description": " [internal route ID: \"get-users-prekeys-client-qualified\"]\n\n", + "operationId": "get-users-prekeys-client-qualified", "parameters": [ { "in": "path", @@ -30876,7 +39837,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/ClientPrekey" + "$ref": "#/components/schemas/ClientPrekey_LTcyODUzMTcw" } } }, @@ -30889,6 +39850,7 @@ "/users/{uid_domain}/{uid}/supported-protocols": { "get": { "description": " [internal route ID: \"get-supported-protocols\"]\n\n", + "operationId": "get-supported-protocols", "parameters": [ { "in": "path", @@ -30915,7 +39877,7 @@ "application/json": { "schema": { "items": { - "$ref": "#/components/schemas/BaseProtocol" + "$ref": "#/components/schemas/BaseProtocolTag_LTM0MDE1NTEx" }, "type": "array", "uniqueItems": true @@ -30924,7 +39886,7 @@ "application/json;charset=utf-8": { "schema": { "items": { - "$ref": "#/components/schemas/BaseProtocol" + "$ref": "#/components/schemas/BaseProtocolTag_LTM0MDE1NTEx" }, "type": "array", "uniqueItems": true @@ -30940,6 +39902,7 @@ "/users/{uid}/email": { "put": { "description": " [internal route ID: \"update-user-email\"]\n\nIf the user has a pending email validation, the validation email will be resent.", + "operationId": "update-user-email", "parameters": [ { "description": "User Id", @@ -30956,7 +39919,7 @@ "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/EmailUpdate" + "$ref": "#/components/schemas/EmailUpdate_NjQ5MDg1OTY0" } } }, @@ -30983,6 +39946,7 @@ "/users/{uid}/rich-info": { "get": { "description": " [internal route ID: \"get-rich-info\"]\n\n", + "operationId": "get-rich-info", "parameters": [ { "description": "User Id", @@ -31052,14 +40016,59 @@ "summary": "Get a user's rich info" } }, + "/users/{uid}/searchable": { + "post": { + "description": " [internal route ID: \"set-user-searchable\"]\n\n", + "operationId": "set-user-searchable", + "parameters": [ + { + "description": "User Id", + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/SetSearchable_NDAxODAxODI5" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + } + }, + "description": "" + } + }, + "summary": "Set user's visibility in search" + } + }, "/verification-code/send": { "post": { "description": " [internal route ID: \"send-verification-code\"]\n\n", + "operationId": "send-verification-code", "requestBody": { "content": { "application/json;charset=utf-8": { "schema": { - "$ref": "#/components/schemas/SendVerificationCode" + "$ref": "#/components/schemas/SendVerificationCode_MjgxNDgxODE2" } } }, @@ -31072,6 +40081,36 @@ }, "summary": "Send a verification code to a given email address." } + }, + "/websocket": { + "get": { + "description": " [internal route ID: \"websocket\"]\n\nThis is a temporary copy of await, please do not use it", + "externalDocs": { + "description": "RFC 6455", + "url": "https://datatracker.ietf.org/doc/html/rfc6455" + }, + "operationId": "websocket", + "parameters": [ + { + "description": "Client ID", + "in": "query", + "name": "client", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "101": { + "description": "Connection upgraded." + }, + "426": { + "description": "Upgrade required." + } + }, + "summary": "Establish websocket connection" + } } }, "security": [ @@ -31081,7 +40120,7 @@ ], "servers": [ { - "url": "/v6" + "url": "/v17" } ] } diff --git a/services/brig/docs/swagger-v18.json b/services/brig/docs/swagger-v18.json new file mode 100644 index 00000000000..e0f697799f4 --- /dev/null +++ b/services/brig/docs/swagger-v18.json @@ -0,0 +1,40127 @@ +{ + "components": { + "schemas": { + "ASCII": { + "example": "aGVsbG8", + "type": "string" + }, + "AcceptTeamInvitation_Nzg5NzI3MjA2": { + "description": "Accept an invitation to join a team on Wire.", + "properties": { + "code": { + "$ref": "#/components/schemas/ASCII" + }, + "password": { + "description": "The user account password.", + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "required": [ + "code", + "password" + ], + "type": "object" + }, + "AccessRoleLegacy_LTYwOTAxMDI1": { + "deprecated": true, + "description": "Deprecated, please use access_role_v2", + "enum": [ + "private", + "team", + "activated", + "non_activated" + ], + "type": "string" + }, + "AccessRole_Mzk3MDYzMzcw": { + "description": "Which users/services can join conversations. This replaces legacy access roles and allows a more fine grained configuration of access roles, and in particular a separation of guest and services access.\n\nThis field is optional. If it is not present, the default will be `[team_member, non_team_member, service]`. Please note that an empty list is not allowed when creating a new conversation.", + "enum": [ + "team_member", + "non_team_member", + "guest", + "service" + ], + "type": "string" + }, + "AccessTokenType_LTgyOTY0NDE5": { + "enum": [ + "DPoP" + ], + "type": "string" + }, + "AccessToken_ODIyMTczMjMw": { + "properties": { + "access_token": { + "description": "The opaque access token string", + "type": "string" + }, + "expires_in": { + "description": "The number of seconds this token is valid", + "type": "integer" + }, + "token_type": { + "$ref": "#/components/schemas/TokenType_NTkyMzk4MjIz" + }, + "user": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "user", + "access_token", + "token_type", + "expires_in" + ], + "type": "object" + }, + "Access_NjkyMzE5ODc0": { + "description": "How users can join conversations", + "enum": [ + "private", + "invite", + "link", + "code" + ], + "type": "string" + }, + "AccountStatus_NzkzNDU1ODU5": { + "enum": [ + "active", + "suspended", + "deleted", + "ephemeral", + "pending-invitation" + ], + "type": "string" + }, + "Action": { + "enum": [ + "add_conversation_member", + "remove_conversation_member", + "modify_conversation_name", + "modify_conversation_message_timer", + "modify_conversation_receipt_mode", + "modify_conversation_access", + "modify_other_conversation_member", + "leave_conversation", + "delete_conversation", + "modify_add_permission" + ], + "type": "string" + }, + "Activate_MzUzNzIxODUw": { + "description": "Data for an activation request.", + "properties": { + "code": { + "$ref": "#/components/schemas/ASCII" + }, + "dryrun": { + "description": "At least one of key, email, or phone has to be present while key takes precedence over email, and email takes precedence over phone. Whether to perform a dryrun, i.e. to only check whether activation would succeed. Dry-runs never issue access cookies or tokens on success but failures still count towards the maximum failure count.", + "type": "boolean" + }, + "email": { + "$ref": "#/components/schemas/Email" + }, + "key": { + "$ref": "#/components/schemas/ASCII" + } + }, + "required": [ + "code", + "dryrun" + ], + "type": "object" + }, + "ActivationResponse_LTIyOTY5NDE3": { + "description": "Response body of a successful activation request", + "properties": { + "email": { + "$ref": "#/components/schemas/Email" + }, + "first": { + "description": "Whether this is the first successful activation (i.e. account activation).", + "type": "boolean" + }, + "sso_id": { + "$ref": "#/components/schemas/UserSSOId" + } + }, + "type": "object" + }, + "AddBotResponse_ODA5MzA2NTA1": { + "properties": { + "accent_id": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "assets": { + "items": { + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" + }, + "type": "array" + }, + "client": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" + }, + "event": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "id", + "client", + "name", + "accent_id", + "assets", + "event" + ], + "type": "object" + }, + "AddBot_NjI0ODkyODk3": { + "properties": { + "locale": { + "$ref": "#/components/schemas/Locale" + }, + "provider": { + "$ref": "#/components/schemas/UUID" + }, + "service": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "provider", + "service" + ], + "type": "object" + }, + "AddPermissionUpdate_LTU3MzEwOTY4": { + "description": "The action of changing the permission to add members to a channel", + "properties": { + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + } + }, + "required": [ + "add_permission" + ], + "type": "object" + }, + "AddPermission_LTE1MzgzNzE3": { + "enum": [ + "admins", + "everyone" + ], + "type": "string" + }, + "AdminlessReminder_LTkyMDUxNTk5": { + "properties": { + "deletion_scheduled_for": { + "$ref": "#/components/schemas/UTCTimeMillis" + } + }, + "required": [ + "deletion_scheduled_for" + ], + "type": "object" + }, + "AllowedGlobalOperationsConfig_MzAwOTU1MDkx": { + "properties": { + "mlsConversationReset": { + "type": "boolean" + } + }, + "required": [ + "mlsConversationReset" + ], + "type": "object" + }, + "Alpha_LTE4NDUxNDQ4": { + "description": "ISO 4217 alphabetic codes. This is only stored by the backend, not processed. It can be removed once billing supports currency changes after team creation.", + "enum": [ + "AED", + "AFN", + "ALL", + "AMD", + "ANG", + "AOA", + "ARS", + "AUD", + "AWG", + "AZN", + "BAM", + "BBD", + "BDT", + "BGN", + "BHD", + "BIF", + "BMD", + "BND", + "BOB", + "BOV", + "BRL", + "BSD", + "BTN", + "BWP", + "BYN", + "BZD", + "CAD", + "CDF", + "CHE", + "CHF", + "CHW", + "CLF", + "CLP", + "CNY", + "COP", + "COU", + "CRC", + "CUC", + "CUP", + "CVE", + "CZK", + "DJF", + "DKK", + "DOP", + "DZD", + "EGP", + "ERN", + "ETB", + "EUR", + "FJD", + "FKP", + "GBP", + "GEL", + "GHS", + "GIP", + "GMD", + "GNF", + "GTQ", + "GYD", + "HKD", + "HNL", + "HRK", + "HTG", + "HUF", + "IDR", + "ILS", + "INR", + "IQD", + "IRR", + "ISK", + "JMD", + "JOD", + "JPY", + "KES", + "KGS", + "KHR", + "KMF", + "KPW", + "KRW", + "KWD", + "KYD", + "KZT", + "LAK", + "LBP", + "LKR", + "LRD", + "LSL", + "LYD", + "MAD", + "MDL", + "MGA", + "MKD", + "MMK", + "MNT", + "MOP", + "MRO", + "MUR", + "MVR", + "MWK", + "MXN", + "MXV", + "MYR", + "MZN", + "NAD", + "NGN", + "NIO", + "NOK", + "NPR", + "NZD", + "OMR", + "PAB", + "PEN", + "PGK", + "PHP", + "PKR", + "PLN", + "PYG", + "QAR", + "RON", + "RSD", + "RUB", + "RWF", + "SAR", + "SBD", + "SCR", + "SDG", + "SEK", + "SGD", + "SHP", + "SLL", + "SOS", + "SRD", + "SSP", + "STD", + "SVC", + "SYP", + "SZL", + "THB", + "TJS", + "TMT", + "TND", + "TOP", + "TRY", + "TTD", + "TWD", + "TZS", + "UAH", + "UGX", + "USD", + "USN", + "UYI", + "UYU", + "UZS", + "VEF", + "VND", + "VUV", + "WST", + "XAF", + "XAG", + "XAU", + "XBA", + "XBB", + "XBC", + "XBD", + "XCD", + "XDR", + "XOF", + "XPD", + "XPF", + "XPT", + "XSU", + "XTS", + "XUA", + "XXX", + "YER", + "ZAR", + "ZMW", + "ZWL" + ], + "example": "EUR", + "type": "string" + }, + "AppInfo_MjgwNTkwOTUz": { + "properties": { + "category": { + "description": "Category name (if uncertain, pick \"other\")", + "type": "string" + }, + "description": { + "maxLength": 300, + "minLength": 0, + "type": "string" + } + }, + "required": [ + "category", + "description" + ], + "type": "object" + }, + "AppLockConfigB_Covered_Identity_NDIxOTc2Njkz": { + "properties": { + "enforceAppLock": { + "type": "boolean" + }, + "inactivityTimeoutSecs": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + } + }, + "required": [ + "enforceAppLock", + "inactivityTimeoutSecs" + ], + "type": "object" + }, + "ApproveLegalHoldForUserRequest_NjEyNzYyMTIx": { + "properties": { + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "type": "object" + }, + "AssetKey": { + "description": "S3 asset key for an icon image with retention information.", + "example": "3-1-47de4580-ae51-4650-acbb-d10c028cb0ac", + "type": "string" + }, + "AssetSize_OTAwMDA3ODY2": { + "enum": [ + "preview", + "complete" + ], + "type": "string" + }, + "AssetSource": {}, + "Asset_LTIyMjc1NDEz": { + "properties": { + "key": { + "$ref": "#/components/schemas/AssetKey" + }, + "size": { + "$ref": "#/components/schemas/AssetSize_OTAwMDA3ODY2" + }, + "type": { + "$ref": "#/components/schemas/MTYxOTI3NjM3" + } + }, + "required": [ + "key", + "type" + ], + "type": "object" + }, + "Asset_Qualified_AssetKey_MzU1MjMxNTA5": { + "properties": { + "domain": { + "$ref": "#/components/schemas/Domain" + }, + "expires": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "key": { + "$ref": "#/components/schemas/AssetKey" + }, + "token": { + "$ref": "#/components/schemas/ASCII" + } + }, + "required": [ + "key", + "domain" + ], + "type": "object" + }, + "AuthSFTServer_LTY5MzcyOTE0": { + "description": "Inspired by WebRTC 'RTCIceServer' object, contains details of SFT servers", + "properties": { + "credential": { + "$ref": "#/components/schemas/ASCII" + }, + "urls": { + "description": "Array containing exactly one SFT server address of the form 'https://:'", + "items": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "type": "array" + }, + "username": { + "$ref": "#/components/schemas/SFTUsername" + } + }, + "required": [ + "urls" + ], + "type": "object" + }, + "AuthnRequest": { + "properties": { + "iD": { + "$ref": "#/components/schemas/Id_AuthnRequest" + }, + "issueInstant": { + "$ref": "#/components/schemas/Time" + }, + "issuer": { + "$ref": "#/components/schemas/URI" + }, + "nameIDPolicy": { + "$ref": "#/components/schemas/NameIdPolicy" + } + }, + "required": [ + "iD", + "issueInstant", + "issuer" + ], + "type": "object" + }, + "Base64ByteString": { + "example": "ZXhhbXBsZQo=", + "type": "string" + }, + "Base64URLByteString": { + "example": "ZXhhbXBsZQo=", + "type": "string" + }, + "BaseProtocolTag_LTM0MDE1NTEx": { + "enum": [ + "proteus", + "mls" + ], + "type": "string" + }, + "BindingNewTeamUser_LTY0MDQxMDEw": { + "properties": { + "currency": { + "$ref": "#/components/schemas/Alpha_LTE4NDUxNDQ4" + }, + "icon": { + "$ref": "#/components/schemas/Icon" + }, + "icon_key": { + "description": "The decryption key for the team icon S3 asset", + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "name": { + "description": "team name", + "maxLength": 256, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "name", + "icon" + ], + "type": "object" + }, + "BotConvView_LTYzMjIzMjQz": { + "properties": { + "id": { + "$ref": "#/components/schemas/UUID" + }, + "members": { + "items": { + "$ref": "#/components/schemas/OtherMember_LTgzNzE2MTk4" + }, + "type": "array" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "members" + ], + "type": "object" + }, + "BotUserView_LTE2MTkwMTcw": { + "properties": { + "accent_id": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "handle": { + "$ref": "#/components/schemas/Handle" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "team": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "id", + "name", + "accent_id" + ], + "type": "object" + }, + "CellsBackend_LTE1Nzg3NzQ2": { + "properties": { + "url": { + "$ref": "#/components/schemas/HttpsUrl" + } + }, + "required": [ + "url" + ], + "type": "object" + }, + "CellsCollaboraStatus_MTgzNTQyNzUz": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ], + "type": "object" + }, + "CellsCollabora_LTMzNDA5MDIz": { + "properties": { + "edition": { + "$ref": "#/components/schemas/CollaboraEdition_LTg2NDA1NDQ4" + } + }, + "required": [ + "edition" + ], + "type": "object" + }, + "CellsConfigB_Covered_Identity_LTE1NzkwOTcz": { + "example": { + "channels": { + "default": "enabled", + "enabled": true + }, + "collabora": { + "enabled": false + }, + "groups": { + "default": "enabled", + "enabled": true + }, + "metadata": { + "namespaces": { + "usermetaTags": { + "allowFreeValues": true, + "defaultValues": [] + } + } + }, + "one2one": { + "default": "enabled", + "enabled": true + }, + "publicLinks": { + "enableFiles": true, + "enableFolders": true, + "enforceExpirationDefault": 0, + "enforceExpirationMax": 0, + "enforcePassword": false + }, + "storage": { + "perFileQuotaBytes": "100000000", + "recycle": { + "allowSkip": false, + "autoPurgeDays": 30, + "disable": false + } + }, + "users": { + "externals": true, + "guests": false + } + }, + "properties": { + "channels": { + "$ref": "#/components/schemas/CellsProperty_NzcxMDIzMzk0" + }, + "collabora": { + "$ref": "#/components/schemas/CellsCollaboraStatus_MTgzNTQyNzUz" + }, + "groups": { + "$ref": "#/components/schemas/CellsProperty_NzcxMDIzMzk0" + }, + "metadata": { + "$ref": "#/components/schemas/CellsMetadata_LTY1OTM5MTM0" + }, + "one2one": { + "$ref": "#/components/schemas/CellsProperty_NzcxMDIzMzk0" + }, + "publicLinks": { + "$ref": "#/components/schemas/CellsPublicLinks_MjgxMzQ3Mzk4" + }, + "storage": { + "$ref": "#/components/schemas/CellsConfigStorage_LTM0NDMwODM4" + }, + "users": { + "$ref": "#/components/schemas/CellsUsers_LTQ4NTEyODA1" + } + }, + "required": [ + "channels", + "groups", + "one2one", + "users", + "collabora", + "publicLinks", + "storage", + "metadata" + ], + "type": "object" + }, + "CellsConfigStorage_LTM0NDMwODM4": { + "properties": { + "perFileQuotaBytes": { + "type": "string" + }, + "recycle": { + "$ref": "#/components/schemas/CellsRecycle_LTQxMTg3NTkx" + } + }, + "required": [ + "perFileQuotaBytes", + "recycle" + ], + "type": "object" + }, + "CellsInternalConfigB_Covered_Identity_LTUzMDkwOTAz": { + "properties": { + "backend": { + "$ref": "#/components/schemas/CellsBackend_LTE1Nzg3NzQ2" + }, + "collabora": { + "$ref": "#/components/schemas/CellsCollabora_LTMzNDA5MDIz" + }, + "storage": { + "$ref": "#/components/schemas/CellsStorage_LTY2Mzc5NzY1" + } + }, + "required": [ + "backend", + "collabora", + "storage" + ], + "type": "object" + }, + "CellsMetadata_LTY1OTM5MTM0": { + "properties": { + "namespaces": { + "$ref": "#/components/schemas/CellsNamespaces_MzUxMjEzOTQw" + } + }, + "required": [ + "namespaces" + ], + "type": "object" + }, + "CellsNamespaces_MzUxMjEzOTQw": { + "properties": { + "usermetaTags": { + "$ref": "#/components/schemas/CellsUserMetaTags_LTc4Njk4NTY0" + } + }, + "required": [ + "usermetaTags" + ], + "type": "object" + }, + "CellsPropertyStatus_MTQ5NjE2MzQ4": { + "enum": [ + "enabled", + "disabled", + "enforced" + ], + "type": "string" + }, + "CellsProperty_NzcxMDIzMzk0": { + "properties": { + "default": { + "$ref": "#/components/schemas/CellsPropertyStatus_MTQ5NjE2MzQ4" + }, + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled", + "default" + ], + "type": "object" + }, + "CellsPublicLinks_MjgxMzQ3Mzk4": { + "properties": { + "enableFiles": { + "type": "boolean" + }, + "enableFolders": { + "type": "boolean" + }, + "enforceExpirationDefault": { + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "enforceExpirationMax": { + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "enforcePassword": { + "type": "boolean" + } + }, + "required": [ + "enableFiles", + "enableFolders", + "enforcePassword", + "enforceExpirationMax", + "enforceExpirationDefault" + ], + "type": "object" + }, + "CellsRecycle_LTQxMTg3NTkx": { + "properties": { + "allowSkip": { + "type": "boolean" + }, + "autoPurgeDays": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "disable": { + "type": "boolean" + } + }, + "required": [ + "autoPurgeDays", + "disable", + "allowSkip" + ], + "type": "object" + }, + "CellsState_LTg4MDEwNDA5": { + "enum": [ + "disabled", + "pending", + "ready" + ], + "type": "string" + }, + "CellsStorage_LTY2Mzc5NzY1": { + "properties": { + "perUserQuotaBytes": { + "example": "-1", + "type": "string" + }, + "totalLimitBytes": { + "example": "-1", + "type": "string" + } + }, + "required": [ + "perUserQuotaBytes" + ], + "type": "object" + }, + "CellsUserMetaTags_LTc4Njk4NTY0": { + "properties": { + "allowFreeValues": { + "type": "boolean" + }, + "defaultValues": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "defaultValues", + "allowFreeValues" + ], + "type": "object" + }, + "CellsUsers_LTQ4NTEyODA1": { + "properties": { + "externals": { + "type": "boolean" + }, + "guests": { + "type": "boolean" + } + }, + "required": [ + "externals", + "guests" + ], + "type": "object" + }, + "ChallengeToken_Mzk3NTcwOTM3": { + "properties": { + "challenge_token": { + "$ref": "#/components/schemas/Token" + } + }, + "required": [ + "challenge_token" + ], + "type": "object" + }, + "ChannelPermissions_Mzc1MTM3NTg2": { + "enum": [ + "team-members", + "everyone", + "admins" + ], + "type": "string" + }, + "ChannelsConfigB_Covered_Identity_ODk2MTk3NDQ4": { + "properties": { + "allowed_to_create_channels": { + "$ref": "#/components/schemas/ChannelPermissions_Mzc1MTM3NTg2" + }, + "allowed_to_open_channels": { + "$ref": "#/components/schemas/ChannelPermissions_Mzc1MTM3NTg2" + } + }, + "required": [ + "allowed_to_create_channels", + "allowed_to_open_channels" + ], + "type": "object" + }, + "CheckHandles_LTc0OTkxMzAx": { + "properties": { + "handles": { + "items": { + "type": "string" + }, + "maxItems": 50, + "minItems": 1, + "type": "array" + }, + "return": { + "maximum": 10, + "minimum": 1, + "type": "integer" + } + }, + "required": [ + "handles", + "return" + ], + "type": "object" + }, + "CheckUserGroupName_LTg0ODU1OTk1": { + "properties": { + "name": { + "maxLength": 4000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "CipherSuiteTag": { + "description": "The cipher suite of the corresponding MLS group", + "maximum": 65535, + "minimum": 0, + "type": "integer" + }, + "ClassifiedDomainsConfig_LTg4MDcwMDg2": { + "properties": { + "domains": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "domains" + ], + "type": "object" + }, + "ClientCapabilityList": { + "items": { + "$ref": "#/components/schemas/ClientCapability_MTY2NDAzMjM3" + }, + "type": "array" + }, + "ClientCapability_MTY2NDAzMjM3": { + "enum": [ + "legalhold-implicit-consent", + "consumable-notifications" + ], + "type": "string" + }, + "ClientClass_NjE3MDgwNzcx": { + "enum": [ + "phone", + "tablet", + "desktop", + "legalhold" + ], + "type": "string" + }, + "ClientIdentity_MjAxMjI3NTUw": { + "properties": { + "client_id": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" + }, + "domain": { + "$ref": "#/components/schemas/Domain" + }, + "user_id": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "domain", + "user_id", + "client_id" + ], + "type": "object" + }, + "ClientMismatch_ODUyODM0MDQ0": { + "properties": { + "deleted": { + "$ref": "#/components/schemas/UserClients" + }, + "missing": { + "$ref": "#/components/schemas/UserClients" + }, + "redundant": { + "$ref": "#/components/schemas/UserClients" + }, + "time": { + "$ref": "#/components/schemas/UTCTimeMillis" + } + }, + "required": [ + "time", + "missing", + "redundant", + "deleted" + ], + "type": "object" + }, + "ClientPrekey_LTcyODUzMTcw": { + "properties": { + "client": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" + }, + "prekey": { + "$ref": "#/components/schemas/UncheckedPrekeyBundle_LTU1MzQzOTgy" + } + }, + "required": [ + "client", + "prekey" + ], + "type": "object" + }, + "ClientType_MjQ0OTQwMzcw": { + "enum": [ + "temporary", + "permanent", + "legalhold" + ], + "type": "string" + }, + "Client_MTM1OTcwOTQ1": { + "properties": { + "capabilities": { + "$ref": "#/components/schemas/ClientCapabilityList" + }, + "class": { + "$ref": "#/components/schemas/ClientClass_NjE3MDgwNzcx" + }, + "cookie": { + "type": "string" + }, + "id": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" + }, + "label": { + "type": "string" + }, + "last_active": { + "$ref": "#/components/schemas/UTCTime" + }, + "mls_public_keys": { + "$ref": "#/components/schemas/MLSPublicKeys" + }, + "model": { + "type": "string" + }, + "time": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "type": { + "$ref": "#/components/schemas/ClientType_MjQ0OTQwMzcw" + } + }, + "required": [ + "id", + "type", + "time" + ], + "type": "object" + }, + "CodeChallengeMethod_NTIxNzk0NDgw": { + "description": "The method used to encode the code challenge. Only `S256` is supported.", + "enum": [ + "S256" + ], + "type": "string" + }, + "CollaboraEdition_LTg2NDA1NDQ4": { + "enum": [ + "NO", + "CODE", + "COOL" + ], + "type": "string" + }, + "CollaboratorPermission_NDg5NTg2ODgy": { + "description": "

Permission granted to a team collaborator.

  • `create_team_conversation`: equivalent to the `CreateConversation` and `AddRemoveConvMember` permissions for team members (both implied in the `member` role); allows creating team group conversations and adding members to them.
  • \n
  • `implicit_connection`: team members are implicitly connected to each other, allowing conversations (1:1 or group) without an explicit connection request. This permission grants the same to a collaborator.
\n

NB: a member of team A can always open conversations with a collaborator of team A; the permission only controls the collaborator's abilities.

", + "enum": [ + "create_team_conversation", + "implicit_connection" + ], + "type": "string" + }, + "CommitBundle": { + "description": "This object can only be parsed in TLS format. Please refer to the MLS specification for details." + }, + "CompletePasswordReset_LTYzMDAxNDA1": { + "properties": { + "code": { + "$ref": "#/components/schemas/ASCII" + }, + "key": { + "$ref": "#/components/schemas/ASCII" + }, + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "required": [ + "key", + "code", + "password" + ], + "type": "object" + }, + "CompletePasswordReset_NDcyMjY5OTc4": { + "description": "Data to complete a password reset", + "properties": { + "code": { + "$ref": "#/components/schemas/ASCII" + }, + "email": { + "$ref": "#/components/schemas/Email" + }, + "key": { + "$ref": "#/components/schemas/ASCII" + }, + "password": { + "description": "New password (6 - 1024 characters)", + "maxLength": 1024, + "minLength": 8, + "type": "string" + }, + "phone": { + "$ref": "#/components/schemas/PhoneNumber" + } + }, + "required": [ + "code", + "password" + ], + "type": "object" + }, + "ConferenceCallingConfigB_Covered_Identity_NDMwMjcyMzM1": { + "properties": { + "useSFTForOneToOneCalls": { + "type": "boolean" + } + }, + "type": "object" + }, + "Connect_ODY3OTE4NTYx": { + "properties": { + "email": { + "type": "string" + }, + "message": { + "type": "string" + }, + "name": { + "type": "string" + }, + "qualified_recipient": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "recipient": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "qualified_recipient" + ], + "type": "object" + }, + "ConnectionUpdate_LTU3MTA1OTA5": { + "properties": { + "status": { + "$ref": "#/components/schemas/Relation_LTE4OTU5MTk4" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Connections_PagingState": { + "type": "string" + }, + "ContactStatusState_LTg2MjAyNzAx": { + "enum": [ + "contactable", + "non-contactable" + ], + "type": "string" + }, + "ContactStatus_LTUzNzk1MzM4": { + "properties": { + "state": { + "$ref": "#/components/schemas/ContactStatusState_LTg2MjAyNzAx" + } + }, + "required": [ + "state" + ], + "type": "object" + }, + "Contact_LTcwODE3Mjc5": { + "description": "Contact discovered through search", + "properties": { + "accent_id": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "handle": { + "type": "string" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "name": { + "type": "string" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "type": { + "$ref": "#/components/schemas/UserType_LTU1OTU4OTM5" + } + }, + "required": [ + "qualified_id", + "name", + "type" + ], + "type": "object" + }, + "ConvMembers_LTc2MDg1NDg2": { + "description": "Users of a conversation", + "properties": { + "others": { + "description": "All other current users of this conversation", + "items": { + "$ref": "#/components/schemas/OtherMember_LTgzNzE2MTk4" + }, + "type": "array" + }, + "self": { + "$ref": "#/components/schemas/Member_OTA5OTgyNzcw" + } + }, + "required": [ + "others" + ], + "type": "object" + }, + "ConvTeamInfo_Mzc5NjcyNjAz": { + "description": "Team information of this conversation", + "properties": { + "managed": { + "description": "This field MUST NOT be used by clients. It is here only for backwards compatibility of the interface." + }, + "teamid": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "teamid", + "managed" + ], + "type": "object" + }, + "ConvType_MzM0NTE3ODE5": { + "enum": [ + 0, + 1, + 2, + 3 + ], + "type": "integer" + }, + "ConversationAccessData_MjMxMTI5ODc3": { + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + } + }, + "required": [ + "access", + "access_role" + ], + "type": "object" + }, + "ConversationCodeInfo_LTc5MzgzNjg3": { + "description": "Contains conversation properties to update", + "properties": { + "code": { + "$ref": "#/components/schemas/ASCII" + }, + "has_password": { + "description": "Whether the conversation has a password", + "type": "boolean" + }, + "key": { + "$ref": "#/components/schemas/ASCII" + }, + "uri": { + "$ref": "#/components/schemas/HttpsUrl" + } + }, + "required": [ + "key", + "code", + "uri", + "has_password" + ], + "type": "object" + }, + "ConversationCode_Mjg3OTI1NTMx": { + "description": "Contains conversation properties to update", + "properties": { + "code": { + "$ref": "#/components/schemas/ASCII" + }, + "key": { + "$ref": "#/components/schemas/ASCII" + } + }, + "required": [ + "key", + "code" + ], + "type": "object" + }, + "ConversationCoverView_LTMwNDkxMTA1": { + "description": "Limited view of Conversation.", + "properties": { + "has_password": { + "type": "boolean" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "has_password" + ], + "type": "object" + }, + "ConversationHistoryUpdate_LTg5MDQ5Nzgx": { + "properties": { + "history": { + "$ref": "#/components/schemas/History" + } + }, + "required": [ + "history" + ], + "type": "object" + }, + "ConversationIds_PagingState": { + "type": "string" + }, + "ConversationMessageTimerUpdate_LTcxMjUwNzQ4": { + "description": "Contains conversation properties to update", + "properties": { + "message_timer": { + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + } + }, + "type": "object" + }, + "ConversationPage_LTIwMDU2NDI3": { + "description": "This is the last page if it contains fewer rows than requested. There may be 0 rows on a page.", + "properties": { + "page": { + "items": { + "$ref": "#/components/schemas/ConversationSearchResult_NDI0MTcyMDU3" + }, + "type": "array" + } + }, + "required": [ + "page" + ], + "type": "object" + }, + "ConversationReceiptModeUpdate_NDE4MzUzNTU3": { + "description": "Contains conversation receipt mode to update to. Receipt mode tells clients whether certain types of receipts should be sent in the given conversation or not. How this value is interpreted is up to clients.", + "properties": { + "receipt_mode": { + "description": "Conversation receipt mode", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + } + }, + "required": [ + "receipt_mode" + ], + "type": "object" + }, + "ConversationRename_ODkwODg1MzQ0": { + "properties": { + "name": { + "description": "The new conversation name", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "ConversationReset_MzU1Nzc5MjAw": { + "properties": { + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "new_group_id": { + "$ref": "#/components/schemas/GroupId" + } + }, + "required": [ + "group_id" + ], + "type": "object" + }, + "ConversationRole": { + "properties": { + "actions": { + "description": "The set of actions allowed for this role", + "items": { + "$ref": "#/components/schemas/Action" + }, + "type": "array" + }, + "conversation_role": { + "$ref": "#/components/schemas/RoleName" + } + } + }, + "ConversationRolesList": { + "properties": { + "conversation_roles": { + "items": { + "$ref": "#/components/schemas/ConversationRole" + }, + "type": "array" + } + }, + "required": [ + "conversation_roles" + ], + "type": "object" + }, + "ConversationSearchResult_NDI0MTcyMDU3": { + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "admin_count": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "member_count": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "access", + "member_count", + "admin_count" + ], + "type": "object" + }, + "Conversation_GroupConvType_MzQzMTQ1OTg3": { + "description": "A conversation object as returned from the server", + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" + }, + "cipher_suite": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "creator": { + "$ref": "#/components/schemas/UUID" + }, + "epoch": { + "description": "The epoch number of the corresponding MLS group", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "epoch_timestamp": { + "$ref": "#/components/schemas/UTCTime" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "history": { + "$ref": "#/components/schemas/History" + }, + "last_event": { + "type": "string" + }, + "last_event_time": { + "type": "string" + }, + "members": { + "$ref": "#/components/schemas/ConvMembers_LTc2MDg1NDg2" + }, + "message_timer": { + "description": "Per-conversation message timer (can be null)", + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "type": "string" + }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, + "protocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "receipt_mode": { + "description": "Conversation receipt mode", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "type": { + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" + } + }, + "required": [ + "qualified_id", + "type", + "access", + "access_role", + "members", + "group_id", + "epoch" + ], + "type": "object" + }, + "ConversationsResponse_GroupConvType_ODkxMjM2ODM0": { + "description": "Response object for getting metadata of a list of conversations", + "properties": { + "failed": { + "description": "The server failed to fetch these conversations, most likely due to network issues while contacting a remote server", + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "type": "array" + }, + "found": { + "items": { + "$ref": "#/components/schemas/OwnConversation_GroupConvType_LTU2MzYxNTg0" + }, + "type": "array" + }, + "not_found": { + "description": "These conversations either don't exist or are deleted.", + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "type": "array" + } + }, + "required": [ + "found", + "not_found", + "failed" + ], + "type": "object" + }, + "CookieList_LTM4MzYwNzAz": { + "description": "List of cookie information", + "properties": { + "cookies": { + "items": { + "$ref": "#/components/schemas/Cookie_LTkyMDA3OTI5" + }, + "type": "array" + } + }, + "required": [ + "cookies" + ], + "type": "object" + }, + "CookieType_LTE0MjczNzY3": { + "enum": [ + "session", + "persistent" + ], + "type": "string" + }, + "Cookie_LTkyMDA3OTI5": { + "properties": { + "created": { + "$ref": "#/components/schemas/UTCTime" + }, + "expires": { + "$ref": "#/components/schemas/UTCTime" + }, + "id": { + "format": "int32", + "maximum": 4294967295, + "minimum": 0, + "type": "integer" + }, + "label": { + "type": "string" + }, + "successor": { + "format": "int32", + "maximum": 4294967295, + "minimum": 0, + "type": "integer" + }, + "type": { + "$ref": "#/components/schemas/CookieType_LTE0MjczNzY3" + } + }, + "required": [ + "id", + "type", + "created", + "expires" + ], + "type": "object" + }, + "CreateConversationCodeRequest_NTYzMTA1NDYz": { + "description": "Request body for creating a conversation code", + "properties": { + "password": { + "description": "Password for accessing the conversation via guest link. Set to null or omit for no password.", + "maxLength": 1024, + "minLength": 8, + "type": "string" + } + }, + "type": "object" + }, + "CreateGroupConversation_GroupConvType_MTQ3OTc4NDk3": { + "description": "A created group-conversation object extended with a list of failed-to-add users", + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" + }, + "cipher_suite": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "creator": { + "$ref": "#/components/schemas/UUID" + }, + "epoch": { + "description": "The epoch number of the corresponding MLS group", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "epoch_timestamp": { + "$ref": "#/components/schemas/UTCTime" + }, + "failed_to_add": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "type": "array" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "history": { + "$ref": "#/components/schemas/History" + }, + "last_event": { + "type": "string" + }, + "last_event_time": { + "type": "string" + }, + "members": { + "$ref": "#/components/schemas/ConvMembers_LTc2MDg1NDg2" + }, + "message_timer": { + "description": "Per-conversation message timer (can be null)", + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "type": "string" + }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, + "protocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "receipt_mode": { + "description": "Conversation receipt mode", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "type": { + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" + } + }, + "required": [ + "qualified_id", + "type", + "access", + "access_role", + "members", + "group_id", + "epoch", + "failed_to_add" + ], + "type": "object" + }, + "CreateOAuthAuthorizationCodeRequest_LTQ3NzI1Mjkz": { + "properties": { + "client_id": { + "$ref": "#/components/schemas/UUID" + }, + "code_challenge": { + "$ref": "#/components/schemas/OAuthCodeChallenge" + }, + "code_challenge_method": { + "$ref": "#/components/schemas/CodeChallengeMethod_NTIxNzk0NDgw" + }, + "redirect_uri": { + "$ref": "#/components/schemas/RedirectUrl" + }, + "response_type": { + "$ref": "#/components/schemas/OAuthResponseType_ODI2Mjg3NzQx" + }, + "scope": { + "description": "The scopes which are requested to get authorization for, separated by a space", + "type": "string" + }, + "state": { + "description": "An opaque value used by the client to maintain state between the request and callback. The authorization server includes this value when redirecting the user-agent back to the client. The parameter SHOULD be used for preventing cross-site request forgery", + "type": "string" + } + }, + "required": [ + "client_id", + "scope", + "response_type", + "redirect_uri", + "state", + "code_challenge_method", + "code_challenge" + ], + "type": "object" + }, + "CreateScimTokenResponse_LTIzOTU2NDU4": { + "properties": { + "info": { + "$ref": "#/components/schemas/ScimTokenInfo_LTI5NjgwNzA1" + }, + "token": { + "type": "string" + } + }, + "required": [ + "token", + "info" + ], + "type": "object" + }, + "CreateScimToken_OTY0NjYxMDQ2": { + "properties": { + "description": { + "type": "string" + }, + "idp": { + "$ref": "#/components/schemas/UUID" + }, + "name": { + "type": "string" + }, + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + }, + "verification_code": { + "$ref": "#/components/schemas/ASCII" + } + }, + "required": [ + "description" + ], + "type": "object" + }, + "CreateUserTeam_MzI4NDQ1Mzkw": { + "properties": { + "team_id": { + "$ref": "#/components/schemas/UUID" + }, + "team_name": { + "type": "string" + } + }, + "required": [ + "team_id", + "team_name" + ], + "type": "object" + }, + "CreatedApp_LTM3NjUxOTY1": { + "properties": { + "cookie": { + "$ref": "#/components/schemas/SomeUserToken" + }, + "user": { + "$ref": "#/components/schemas/UserProfile_LTQzMTQxMTE1" + } + }, + "required": [ + "user", + "cookie" + ], + "type": "object" + }, + "CustomBackend_LTQxODI0MjQ0": { + "description": "Description of a custom backend", + "properties": { + "config_json_url": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "webapp_welcome_url": { + "$ref": "#/components/schemas/HttpsUrl" + } + }, + "required": [ + "config_json_url", + "webapp_welcome_url" + ], + "type": "object" + }, + "DPoPAccessToken": { + "type": "string" + }, + "DPoPAccessTokenResponse_LTgyODU5MDE3": { + "properties": { + "expires_in": { + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "token": { + "$ref": "#/components/schemas/DPoPAccessToken" + }, + "type": { + "$ref": "#/components/schemas/AccessTokenType_LTgyOTY0NDE5" + } + }, + "required": [ + "token", + "type", + "expires_in" + ], + "type": "object" + }, + "DeleteKeyPackages_LTQxNTcxNjY3": { + "properties": { + "key_packages": { + "items": { + "$ref": "#/components/schemas/KeyPackageRef" + }, + "maxItems": 1000, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "key_packages" + ], + "type": "object" + }, + "DeleteProvider_MzYxMzM3Mjg2": { + "properties": { + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "required": [ + "password" + ], + "type": "object" + }, + "DeleteService_LTY2NzY5NzMz": { + "properties": { + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "required": [ + "password" + ], + "type": "object" + }, + "DeleteUser_NjE0MjE2Mjkz": { + "properties": { + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "type": "object" + }, + "DeletionCodeTimeout_LTU1MTk0NDI3": { + "properties": { + "expires_in": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + } + }, + "required": [ + "expires_in" + ], + "type": "object" + }, + "DisableLegalHoldForUserRequest_LTYyMDYxOTEy": { + "properties": { + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "type": "object" + }, + "Domain": { + "example": "example.com", + "type": "string" + }, + "DomainOwnershipToken_NTU0ODc1NDE5": { + "properties": { + "domain_ownership_token": { + "$ref": "#/components/schemas/Token" + } + }, + "required": [ + "domain_ownership_token" + ], + "type": "object" + }, + "DomainRedirectConfigTag_MjE2MDI4MDIw": { + "enum": [ + "remove", + "backend", + "no-registration" + ], + "type": "string" + }, + "DomainRedirectConfig_NTI5NDE5MDQy": { + "properties": { + "backend": { + "$ref": "#/components/schemas/HttpsUrl_HttpsUrl_NjUyMDgzNzk3" + }, + "domain_redirect": { + "$ref": "#/components/schemas/DomainRedirectConfigTag_MjE2MDI4MDIw" + } + }, + "required": [ + "domain_redirect", + "backend" + ], + "type": "object" + }, + "DomainRedirectResponse_V10_LTEyMjI4NTM0": { + "properties": { + "backend": { + "$ref": "#/components/schemas/HttpsUrl_Maybe_HttpsUrl_LTQ1MDkyMzY2" + }, + "domain_redirect": { + "$ref": "#/components/schemas/DomainRedirectTag_LTY3NjU1MDEy" + }, + "due_to_existing_account": { + "type": "boolean" + }, + "sso_code": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "domain_redirect", + "sso_code", + "backend" + ], + "type": "object" + }, + "DomainRedirectTag_LTY3NjU1MDEy": { + "enum": [ + "none", + "locked", + "sso", + "backend", + "no-registration", + "pre-authorized" + ], + "type": "string" + }, + "DomainRegistrationResponse_V10_MjE0NDkxODY4": { + "properties": { + "authorized_team": { + "$ref": "#/components/schemas/UUID" + }, + "backend": { + "$ref": "#/components/schemas/HttpsUrl_Maybe_HttpsUrl_LTQ1MDkyMzY2" + }, + "dns_verification_token": { + "$ref": "#/components/schemas/ASCII" + }, + "domain": { + "$ref": "#/components/schemas/Domain" + }, + "domain_redirect": { + "$ref": "#/components/schemas/DomainRedirectTag_LTY3NjU1MDEy" + }, + "sso_code": { + "$ref": "#/components/schemas/UUID" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "team_invite": { + "$ref": "#/components/schemas/TeamInviteTag_LTQyNTMyNzA0" + } + }, + "required": [ + "domain", + "domain_redirect", + "sso_code", + "backend", + "team_invite", + "team" + ], + "type": "object" + }, + "DomainVerificationChallenge_NjIwMzA1MjE5": { + "properties": { + "dns_verification_token": { + "$ref": "#/components/schemas/ASCII" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "token": { + "$ref": "#/components/schemas/Token" + } + }, + "required": [ + "id", + "token", + "dns_verification_token" + ], + "type": "object" + }, + "EdMemberLeftReason_OTAyMDA4NzEw": { + "enum": [ + "left", + "user-deleted", + "removed" + ], + "type": "string" + }, + "EdMemberLeftReason_QualifiedUserIdList_LTYyOTg2OTQ1": { + "properties": { + "qualified_user_ids": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "type": "array" + }, + "reason": { + "$ref": "#/components/schemas/EdMemberLeftReason_OTAyMDA4NzEw" + }, + "user_ids": { + "deprecated": true, + "description": "Deprecated, use qualified_user_ids", + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + } + }, + "required": [ + "reason", + "qualified_user_ids", + "user_ids" + ], + "type": "object" + }, + "Either_OAuthAccessTokenRequest_OAuthRefreshAccessTokenRequest": { + "oneOf": [ + { + "properties": { + "Left": { + "$ref": "#/components/schemas/OAuthAccessTokenRequest_LTYyNTcyMzI4" + } + }, + "required": [ + "Left" + ], + "title": "Left", + "type": "object" + }, + { + "properties": { + "Right": { + "$ref": "#/components/schemas/OAuthRefreshAccessTokenRequest_LTUwNjA3OTI1" + } + }, + "required": [ + "Right" + ], + "title": "Right", + "type": "object" + } + ] + }, + "Email": { + "type": "string" + }, + "EmailUpdate_LTYwODE0ODQ5": { + "properties": { + "email": { + "$ref": "#/components/schemas/Email" + } + }, + "required": [ + "email" + ], + "type": "object" + }, + "EmailUpdate_NjQ5MDg1OTY0": { + "properties": { + "email": { + "$ref": "#/components/schemas/Email" + } + }, + "required": [ + "email" + ], + "type": "object" + }, + "EnforceFilDwadLtCgB_vIy_LTQ2NjU1Nzcx": { + "properties": { + "enforcedDownloadLocation": { + "type": "string" + } + }, + "type": "object" + }, + "EpochTimestamp": { + "example": "2021-05-12T10:52:02Z", + "format": "yyyy-mm-ddThh:MM:ssZ", + "type": "string" + }, + "EventType_LTQ3NTQyNDYz": { + "enum": [ + "conversation.member-join", + "conversation.member-leave", + "conversation.member-update", + "conversation.rename", + "conversation.access-update", + "conversation.receipt-mode-update", + "conversation.message-timer-update", + "conversation.code-update", + "conversation.code-delete", + "conversation.create", + "conversation.create-meeting", + "conversation.delete", + "conversation.delete-meeting", + "conversation.mls-reset", + "conversation.connect-request", + "conversation.typing", + "conversation.otr-message-add", + "conversation.mls-message-add", + "conversation.mls-welcome", + "conversation.protocol-update", + "conversation.add-permission-update", + "conversation.history-update", + "conversation.adminless-reminder" + ], + "type": "string" + }, + "EventVia_Mjc4MzcyNzE0": { + "enum": [ + "scim", + "user" + ], + "type": "string" + }, + "Event_LTMwMTMyODM5": { + "properties": { + "conversation": { + "$ref": "#/components/schemas/UUID" + }, + "data": { + "description": "The action of changing the permission to add members to a channel", + "example": "ZXhhbXBsZQo=", + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "$ref": "#/components/schemas/AccessRoleLegacy_LTYwOTAxMDI1" + }, + "access_role_v2": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "add_type": { + "$ref": "#/components/schemas/JoinType_LTY4MDg2MzA5" + }, + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" + }, + "cipher_suite": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "code": { + "$ref": "#/components/schemas/ASCII" + }, + "conversation_role": { + "$ref": "#/components/schemas/RoleName" + }, + "creator": { + "$ref": "#/components/schemas/UUID" + }, + "data": { + "description": "Extra (symmetric) data (i.e. ciphertext, Base64 in JSON) that is common with all other recipients.", + "type": "string" + }, + "deletion_scheduled_for": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "depth": { + "$ref": "#/components/schemas/HistoryDuration" + }, + "email": { + "type": "string" + }, + "epoch": { + "description": "The epoch number of the corresponding MLS group", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "epoch_timestamp": { + "$ref": "#/components/schemas/EpochTimestamp" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "has_password": { + "description": "Whether the conversation has a password", + "type": "boolean" + }, + "hidden": { + "type": "boolean" + }, + "hidden_ref": { + "type": "string" + }, + "history": { + "$ref": "#/components/schemas/History" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "key": { + "$ref": "#/components/schemas/ASCII" + }, + "last_event": { + "type": "string" + }, + "last_event_time": { + "type": "string" + }, + "members": { + "$ref": "#/components/schemas/OwnConvMembers_LTEwMzUzODMy" + }, + "message": { + "type": "string" + }, + "message_timer": { + "description": "Per-conversation message timer (can be null)", + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "type": "string" + }, + "new_group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "otr_archived": { + "type": "boolean" + }, + "otr_archived_ref": { + "type": "string" + }, + "otr_muted_ref": { + "type": "string" + }, + "otr_muted_status": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, + "protocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "qualified_recipient": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "qualified_target": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "qualified_user_ids": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "type": "array" + }, + "reason": { + "$ref": "#/components/schemas/EdMemberLeftReason_OTAyMDA4NzEw" + }, + "receipt_mode": { + "description": "Conversation receipt mode", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "recipient": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" + }, + "sender": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/TypingStatus_LTg5MzcyNDMy" + }, + "target": { + "$ref": "#/components/schemas/UUID" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "text": { + "description": "The ciphertext for the recipient (Base64 in JSON)", + "type": "string" + }, + "type": { + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" + }, + "uri": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "user_ids": { + "deprecated": true, + "description": "Deprecated, use qualified_user_ids", + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + }, + "users": { + "items": { + "$ref": "#/components/schemas/SimpleMember_NTY5MTcxMzcx" + }, + "type": "array" + } + }, + "required": [ + "users", + "add_type", + "reason", + "qualified_user_ids", + "user_ids", + "qualified_target", + "name", + "access", + "key", + "code", + "uri", + "has_password", + "qualified_id", + "type", + "members", + "group_id", + "epoch", + "epoch_timestamp", + "cipher_suite", + "qualified_recipient", + "receipt_mode", + "sender", + "recipient", + "text", + "status", + "add_permission", + "depth", + "deletion_scheduled_for" + ], + "type": "object" + }, + "from": { + "$ref": "#/components/schemas/UUID" + }, + "qualified_conversation": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "qualified_from": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "subconv": { + "type": "string" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "time": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "type": { + "$ref": "#/components/schemas/EventType_LTQ3NTQyNDYz" + }, + "via": { + "$ref": "#/components/schemas/EventVia_Mjc4MzcyNzE0" + } + }, + "required": [ + "type", + "data", + "qualified_conversation", + "qualified_from", + "via", + "time" + ], + "type": "object" + }, + "Featur_EnfocilDwdLCgBIy_MjcxMzc1NDA5": { + "properties": { + "config": { + "$ref": "#/components/schemas/EnforceFilDwadLtCgB_vIy_LTQ2NjU1Nzcx" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "config" + ], + "type": "object" + }, + "Featur_SlfDingMsCoBIdy_LTg2MzYzNjc2": { + "properties": { + "config": { + "$ref": "#/components/schemas/SelfDeletingMessagesConfigB_Covered_Identity_LTY0NzQ4MzU1" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "config" + ], + "type": "object" + }, + "Featur_Vsiond_18PvAmlGpCfgBIy_MjUwNjk2MjQwV18": { + "properties": { + "config": { + "$ref": "#/components/schemas/Versiond_18_PvtAmlGupCfgBaIy_LTUyNzk3MzUx" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "config" + ], + "type": "object" + }, + "FeatureStatus_LTMzMTUwODEw": { + "enum": [ + "enabled", + "disabled" + ], + "type": "string" + }, + "Feature_AppLockConfigB_Bare_Identity_MTAzMjI5NDYy": { + "properties": { + "config": { + "$ref": "#/components/schemas/AppLockConfigB_Covered_Identity_NDIxOTc2Njkz" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "config" + ], + "type": "object" + }, + "Feature_CellsConfigB_Bare_Identity_NzU2NjgxNzEw": { + "properties": { + "config": { + "$ref": "#/components/schemas/CellsConfigB_Covered_Identity_LTE1NzkwOTcz" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "config" + ], + "type": "object" + }, + "Feature_ChannelsConfigB_Bare_Identity_LTU4NTE4MTgx": { + "properties": { + "config": { + "$ref": "#/components/schemas/ChannelsConfigB_Covered_Identity_ODk2MTk3NDQ4" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "config" + ], + "type": "object" + }, + "Feature_ConferenceCallingConfigB_Bare_Identity_Njc2NTcxNTI3": { + "properties": { + "config": { + "$ref": "#/components/schemas/ConferenceCallingConfigB_Covered_Identity_NDMwMjcyMzM1" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Feature_ExposeInvitationURLsToTeamAdminConfig_LTY5NzY2Mzg5": { + "properties": { + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Feature_FileSharingConfig_LTUyNjkxMzM4": { + "properties": { + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Feature_GuestLinksConfig_NjQyMDMxNjg3": { + "properties": { + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Feature_LegalholdConfig_NjM3MTkxNjYw": { + "properties": { + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Feature_MLSConfigB_Bare_Identity_LTI5MjA3MDYy": { + "properties": { + "config": { + "$ref": "#/components/schemas/MLSConfigB_Covered_Identity_LTEzNTk3MzM5" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "config" + ], + "type": "object" + }, + "Feature_MeetingsConfig_NDc2MzM0MDE1": { + "properties": { + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Feature_MlsE2EIdConfigB_Bare_Identity_LTUxODYzODEx": { + "properties": { + "config": { + "$ref": "#/components/schemas/MlsE2EIdConfigB_Covered_Identity_NDQ0NjEwNzA3" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "config" + ], + "type": "object" + }, + "Feature_MlsMigrationConfigB_Bare_Identity_LTQyMDAxMTkz": { + "properties": { + "config": { + "$ref": "#/components/schemas/MlsMigrationConfigB_Covered_Identity_LTM3NDQ4Mzg4" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "config" + ], + "type": "object" + }, + "Feature_OutlookCalIntegrationConfig_LTg0MjIxNTMx": { + "properties": { + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Feature_SearchVisibilityAvailableConfig_LTMzNTkxODI1": { + "properties": { + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Feature_SearchVisibilityInboundConfig_MTI1NzQxODY2": { + "properties": { + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "Feature_SndFactorPasswordChallengeConfig_NDc0MzUyMzQz": { + "properties": { + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "FederatedUserSearchPolicy_MzkwODA4MTM3": { + "description": "Search policy that was applied when searching for users", + "enum": [ + "no_search", + "exact_handle_search", + "full_search" + ], + "type": "string" + }, + "Fingerprint": { + "example": "ioy3GeIjgQRsobf2EKGO3O8mq/FofFxHRqy0T4ERIZ8=", + "type": "string" + }, + "FormRedirect": { + "properties": { + "uri": { + "type": "string" + }, + "xml": { + "$ref": "#/components/schemas/AuthnRequest" + } + }, + "type": "object" + }, + "Frequency_Mzk0ODQwOTM3": { + "enum": [ + "daily", + "weekly", + "monthly", + "yearly" + ], + "type": "string" + }, + "GetByEmailReq_LTY4MzE3Njgy": { + "properties": { + "email": { + "$ref": "#/components/schemas/Email" + } + }, + "required": [ + "email" + ], + "type": "object" + }, + "GetByEmailResp_LTMxNTY3MjA0": { + "properties": { + "sso_code": { + "$ref": "#/components/schemas/UUID" + } + }, + "type": "object" + }, + "GetDomainRegistrationRequest_LTg4NTM1MzM2": { + "properties": { + "email": { + "$ref": "#/components/schemas/Email" + } + }, + "required": [ + "email" + ], + "type": "object" + }, + "GetMuliTabPgRqs_ConcLOrm501_LTIwMjA4NzYw": { + "description": "A request to list some or all of a user's Connections, including remote ones", + "properties": { + "paging_state": { + "$ref": "#/components/schemas/Connections_PagingState" + }, + "size": { + "description": "optional, must be <= 500, defaults to 100.", + "format": "int32", + "maximum": 500, + "minimum": 1, + "type": "integer" + } + }, + "type": "object" + }, + "GetMuliTabPgRqs_ConvrIdLcOm10_ODU0NjQ1NDMz": { + "description": "A request to list some or all of a user's ConversationIds, including remote ones", + "properties": { + "paging_state": { + "$ref": "#/components/schemas/ConversationIds_PagingState" + }, + "size": { + "description": "optional, must be <= 1000, defaults to 1000.", + "format": "int32", + "maximum": 1000, + "minimum": 1, + "type": "integer" + } + }, + "type": "object" + }, + "GroupConvTypeLegacy_NTUxMDI2Mzkw": { + "enum": [ + "group_conversation", + "channel" + ], + "type": "string" + }, + "GroupConvType_LTU4NjU0MTY5": { + "enum": [ + "group_conversation", + "channel", + "meeting" + ], + "type": "string" + }, + "GroupId": { + "description": "A base64-encoded MLS group ID", + "example": "ZXhhbXBsZQo=", + "type": "string" + }, + "GroupInfoData": { + "description": "This object can only be parsed in TLS format. Please refer to the MLS specification for details." + }, + "Handle": { + "type": "string" + }, + "HandleUpdate_NTI4NDk1OTAx": { + "properties": { + "handle": { + "type": "string" + } + }, + "required": [ + "handle" + ], + "type": "object" + }, + "History": { + "properties": { + "depth": { + "$ref": "#/components/schemas/HistoryDuration" + } + }, + "required": [ + "depth" + ], + "type": "object" + }, + "HistoryDuration": { + "type": "string" + }, + "HistorySharingConfig_Mjc4MzA1Nzgw": { + "properties": { + "depth": { + "$ref": "#/components/schemas/HistoryDuration" + } + }, + "required": [ + "depth" + ], + "type": "object" + }, + "HttpsUrl": { + "example": "https://example.com", + "type": "string" + }, + "HttpsUrl_HttpsUrl_NjUyMDgzNzk3": { + "properties": { + "config_url": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "webapp_url": { + "$ref": "#/components/schemas/HttpsUrl" + } + }, + "required": [ + "config_url", + "webapp_url" + ], + "type": "object" + }, + "HttpsUrl_Maybe_HttpsUrl_LTQ1MDkyMzY2": { + "properties": { + "config_url": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "webapp_url": { + "$ref": "#/components/schemas/HttpsUrl" + } + }, + "required": [ + "config_url" + ], + "type": "object" + }, + "Icon": { + "description": "S3 asset key for an icon image with retention information. Allows special value 'default'.", + "example": "3-1-47de4580-ae51-4650-acbb-d10c028cb0ac", + "type": "string" + }, + "IdObject_ClientId_LTM3NjQyODM5": { + "properties": { + "id": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "IdPConfig_WireIdP_NDA5MTE4Mjk0": { + "properties": { + "extraInfo": { + "$ref": "#/components/schemas/WireIdP_ODMzOTExMzYw" + }, + "id": { + "$ref": "#/components/schemas/URI" + }, + "metadata": { + "$ref": "#/components/schemas/IdPMetadata_MTI3NzE4MTA0" + } + }, + "required": [ + "id", + "metadata", + "extraInfo" + ], + "type": "object" + }, + "IdPList": { + "properties": { + "providers": { + "items": { + "$ref": "#/components/schemas/IdPConfig_WireIdP_NDA5MTE4Mjk0" + }, + "type": "array" + } + }, + "required": [ + "providers" + ], + "type": "object" + }, + "IdPMetadataInfo": { + "maxProperties": 1, + "minProperties": 1, + "properties": { + "value": { + "type": "string" + } + }, + "type": "object" + }, + "IdPMetadata_MTI3NzE4MTA0": { + "properties": { + "certAuthnResponse": { + "items": { + "$ref": "#/components/schemas/SignedCertificate" + }, + "minItems": 1, + "type": "array" + }, + "issuer": { + "$ref": "#/components/schemas/URI" + }, + "requestURI": { + "type": "string" + } + }, + "required": [ + "issuer", + "requestURI", + "certAuthnResponse" + ], + "type": "object" + }, + "Id_AuthnRequest": { + "properties": { + "iD": { + "type": "string" + } + }, + "required": [ + "iD" + ], + "type": "object" + }, + "InvitationList_ODk4NTQxODc3": { + "description": "A list of sent team invitations.", + "properties": { + "has_more": { + "description": "Indicator that the server has more invitations than returned.", + "type": "boolean" + }, + "invitations": { + "items": { + "$ref": "#/components/schemas/Invitation_NTkzMDYwODc1" + }, + "type": "array" + } + }, + "required": [ + "invitations", + "has_more" + ], + "type": "object" + }, + "InvitationRequest_LTcyMDIzNDc0": { + "description": "A request to join a team on Wire.", + "properties": { + "allow_existing": { + "description": "Whether invitations to existing users are allowed.", + "type": "boolean" + }, + "email": { + "$ref": "#/components/schemas/Email" + }, + "locale": { + "$ref": "#/components/schemas/Locale" + }, + "name": { + "description": "Name of the invitee (1 - 128 characters).", + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "role": { + "$ref": "#/components/schemas/Role_LTIzMjAzMjky" + } + }, + "required": [ + "email" + ], + "type": "object" + }, + "InvitationUserView_LTUyMTE3Nzkz": { + "properties": { + "created_at": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "created_by": { + "$ref": "#/components/schemas/UUID" + }, + "created_by_email": { + "$ref": "#/components/schemas/Email" + }, + "email": { + "$ref": "#/components/schemas/Email" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "managed_by": { + "$ref": "#/components/schemas/ManagedBy_NTI0ODc0NTQx" + }, + "name": { + "description": "Name of the invitee (1 - 128 characters)", + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "role": { + "$ref": "#/components/schemas/Role_LTIzMjAzMjky" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "url": { + "$ref": "#/components/schemas/URIRef_Absolute" + } + }, + "required": [ + "team", + "id", + "created_at", + "email" + ], + "type": "object" + }, + "Invitation_NTkzMDYwODc1": { + "description": "An invitation to join a team on Wire. If invitee is invited from an existing personal account, inviter email is included.", + "properties": { + "created_at": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "created_by": { + "$ref": "#/components/schemas/UUID" + }, + "email": { + "$ref": "#/components/schemas/Email" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "name": { + "description": "Name of the invitee (1 - 128 characters)", + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "role": { + "$ref": "#/components/schemas/Role_LTIzMjAzMjky" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "url": { + "$ref": "#/components/schemas/URIRef_Absolute" + } + }, + "required": [ + "team", + "id", + "created_at", + "email" + ], + "type": "object" + }, + "InviteQualified_ODYyODIyNjYz": { + "properties": { + "conversation_role": { + "$ref": "#/components/schemas/RoleName" + }, + "qualified_users": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "qualified_users" + ], + "type": "object" + }, + "JoinConversationByCode_NjgzMzM4Mjg5": { + "description": "Request body for joining a conversation by code", + "properties": { + "code": { + "$ref": "#/components/schemas/ASCII" + }, + "key": { + "$ref": "#/components/schemas/ASCII" + }, + "password": { + "maxLength": 1024, + "minLength": 8, + "type": "string" + } + }, + "required": [ + "key", + "code" + ], + "type": "object" + }, + "JoinType_LTY4MDg2MzA5": { + "enum": [ + "external_add", + "internal_add" + ], + "type": "string" + }, + "KeyMap_Value_MzAxODEwOTgx": { + "type": "object" + }, + "KeyPackage": { + "example": "a2V5IHBhY2thZ2UgZGF0YQo=", + "type": "string" + }, + "KeyPackageBundleEntry_NDQ2MzQ2MzMz": { + "properties": { + "client": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" + }, + "domain": { + "$ref": "#/components/schemas/Domain" + }, + "key_package": { + "$ref": "#/components/schemas/KeyPackage" + }, + "key_package_ref": { + "$ref": "#/components/schemas/KeyPackageRef" + }, + "user": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "domain", + "user", + "client", + "key_package_ref", + "key_package" + ], + "type": "object" + }, + "KeyPackageBundle_MjU2MjY0MDU2": { + "properties": { + "key_packages": { + "items": { + "$ref": "#/components/schemas/KeyPackageBundleEntry_NDQ2MzQ2MzMz" + }, + "type": "array" + } + }, + "required": [ + "key_packages" + ], + "type": "object" + }, + "KeyPackageCount_LTYwNDg5MDcz": { + "properties": { + "count": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + } + }, + "required": [ + "count" + ], + "type": "object" + }, + "KeyPackageRef": { + "example": "ZXhhbXBsZQo=", + "type": "string" + }, + "KeyPackageUpload_NTQ2Mjk2NzEx": { + "properties": { + "key_packages": { + "items": { + "$ref": "#/components/schemas/KeyPackage" + }, + "type": "array" + } + }, + "required": [ + "key_packages" + ], + "type": "object" + }, + "LHServiceStatus_ODc3NzE0Mjg3": { + "enum": [ + "configured", + "not_configured", + "disabled" + ], + "type": "string" + }, + "LimitedQualifiedUserIdList_500": { + "properties": { + "qualified_users": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "type": "array" + } + }, + "required": [ + "qualified_users" + ], + "type": "object" + }, + "ListConversations_MjkxMTIwODMz": { + "description": "A request to list some of a user's conversations, including remote ones. Maximum 1000 qualified conversation IDs", + "properties": { + "qualified_ids": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "maxItems": 1000, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "qualified_ids" + ], + "type": "object" + }, + "ListType_LTkyMDM4MzA1": { + "description": "true if 'members' doesn't contain all team members", + "enum": [ + true, + false + ], + "type": "boolean" + }, + "ListUsersById_LTQ5MTE3NDc0": { + "properties": { + "failed": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "minItems": 1, + "type": "array" + }, + "found": { + "items": { + "$ref": "#/components/schemas/UserProfile_LTQzMTQxMTE1" + }, + "type": "array" + } + }, + "required": [ + "found" + ], + "type": "object" + }, + "ListUsersQuery": { + "description": "exactly one of qualified_ids or qualified_handles must be provided.", + "example": { + "qualified_ids": [ + { + "domain": "example.com", + "id": "00000000-0000-0000-0000-000000000000" + } + ] + }, + "properties": { + "qualified_handles": { + "items": { + "$ref": "#/components/schemas/Qualified_Handle_Nzg0MDE3Nzk4" + }, + "type": "array" + }, + "qualified_ids": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "type": "array" + } + }, + "type": "object" + }, + "Locale": { + "type": "string" + }, + "LocaleUpdate_LTgzNjgyOTEw": { + "properties": { + "locale": { + "$ref": "#/components/schemas/Locale" + } + }, + "required": [ + "locale" + ], + "type": "object" + }, + "LockStatus_LTIyMTU5OTkw": { + "enum": [ + "locked", + "unlocked" + ], + "type": "string" + }, + "LockableFeature_AllowedGlobalOperationsConfig_NjQ1MjA5MDYw": { + "properties": { + "config": { + "$ref": "#/components/schemas/AllowedGlobalOperationsConfig_MzAwOTU1MDkx" + }, + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus", + "config" + ], + "type": "object" + }, + "LockableFeature_AppLockConfigB_Bare_Identity_ODgzNDI0OTU5": { + "properties": { + "config": { + "$ref": "#/components/schemas/AppLockConfigB_Covered_Identity_NDIxOTc2Njkz" + }, + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus", + "config" + ], + "type": "object" + }, + "LockableFeature_AppsConfig_MzQyNTMxNTk5": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_AssetAuditLogConfig_NDQ3MzcyMzk2": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_BackgroundEffectsConfig_MTg1MTk3NTM5": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_CellsConfigB_Bare_Identity_LTgzMDA1NjI3": { + "properties": { + "config": { + "$ref": "#/components/schemas/CellsConfigB_Covered_Identity_LTE1NzkwOTcz" + }, + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus", + "config" + ], + "type": "object" + }, + "LockableFeature_ChannelsConfigB_Bare_Identity_NzA2NDEyMDEw": { + "properties": { + "config": { + "$ref": "#/components/schemas/ChannelsConfigB_Covered_Identity_ODk2MTk3NDQ4" + }, + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus", + "config" + ], + "type": "object" + }, + "LockableFeature_ChatBubblesConfig_NDgwMTQzNjI2": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_ClassifiedDomainsConfig_LTY1ODQwODg1": { + "properties": { + "config": { + "$ref": "#/components/schemas/ClassifiedDomainsConfig_LTg4MDcwMDg2" + }, + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus", + "config" + ], + "type": "object" + }, + "LockableFeature_ConsumableNotificationsConfig_MjUxMjczMjM0": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_DigitalSignaturesConfig_ODM2MDA2NDU4": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_DomainRegistrationConfig_NzU0NjczNTE0": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_FileSharingConfig_MjgwNjIzODEz": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_GuestLinksConfig_LTcwNjU0NDMw": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_LegalholdConfig_LTc5MTk5OTIw": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_LimitedEventFanoutConfig_MTg3ODM0NzU0": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_MLSConfigB_Bare_Identity_MTg1MTc0NTEw": { + "properties": { + "config": { + "$ref": "#/components/schemas/MLSConfigB_Covered_Identity_LTEzNTk3MzM5" + }, + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus", + "config" + ], + "type": "object" + }, + "LockableFeature_MeetingsConfig_LTE0OTQ5Nzcw": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_MeetingsPremiumConfig_NDg1ODEyNTA1": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_MlsE2EIdConfigB_Bare_Identity_MTU2ODkyMDc4": { + "properties": { + "config": { + "$ref": "#/components/schemas/MlsE2EIdConfigB_Covered_Identity_NDQ0NjEwNzA3" + }, + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus", + "config" + ], + "type": "object" + }, + "LockableFeature_OutlookCalIntegrationConfig_NjQ0MzMyMzY0": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_SSOConfig_NjcyMjU4MDY2": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_SearchVisibilityAvailableConfig_LTkxMTA5ODk5": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_SearchVisibilityInboundConfig_NzA5NzczNTgy": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_SndFactorPasswordChallengeConfig_MjQ3NzQ2ODgx": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFeature_StealthUsersConfig_LTE1MTk2NzIz": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFtur_CnfigBIdy_NzY1NDU5MDAy": { + "properties": { + "config": { + "$ref": "#/components/schemas/ConferenceCallingConfigB_Covered_Identity_NDMwMjcyMzM1" + }, + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFtur_CsInfigBdy_LTQ3MTU3Mjg0": { + "properties": { + "config": { + "$ref": "#/components/schemas/CellsInternalConfigB_Covered_Identity_LTUzMDkwOTAz" + }, + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus", + "config" + ], + "type": "object" + }, + "LockableFtur_EnfiDwdCgBIy_ODA5OTA5MTQ4": { + "properties": { + "config": { + "$ref": "#/components/schemas/EnforceFilDwadLtCgB_vIy_LTQ2NjU1Nzcx" + }, + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus", + "config" + ], + "type": "object" + }, + "LockableFtur_ExpsInviURTmAdCfg_LTQzMzU2OTY1": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFtur_MsignCfBIdy_LTE1NjAxNjU2": { + "properties": { + "config": { + "$ref": "#/components/schemas/MlsMigrationConfigB_Covered_Identity_LTM3NDQ4Mzg4" + }, + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus", + "config" + ], + "type": "object" + }, + "LockableFtur_PvnAdmisGpCfgBIy_MTQxOTU4Mzgw": { + "properties": { + "config": { + "$ref": "#/components/schemas/PreventAdminlessGroupsConfigB_Covered_Identity_MjQ2NDYwMTk2" + }, + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus", + "config" + ], + "type": "object" + }, + "LockableFtur_RqiExnmVfCg_NjUyMzgzNzY5": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "LockableFtur_SfDingMsCBIdy_LTg5MTEwNTA2": { + "properties": { + "config": { + "$ref": "#/components/schemas/SelfDeletingMessagesConfigB_Covered_Identity_LTY0NzQ4MzU1" + }, + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus", + "config" + ], + "type": "object" + }, + "LockableFtur_SimpfdUsCnRqQg_Njk5NjU4OTgy": { + "properties": { + "lockStatus": { + "$ref": "#/components/schemas/LockStatus_LTIyMTU5OTkw" + }, + "status": { + "$ref": "#/components/schemas/FeatureStatus_LTMzMTUwODEw" + }, + "ttl": { + "example": "unlimited", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "status", + "lockStatus" + ], + "type": "object" + }, + "Login_LTgyNTIzMTM1": { + "properties": { + "email": { + "$ref": "#/components/schemas/Email" + }, + "handle": { + "$ref": "#/components/schemas/Handle" + }, + "label": { + "type": "string" + }, + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + }, + "verification_code": { + "$ref": "#/components/schemas/ASCII" + } + }, + "required": [ + "password" + ], + "type": "object" + }, + "MLSConfigB_Covered_Identity_LTEzNTk3MzM5": { + "description": "allowlist of users that may change protocols", + "properties": { + "allowedCipherSuites": { + "items": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "type": "array" + }, + "defaultCipherSuite": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "defaultProtocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "groupInfoDiagnostics": { + "type": "boolean" + }, + "protocolToggleUsers": { + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + }, + "supportedProtocols": { + "items": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "type": "array" + } + }, + "required": [ + "protocolToggleUsers", + "defaultProtocol", + "allowedCipherSuites", + "defaultCipherSuite", + "supportedProtocols" + ], + "type": "object" + }, + "MLSKeysByPurpose_MLSKeys_SomeKey_NjkxMjk0MTAx": { + "properties": { + "removal": { + "$ref": "#/components/schemas/MLSKeys_SomeKey_LTUzNDA5MzA3" + } + }, + "required": [ + "removal" + ], + "type": "object" + }, + "MLSKeys_SomeKey_LTUzNDA5MzA3": { + "properties": { + "ecdsa_secp256r1_sha256": { + "$ref": "#/components/schemas/SomeKey" + }, + "ecdsa_secp384r1_sha384": { + "$ref": "#/components/schemas/SomeKey" + }, + "ecdsa_secp521r1_sha512": { + "$ref": "#/components/schemas/SomeKey" + }, + "ed25519": { + "$ref": "#/components/schemas/SomeKey" + } + }, + "required": [ + "ed25519", + "ecdsa_secp256r1_sha256", + "ecdsa_secp384r1_sha384", + "ecdsa_secp521r1_sha512" + ], + "type": "object" + }, + "MLSMessage": { + "description": "This object can only be parsed in TLS format. Please refer to the MLS specification for details." + }, + "MLSMessageSendingStatus_NjA1NDA0MTE4": { + "properties": { + "events": { + "description": "A list of events caused by sending the message.", + "items": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + }, + "type": "array" + }, + "time": { + "$ref": "#/components/schemas/UTCTimeMillis" + } + }, + "required": [ + "events", + "time" + ], + "type": "object" + }, + "MLSOne2OneConversation_SomeKey_GroupConvType_LTg2MTcwMjY3": { + "properties": { + "conversation": { + "$ref": "#/components/schemas/v9_OwnConversation_GroupConvType_LTU2MzYxNTg0" + }, + "public_keys": { + "$ref": "#/components/schemas/MLSKeysByPurpose_MLSKeys_SomeKey_NjkxMjk0MTAx" + } + }, + "required": [ + "conversation", + "public_keys" + ], + "type": "object" + }, + "MLSPublicKeys": { + "additionalProperties": { + "example": "ZXhhbXBsZQo=", + "type": "string" + }, + "description": "Mapping from signature scheme (tags) to public key data", + "example": { + "ecdsa_secp256r1_sha256": "ZXhhbXBsZQo=", + "ecdsa_secp384r1_sha384": "ZXhhbXBsZQo=", + "ecdsa_secp521r1_sha512": "ZXhhbXBsZQo=", + "ed25519": "ZXhhbXBsZQo=" + }, + "type": "object" + }, + "MLSReset_NzgwODA3ODc4": { + "properties": { + "epoch": { + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + } + }, + "required": [ + "group_id", + "epoch" + ], + "type": "object" + }, + "MTYxOTI3NjM3": { + "enum": [ + "image" + ], + "type": "string" + }, + "ManagedBy_NTI0ODc0NTQx": { + "enum": [ + "wire", + "scim" + ], + "type": "string" + }, + "MeetingEmailsInvitation_NzgyNzUzMzcz": { + "description": "Emails invitation", + "properties": { + "emails": { + "items": { + "$ref": "#/components/schemas/Email" + }, + "type": "array" + } + }, + "required": [ + "emails" + ], + "type": "object" + }, + "MeetingWithConversation_LTMyNzA4NzU0": { + "description": "A scheduled meeting with its associated conversation", + "properties": { + "conversation": { + "$ref": "#/components/schemas/Conversation_GroupConvType_MzQzMTQ1OTg3" + }, + "created_at": { + "$ref": "#/components/schemas/UTCTime" + }, + "end_time": { + "$ref": "#/components/schemas/UTCTime" + }, + "invited_emails": { + "items": { + "$ref": "#/components/schemas/Email" + }, + "type": "array" + }, + "qualified_conversation": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "qualified_creator": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Meeting_MjgxMDUyNjc3" + }, + "recurrence": { + "$ref": "#/components/schemas/Recurrence_LTQ0OTc0ODE2" + }, + "start_time": { + "$ref": "#/components/schemas/UTCTime" + }, + "title": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "tzid": { + "$ref": "#/components/schemas/TimeZone" + }, + "updated_at": { + "$ref": "#/components/schemas/UTCTime" + } + }, + "required": [ + "qualified_id", + "title", + "qualified_creator", + "start_time", + "end_time", + "tzid", + "qualified_conversation", + "invited_emails", + "created_at", + "updated_at", + "conversation" + ], + "type": "object" + }, + "Meeting_ODU0OTMzMTgw": { + "description": "A scheduled meeting", + "properties": { + "created_at": { + "$ref": "#/components/schemas/UTCTime" + }, + "end_time": { + "$ref": "#/components/schemas/UTCTime" + }, + "invited_emails": { + "items": { + "$ref": "#/components/schemas/Email" + }, + "type": "array" + }, + "qualified_conversation": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "qualified_creator": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Meeting_MjgxMDUyNjc3" + }, + "recurrence": { + "$ref": "#/components/schemas/Recurrence_LTQ0OTc0ODE2" + }, + "start_time": { + "$ref": "#/components/schemas/UTCTime" + }, + "title": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "tzid": { + "$ref": "#/components/schemas/TimeZone" + }, + "updated_at": { + "$ref": "#/components/schemas/UTCTime" + } + }, + "required": [ + "qualified_id", + "title", + "qualified_creator", + "start_time", + "end_time", + "tzid", + "qualified_conversation", + "invited_emails", + "created_at", + "updated_at" + ], + "type": "object" + }, + "MemberUpdateData_LTc3Nzc3NTEy": { + "properties": { + "conversation_role": { + "$ref": "#/components/schemas/RoleName" + }, + "hidden": { + "type": "boolean" + }, + "hidden_ref": { + "type": "string" + }, + "otr_archived": { + "type": "boolean" + }, + "otr_archived_ref": { + "type": "string" + }, + "otr_muted_ref": { + "type": "string" + }, + "otr_muted_status": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "qualified_target": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "target": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "qualified_target" + ], + "type": "object" + }, + "MemberUpdate_LTg4NTQ0OTYz": { + "properties": { + "hidden": { + "type": "boolean" + }, + "hidden_ref": { + "type": "string" + }, + "otr_archived": { + "type": "boolean" + }, + "otr_archived_ref": { + "type": "string" + }, + "otr_muted_ref": { + "type": "string" + }, + "otr_muted_status": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + } + }, + "type": "object" + }, + "Member_OTA5OTgyNzcw": { + "description": "The user ID of the requestor if the requestor is a member of the conversation", + "properties": { + "conversation_role": { + "$ref": "#/components/schemas/RoleName" + }, + "hidden": { + "type": "boolean" + }, + "hidden_ref": { + "type": "string" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "otr_archived": { + "type": "boolean" + }, + "otr_archived_ref": { + "type": "string" + }, + "otr_muted_ref": { + "type": "string" + }, + "otr_muted_status": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "service": { + "$ref": "#/components/schemas/ServiceRef_LTgxMjY3NzAz" + }, + "status": {}, + "status_ref": {}, + "status_time": {} + }, + "required": [ + "qualified_id" + ], + "type": "object" + }, + "MembersJoin_LTg0MDc1NjQ3": { + "properties": { + "add_type": { + "$ref": "#/components/schemas/JoinType_LTY4MDg2MzA5" + }, + "user_ids": { + "deprecated": true, + "description": "deprecated", + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + }, + "users": { + "items": { + "$ref": "#/components/schemas/SimpleMember_NTY5MTcxMzcx" + }, + "type": "array" + } + }, + "required": [ + "users", + "add_type" + ], + "type": "object" + }, + "MessageSendingStatus_ODg0NDgyNDk4": { + "description": "The Proteus message sending status. It has these fields:\n- `time`: Time of sending message.\n- `missing`: Clients that the message /should/ have been encrypted for, but wasn't.\n- `redundant`: Clients that the message /should not/ have been encrypted for, but was.\n- `deleted`: Clients that were deleted.\n- `failed_to_send`: When message sending fails for some clients but succeeds for others, e.g., because a remote backend is unreachable, this field will contain the list of clients for which the message sending failed. This list should be empty when message sending is not even tried, like when some clients are missing.", + "properties": { + "deleted": { + "$ref": "#/components/schemas/QualifiedUserClients" + }, + "failed_to_confirm_clients": { + "$ref": "#/components/schemas/QualifiedUserClients" + }, + "failed_to_send": { + "$ref": "#/components/schemas/QualifiedUserClients" + }, + "missing": { + "$ref": "#/components/schemas/QualifiedUserClients" + }, + "redundant": { + "$ref": "#/components/schemas/QualifiedUserClients" + }, + "time": { + "$ref": "#/components/schemas/UTCTimeMillis" + } + }, + "required": [ + "time", + "missing", + "redundant", + "deleted", + "failed_to_send", + "failed_to_confirm_clients" + ], + "type": "object" + }, + "MlsE2EIdConfigB_Covered_Identity_NDQ0NjEwNzA3": { + "description": "When a client first tries to fetch or renew a certificate, they may need to login to an identity provider (IdP) depending on their IdP domain authentication policy. The user may have a grace period during which they can \"snooze\" this login. The duration of this grace period (in seconds) is set in the `verificationDuration` parameter, which is enforced separately by each client. After the grace period has expired, the client will not allow the user to use the application until they have logged to refresh the certificate. The default value is 1 day (86400s). The client enrolls using the Automatic Certificate Management Environment (ACME) protocol. The `acmeDiscoveryUrl` parameter must be set to the HTTPS URL of the ACME server discovery endpoint for this team. It is of the form \"https://acme.{backendDomain}/acme/{provisionerName}/discovery\". For example: `https://acme.example.com/acme/provisioner1/discovery`.", + "properties": { + "acmeDiscoveryUrl": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "crlProxy": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "useProxyOnMobile": { + "type": "boolean" + }, + "verificationExpiration": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + } + }, + "required": [ + "verificationExpiration" + ], + "type": "object" + }, + "MlsMigrationConfigB_Covered_Identity_LTM3NDQ4Mzg4": { + "properties": { + "allowManualMigration": { + "type": "boolean" + }, + "finaliseRegardlessAfter": { + "example": "2021-05-12T10:52:02Z", + "format": "yyyy-mm-ddThh:MM:ssZ", + "type": "string" + }, + "startTime": { + "example": "2021-05-12T10:52:02Z", + "format": "yyyy-mm-ddThh:MM:ssZ", + "type": "string" + } + }, + "type": "object" + }, + "MultiTabePg_ConcsLOrRmU_MTgwMzU4OTU5": { + "properties": { + "connections": { + "items": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + }, + "type": "array" + }, + "has_more": { + "type": "boolean" + }, + "paging_state": { + "$ref": "#/components/schemas/Connections_PagingState" + } + }, + "required": [ + "connections", + "has_more", + "paging_state" + ], + "type": "object" + }, + "MultiTabePg_ConvrsIdqf_cLORm_Q_Mzg0MjYzNzM0": { + "properties": { + "has_more": { + "type": "boolean" + }, + "paging_state": { + "$ref": "#/components/schemas/ConversationIds_PagingState" + }, + "qualified_conversations": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "type": "array" + } + }, + "required": [ + "qualified_conversations", + "has_more", + "paging_state" + ], + "type": "object" + }, + "NP_LockableFtur_ghdCnfiSOVsyAvIRqExmDpB_MGwUT2Q_LTM1Mzc0ODgy": { + "properties": { + "allowedGlobalOperations": { + "$ref": "#/components/schemas/LockableFeature_AllowedGlobalOperationsConfig_NjQ1MjA5MDYw" + }, + "appLock": { + "$ref": "#/components/schemas/LockableFeature_AppLockConfigB_Bare_Identity_ODgzNDI0OTU5" + }, + "apps": { + "$ref": "#/components/schemas/LockableFeature_AppsConfig_MzQyNTMxNTk5" + }, + "assetAuditLog": { + "$ref": "#/components/schemas/LockableFeature_AssetAuditLogConfig_NDQ3MzcyMzk2" + }, + "backgroundEffects": { + "$ref": "#/components/schemas/LockableFeature_BackgroundEffectsConfig_MTg1MTk3NTM5" + }, + "cells": { + "$ref": "#/components/schemas/LockableFeature_CellsConfigB_Bare_Identity_LTgzMDA1NjI3" + }, + "cellsInternal": { + "$ref": "#/components/schemas/LockableFtur_CsInfigBdy_LTQ3MTU3Mjg0" + }, + "channels": { + "$ref": "#/components/schemas/LockableFeature_ChannelsConfigB_Bare_Identity_NzA2NDEyMDEw" + }, + "chatBubbles": { + "$ref": "#/components/schemas/LockableFeature_ChatBubblesConfig_NDgwMTQzNjI2" + }, + "classifiedDomains": { + "$ref": "#/components/schemas/LockableFeature_ClassifiedDomainsConfig_LTY1ODQwODg1" + }, + "conferenceCalling": { + "$ref": "#/components/schemas/LockableFtur_CnfigBIdy_NzY1NDU5MDAy" + }, + "consumableNotifications": { + "$ref": "#/components/schemas/LockableFeature_ConsumableNotificationsConfig_MjUxMjczMjM0" + }, + "conversationGuestLinks": { + "$ref": "#/components/schemas/LockableFeature_GuestLinksConfig_LTcwNjU0NDMw" + }, + "digitalSignatures": { + "$ref": "#/components/schemas/LockableFeature_DigitalSignaturesConfig_ODM2MDA2NDU4" + }, + "domainRegistration": { + "$ref": "#/components/schemas/LockableFeature_DomainRegistrationConfig_NzU0NjczNTE0" + }, + "enforceFileDownloadLocation": { + "$ref": "#/components/schemas/LockableFtur_EnfiDwdCgBIy_ODA5OTA5MTQ4" + }, + "exposeInvitationURLsToTeamAdmin": { + "$ref": "#/components/schemas/LockableFtur_ExpsInviURTmAdCfg_LTQzMzU2OTY1" + }, + "fileSharing": { + "$ref": "#/components/schemas/LockableFeature_FileSharingConfig_MjgwNjIzODEz" + }, + "legalhold": { + "$ref": "#/components/schemas/LockableFeature_LegalholdConfig_LTc5MTk5OTIw" + }, + "limitedEventFanout": { + "$ref": "#/components/schemas/LockableFeature_LimitedEventFanoutConfig_MTg3ODM0NzU0" + }, + "meetings": { + "$ref": "#/components/schemas/LockableFeature_MeetingsConfig_LTE0OTQ5Nzcw" + }, + "meetingsPremium": { + "$ref": "#/components/schemas/LockableFeature_MeetingsPremiumConfig_NDg1ODEyNTA1" + }, + "mls": { + "$ref": "#/components/schemas/LockableFeature_MLSConfigB_Bare_Identity_MTg1MTc0NTEw" + }, + "mlsE2EId": { + "$ref": "#/components/schemas/LockableFeature_MlsE2EIdConfigB_Bare_Identity_MTU2ODkyMDc4" + }, + "mlsMigration": { + "$ref": "#/components/schemas/LockableFtur_MsignCfBIdy_LTE1NjAxNjU2" + }, + "outlookCalIntegration": { + "$ref": "#/components/schemas/LockableFeature_OutlookCalIntegrationConfig_NjQ0MzMyMzY0" + }, + "preventAdminlessGroups": { + "$ref": "#/components/schemas/LockableFtur_PvnAdmisGpCfgBIy_MTQxOTU4Mzgw" + }, + "searchVisibility": { + "$ref": "#/components/schemas/LockableFeature_SearchVisibilityAvailableConfig_LTkxMTA5ODk5" + }, + "searchVisibilityInbound": { + "$ref": "#/components/schemas/LockableFeature_SearchVisibilityInboundConfig_NzA5NzczNTgy" + }, + "selfDeletingMessages": { + "$ref": "#/components/schemas/LockableFtur_SfDingMsCBIdy_LTg5MTEwNTA2" + }, + "simplifiedUserConnectionRequestQRCode": { + "$ref": "#/components/schemas/LockableFtur_SimpfdUsCnRqQg_Njk5NjU4OTgy" + }, + "sndFactorPasswordChallenge": { + "$ref": "#/components/schemas/LockableFeature_SndFactorPasswordChallengeConfig_MjQ3NzQ2ODgx" + }, + "sso": { + "$ref": "#/components/schemas/LockableFeature_SSOConfig_NjcyMjU4MDY2" + }, + "stealthUsers": { + "$ref": "#/components/schemas/LockableFeature_StealthUsersConfig_LTE1MTk2NzIz" + }, + "validateSAMLemails": { + "$ref": "#/components/schemas/LockableFtur_RqiExnmVfCg_NjUyMzgzNzY5" + } + }, + "required": [ + "legalhold", + "sso", + "searchVisibility", + "searchVisibilityInbound", + "validateSAMLemails", + "digitalSignatures", + "appLock", + "fileSharing", + "classifiedDomains", + "conferenceCalling", + "selfDeletingMessages", + "conversationGuestLinks", + "sndFactorPasswordChallenge", + "mls", + "exposeInvitationURLsToTeamAdmin", + "outlookCalIntegration", + "mlsE2EId", + "mlsMigration", + "enforceFileDownloadLocation", + "limitedEventFanout", + "domainRegistration", + "channels", + "preventAdminlessGroups", + "cells", + "allowedGlobalOperations", + "consumableNotifications", + "chatBubbles", + "apps", + "simplifiedUserConnectionRequestQRCode", + "assetAuditLog", + "stealthUsers", + "cellsInternal", + "meetings", + "meetingsPremium", + "backgroundEffects" + ], + "type": "object" + }, + "NameIDFormat": { + "enum": [ + "NameIDFUnspecified", + "NameIDFEmail", + "NameIDFX509", + "NameIDFWindows", + "NameIDFKerberos", + "NameIDFEntity", + "NameIDFPersistent", + "NameIDFTransient" + ], + "type": "string" + }, + "NameIdPolicy": { + "properties": { + "allowCreate": { + "type": "boolean" + }, + "format": { + "$ref": "#/components/schemas/NameIDFormat" + }, + "spNameQualifier": { + "type": "string" + } + }, + "required": [ + "format", + "allowCreate" + ], + "type": "object" + }, + "NewApp_LTQwODMwMzQ4": { + "properties": { + "accent_id": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "assets": { + "items": { + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" + }, + "type": "array" + }, + "category": { + "description": "Category name (if uncertain, pick \"other\")", + "type": "string" + }, + "description": { + "maxLength": 300, + "minLength": 0, + "type": "string" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "required": [ + "name", + "category", + "description", + "password" + ], + "type": "object" + }, + "NewAssetToken_NTAwMDQwODYy": { + "properties": { + "token": { + "$ref": "#/components/schemas/ASCII" + } + }, + "required": [ + "token" + ], + "type": "object" + }, + "NewClient_ODg1NjY4Njgy": { + "properties": { + "capabilities": { + "$ref": "#/components/schemas/ClientCapabilityList" + }, + "class": { + "$ref": "#/components/schemas/ClientClass_NjE3MDgwNzcx" + }, + "cookie": { + "description": "The cookie label, i.e. the label used when logging in.", + "type": "string" + }, + "label": { + "type": "string" + }, + "lastkey": { + "$ref": "#/components/schemas/UncheckedPrekeyBundle_LTU1MzQzOTgy" + }, + "mls_public_keys": { + "$ref": "#/components/schemas/MLSPublicKeys" + }, + "model": { + "type": "string" + }, + "password": { + "description": "The password of the authenticated user for verification. Note: Required for registration of the 2nd, 3rd, ... client.", + "maxLength": 1024, + "minLength": 6, + "type": "string" + }, + "prekeys": { + "description": "Prekeys for other clients to establish OTR sessions.", + "items": { + "$ref": "#/components/schemas/UncheckedPrekeyBundle_LTU1MzQzOTgy" + }, + "type": "array" + }, + "type": { + "$ref": "#/components/schemas/ClientType_MjQ0OTQwMzcw" + }, + "verification_code": { + "$ref": "#/components/schemas/ASCII" + } + }, + "required": [ + "prekeys", + "lastkey", + "type" + ], + "type": "object" + }, + "NewConv_LTgzNTk1NDQx": { + "description": "JSON object to create a new conversation. When using 'qualified_users' (preferred), you can omit 'users'", + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "cells": { + "type": "boolean" + }, + "conversation_role": { + "$ref": "#/components/schemas/RoleName" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" + }, + "history": { + "$ref": "#/components/schemas/History" + }, + "message_timer": { + "description": "Per-conversation message timer", + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, + "protocol": { + "$ref": "#/components/schemas/BaseProtocolTag_LTM0MDE1NTEx" + }, + "qualified_users": { + "description": "List of qualified user IDs (excluding the requestor) to be part of this conversation", + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "type": "array" + }, + "receipt_mode": { + "description": "Conversation receipt mode", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "skip_creator": { + "description": "Don't add creator to the conversation, only works for team admins not wanting to be part of the channels they create.", + "type": "boolean" + }, + "team": { + "$ref": "#/components/schemas/ConvTeamInfo_Mzc5NjcyNjAz" + }, + "users": { + "deprecated": true, + "description": "List of user IDs (excluding the requestor) to be part of this conversation (deprecated)", + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + } + }, + "type": "object" + }, + "NewLegalHoldService_Mzg0ODQ5NDU1": { + "properties": { + "auth_token": { + "$ref": "#/components/schemas/ASCII" + }, + "base_url": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "public_key": { + "$ref": "#/components/schemas/ServiceKeyPEM" + } + }, + "required": [ + "base_url", + "public_key", + "auth_token" + ], + "type": "object" + }, + "NewMeeting_LTI1NTMzOTU5": { + "description": "Request to create a new meeting", + "properties": { + "end_time": { + "$ref": "#/components/schemas/UTCTime" + }, + "invited_emails": { + "items": { + "$ref": "#/components/schemas/Email" + }, + "type": "array" + }, + "recurrence": { + "$ref": "#/components/schemas/Recurrence_LTQ0OTc0ODE2" + }, + "start_time": { + "$ref": "#/components/schemas/UTCTime" + }, + "title": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "tzid": { + "$ref": "#/components/schemas/TimeZone" + } + }, + "required": [ + "start_time", + "end_time", + "tzid", + "title" + ], + "type": "object" + }, + "NewOne2OneConv_LTI3OTc4NDAz": { + "description": "JSON object to create a new 1:1 conversation. When using 'qualified_users' (preferred), you can omit 'users'", + "properties": { + "name": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "qualified_users": { + "description": "List of qualified user IDs (excluding the requestor) to be part of this conversation", + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "type": "array" + }, + "team": { + "$ref": "#/components/schemas/ConvTeamInfo_Mzc5NjcyNjAz" + }, + "users": { + "deprecated": true, + "description": "List of user IDs (excluding the requestor) to be part of this conversation (deprecated)", + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + } + }, + "type": "object" + }, + "NewOtrMessage_LTUyMTE5MTMw": { + "properties": { + "data": { + "type": "string" + }, + "native_priority": { + "$ref": "#/components/schemas/Priority_ODA3NDM3MDYy" + }, + "native_push": { + "type": "boolean" + }, + "recipients": { + "$ref": "#/components/schemas/UserClientMap" + }, + "report_missing": { + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + }, + "sender": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" + }, + "transient": { + "type": "boolean" + } + }, + "required": [ + "sender", + "recipients" + ], + "type": "object" + }, + "NewPasswordReset_LTEyNzAxMTcy": { + "description": "Data to initiate a password reset", + "properties": { + "email": { + "$ref": "#/components/schemas/Email" + }, + "phone": { + "description": "Email", + "type": "string" + } + }, + "type": "object" + }, + "NewProviderResponse_OTE0ODI2NjU0": { + "properties": { + "id": { + "$ref": "#/components/schemas/UUID" + }, + "password": { + "maxLength": 1024, + "minLength": 8, + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "NewProvider_LTEyMTY5MjYy": { + "properties": { + "description": { + "maxLength": 1024, + "minLength": 1, + "type": "string" + }, + "email": { + "$ref": "#/components/schemas/Email" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + }, + "url": { + "$ref": "#/components/schemas/HttpsUrl" + } + }, + "required": [ + "name", + "email", + "url", + "description" + ], + "type": "object" + }, + "NewServiceResponse_LTExMzcwMjg5": { + "properties": { + "auth_token": { + "$ref": "#/components/schemas/ASCII" + }, + "id": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "NewService_LTYwOTU1MDQ3": { + "properties": { + "assets": { + "items": { + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" + }, + "type": "array" + }, + "auth_token": { + "$ref": "#/components/schemas/ASCII" + }, + "base_url": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "description": { + "maxLength": 1024, + "minLength": 1, + "type": "string" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "public_key": { + "$ref": "#/components/schemas/ServiceKeyPEM" + }, + "summary": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "tags": { + "items": { + "$ref": "#/components/schemas/ServiceTag_LTMyNTEzNjYy" + }, + "maxItems": 3, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "name", + "summary", + "description", + "base_url", + "public_key", + "assets", + "tags" + ], + "type": "object" + }, + "NewTeamCollaborator_LTIxNjEzMTYw": { + "properties": { + "permissions": { + "items": { + "$ref": "#/components/schemas/CollaboratorPermission_NDg5NTg2ODgy" + }, + "type": "array" + }, + "user": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "user", + "permissions" + ], + "type": "object" + }, + "NewTeamMember_Required_LTg2NjU5OTI2": { + "description": "Required data when creating new team members", + "properties": { + "member": { + "description": "the team member to add (the legalhold_status field must be null or missing!)", + "properties": { + "created_at": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "created_by": { + "$ref": "#/components/schemas/UUID" + }, + "permissions": { + "$ref": "#/components/schemas/Permissions_NDE0ODM5NDUx" + }, + "user": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "user", + "permissions" + ], + "type": "object" + } + }, + "required": [ + "member" + ], + "type": "object" + }, + "NewUserGroup_MzYxODU0OTU1": { + "properties": { + "members": { + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + }, + "name": { + "maxLength": 4000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "name", + "members" + ], + "type": "object" + }, + "NewUser_PlainTextPassword_8_LTI4MzI5NzQx": { + "properties": { + "accent_id": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "assets": { + "items": { + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" + }, + "type": "array" + }, + "email": { + "$ref": "#/components/schemas/Email" + }, + "email_code": { + "$ref": "#/components/schemas/ASCII" + }, + "expires_in": { + "maximum": 604800, + "minimum": 1, + "type": "integer" + }, + "invitation_code": { + "$ref": "#/components/schemas/ASCII" + }, + "label": { + "type": "string" + }, + "locale": { + "$ref": "#/components/schemas/Locale" + }, + "managed_by": { + "$ref": "#/components/schemas/ManagedBy_NTI0ODc0NTQx" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "password": { + "maxLength": 1024, + "minLength": 8, + "type": "string" + }, + "picture": { + "$ref": "#/components/schemas/Pict_DEPRECATED_USE_ASSETS_INSTEAD" + }, + "sso_id": { + "$ref": "#/components/schemas/UserSSOId" + }, + "supported_protocols": { + "items": { + "$ref": "#/components/schemas/BaseProtocolTag_LTM0MDE1NTEx" + }, + "type": "array" + }, + "team": { + "$ref": "#/components/schemas/BindingNewTeamUser_LTY0MDQxMDEw" + }, + "team_code": { + "$ref": "#/components/schemas/ASCII" + }, + "team_id": { + "$ref": "#/components/schemas/UUID" + }, + "uuid": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "OAuthAccessTokenRequest_LTYyNTcyMzI4": { + "properties": { + "client_id": { + "$ref": "#/components/schemas/UUID" + }, + "code": { + "$ref": "#/components/schemas/OAuthAuthorizationCode" + }, + "code_verifier": { + "description": "The code verifier to complete the code challenge", + "maxLength": 128, + "minLength": 43, + "type": "string" + }, + "grant_type": { + "$ref": "#/components/schemas/OAuthGrantType_LTIxODA5NDIw" + }, + "redirect_uri": { + "$ref": "#/components/schemas/RedirectUrl" + } + }, + "required": [ + "grant_type", + "client_id", + "code_verifier", + "code", + "redirect_uri" + ], + "type": "object" + }, + "OAuthAccessTokenResponse_NzEwOTI4NjQ0": { + "properties": { + "access_token": { + "description": "The access token, which has a relatively short lifetime", + "type": "string" + }, + "expires_in": { + "description": "The lifetime of the access token in seconds", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "refresh_token": { + "description": "The refresh token, which has a relatively long lifetime, and can be used to obtain a new access token", + "type": "string" + }, + "token_type": { + "$ref": "#/components/schemas/OAuthAccessTokenType_MjU3ODI0NDIw" + } + }, + "required": [ + "access_token", + "token_type", + "expires_in", + "refresh_token" + ], + "type": "object" + }, + "OAuthAccessTokenType_MjU3ODI0NDIw": { + "description": "The type of the access token. Currently only `Bearer` is supported.", + "enum": [ + "Bearer" + ], + "type": "string" + }, + "OAuthApplication_Mjk5NTUxNjA1": { + "properties": { + "id": { + "$ref": "#/components/schemas/UUID" + }, + "name": { + "description": "The OAuth client's name", + "maxLength": 256, + "minLength": 6, + "type": "string" + }, + "sessions": { + "description": "The OAuth client's sessions", + "items": { + "$ref": "#/components/schemas/OAuthSession_LTQxOTIxNTMy" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "sessions" + ], + "type": "object" + }, + "OAuthAuthorizationCode": { + "description": "The authorization code", + "type": "string" + }, + "OAuthClient_NzExMTI5NTIy": { + "properties": { + "application_name": { + "maxLength": 256, + "minLength": 6, + "type": "string" + }, + "client_id": { + "$ref": "#/components/schemas/UUID" + }, + "redirect_url": { + "$ref": "#/components/schemas/RedirectUrl" + } + }, + "required": [ + "client_id", + "application_name", + "redirect_url" + ], + "type": "object" + }, + "OAuthCodeChallenge": { + "description": "Generated by the client from the code verifier (unpadded base64url-encoded SHA256 hash of the code verifier)", + "type": "string" + }, + "OAuthGrantType_LTIxODA5NDIw": { + "description": "Indicates which authorization flow to use. Use `authorization_code` for authorization code flow.", + "enum": [ + "authorization_code", + "refresh_token" + ], + "type": "string" + }, + "OAuthRefreshAccessTokenRequest_LTUwNjA3OTI1": { + "properties": { + "client_id": { + "$ref": "#/components/schemas/UUID" + }, + "grant_type": { + "$ref": "#/components/schemas/OAuthGrantType_LTIxODA5NDIw" + }, + "refresh_token": { + "description": "The refresh token", + "type": "string" + } + }, + "required": [ + "grant_type", + "client_id", + "refresh_token" + ], + "type": "object" + }, + "OAuthResponseType_ODI2Mjg3NzQx": { + "description": "Indicates which authorization flow to use. Use `code` for authorization code flow.", + "enum": [ + "code" + ], + "type": "string" + }, + "OAuthRevokeRefreshTokenRequest_MjA1MDg4MzQ4": { + "properties": { + "client_id": { + "$ref": "#/components/schemas/UUID" + }, + "refresh_token": { + "description": "The refresh token", + "type": "string" + } + }, + "required": [ + "client_id", + "refresh_token" + ], + "type": "object" + }, + "OAuthSession_LTQxOTIxNTMy": { + "properties": { + "created_at": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "refresh_token_id": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "refresh_token_id", + "created_at" + ], + "type": "object" + }, + "Object": { + "additionalProperties": true, + "description": "A single notification event", + "properties": { + "type": { + "description": "Event type", + "type": "string" + } + }, + "title": "Event", + "type": "object" + }, + "OtherMemberUpdate_LTM1MjYzOTU0": { + "description": "Update user properties of other members relative to a conversation", + "properties": { + "conversation_role": { + "$ref": "#/components/schemas/RoleName" + } + }, + "type": "object" + }, + "OtherMember_LTgzNzE2MTk4": { + "properties": { + "conversation_role": { + "$ref": "#/components/schemas/RoleName" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "service": { + "$ref": "#/components/schemas/ServiceRef_LTgxMjY3NzAz" + }, + "status": { + "deprecated": true, + "description": "deprecated", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + } + }, + "required": [ + "qualified_id" + ], + "type": "object" + }, + "OtrMessage_LTY4MTYzNzg3": { + "description": "Encrypted message of a conversation", + "properties": { + "data": { + "description": "Extra (symmetric) data (i.e. ciphertext, Base64 in JSON) that is common with all other recipients.", + "type": "string" + }, + "recipient": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" + }, + "sender": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" + }, + "text": { + "description": "The ciphertext for the recipient (Base64 in JSON)", + "type": "string" + } + }, + "required": [ + "sender", + "recipient", + "text" + ], + "type": "object" + }, + "OwnConvMembers_LTEwMzUzODMy": { + "description": "Users of a conversation", + "properties": { + "others": { + "description": "All other current users of this conversation", + "items": { + "$ref": "#/components/schemas/OtherMember_LTgzNzE2MTk4" + }, + "type": "array" + }, + "self": { + "$ref": "#/components/schemas/Member_OTA5OTgyNzcw" + } + }, + "required": [ + "self", + "others" + ], + "type": "object" + }, + "OwnConversation_GroupConvType_LTU2MzYxNTg0": { + "description": "A conversation object as returned from the server", + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" + }, + "cipher_suite": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "creator": { + "$ref": "#/components/schemas/UUID" + }, + "epoch": { + "description": "The epoch number of the corresponding MLS group", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "epoch_timestamp": { + "$ref": "#/components/schemas/UTCTime" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "history": { + "$ref": "#/components/schemas/History" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "last_event": { + "type": "string" + }, + "last_event_time": { + "type": "string" + }, + "members": { + "$ref": "#/components/schemas/OwnConvMembers_LTEwMzUzODMy" + }, + "message_timer": { + "description": "Per-conversation message timer (can be null)", + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "type": "string" + }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, + "protocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "receipt_mode": { + "description": "Conversation receipt mode", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "type": { + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" + } + }, + "required": [ + "qualified_id", + "type", + "access", + "access_role", + "members", + "group_id", + "epoch" + ], + "type": "object" + }, + "PagingState": { + "description": "Paging state that should be supplied to retrieve the next page of results", + "type": "string" + }, + "PasswordChange_MTgzMDM2NTY2": { + "description": "Data to change a password. The old password is required if a password already exists.", + "properties": { + "new_password": { + "maxLength": 1024, + "minLength": 8, + "type": "string" + }, + "old_password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "required": [ + "new_password" + ], + "type": "object" + }, + "PasswordChange_NDI0ODgwNDU0": { + "properties": { + "new_password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + }, + "old_password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "required": [ + "old_password", + "new_password" + ], + "type": "object" + }, + "PasswordReqBody_LTcxMzE3ODE3": { + "properties": { + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "type": "object" + }, + "PasswordReset_LTYzNDYxNTQ3": { + "properties": { + "email": { + "$ref": "#/components/schemas/Email" + } + }, + "required": [ + "email" + ], + "type": "object" + }, + "Permissions_NDE0ODM5NDUx": { + "description": "This is just a complicated way of representing a team role. self and copy always have to contain the same integer, and only the following integers are allowed: 1025 (partner), 1587 (member), 5951 (admin), 8191 (owner). Unit tests of the galley-types package in wire-server contain an authoritative list.", + "properties": { + "copy": { + "description": "Permissions that this user is able to grant others", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "self": { + "description": "Permissions that the user has", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "self", + "copy" + ], + "type": "object" + }, + "PhoneNumber": { + "description": "A known phone number with a pending password reset.", + "type": "string" + }, + "Pict_DEPRECATED_USE_ASSETS_INSTEAD": { + "items": { + "type": "object" + }, + "maxItems": 10, + "minItems": 0, + "type": "array" + }, + "PrekeyBundle_MzgzOTk4MjYz": { + "properties": { + "clients": { + "items": { + "$ref": "#/components/schemas/ClientPrekey_LTcyODUzMTcw" + }, + "type": "array" + }, + "user": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "user", + "clients" + ], + "type": "object" + }, + "PreventAdminlessGroupsConfigB_Covered_Identity_MjQ2NDYwMTk2": { + "properties": { + "deletionTimeout": { + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "deletionTimeoutDuration": { + "type": "string" + }, + "promotionStrategy": { + "$ref": "#/components/schemas/PreventAdminlessGroupsPromotionStrategy_Mjc1ODA2MDU1" + }, + "reminderTimeoutDurations": { + "items": { + "type": "string" + }, + "type": "array" + }, + "reminderTimeouts": { + "items": { + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "type": "array" + } + }, + "required": [ + "promotionStrategy" + ], + "type": "object" + }, + "PreventAdminlessGroupsPromotionStrategy_Mjc1ODA2MDU1": { + "enum": [ + "alphabetical", + "random", + "all" + ], + "type": "string" + }, + "Priority_ODA3NDM3MDYy": { + "enum": [ + "low", + "high" + ], + "type": "string" + }, + "PropertyKeysAndValues": { + "type": "object" + }, + "PropertyValue": { + "description": "An arbitrary JSON value for a property" + }, + "ProtocolTag_ODg1MTE5NjEw": { + "enum": [ + "proteus", + "mls", + "mixed" + ], + "type": "string" + }, + "ProtocolUpdate_NzY1ODgxNDQy": { + "properties": { + "protocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + } + }, + "type": "object" + }, + "ProviderActivationResponse_LTgzNTU3MzA5": { + "properties": { + "email": { + "$ref": "#/components/schemas/Email" + } + }, + "required": [ + "email" + ], + "type": "object" + }, + "ProviderLogin_LTE2MTk2NTM5": { + "properties": { + "email": { + "$ref": "#/components/schemas/Email" + }, + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "required": [ + "email", + "password" + ], + "type": "object" + }, + "Provider_NDIyMzQ3ODIy": { + "properties": { + "description": { + "type": "string" + }, + "email": { + "$ref": "#/components/schemas/Email" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "url": { + "$ref": "#/components/schemas/HttpsUrl" + } + }, + "required": [ + "id", + "name", + "email", + "url", + "description" + ], + "type": "object" + }, + "PubClient": { + "properties": { + "class": { + "$ref": "#/components/schemas/ClientClass_NjE3MDgwNzcx" + }, + "id": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "PublicSubConversation_MjI2NTIxMzU4": { + "description": "An MLS subconversation", + "properties": { + "cipher_suite": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "epoch": { + "description": "The epoch number of the corresponding MLS group", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "epoch_timestamp": { + "$ref": "#/components/schemas/UTCTime" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "members": { + "items": { + "$ref": "#/components/schemas/ClientIdentity_MjAxMjI3NTUw" + }, + "type": "array" + }, + "parent_qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "subconv_id": { + "type": "string" + } + }, + "required": [ + "parent_qualified_id", + "subconv_id", + "group_id", + "epoch", + "members" + ], + "type": "object" + }, + "PushTokenList_NDI0Mjc3MzY3": { + "description": "List of Native Push Tokens", + "properties": { + "tokens": { + "description": "Push tokens", + "items": { + "$ref": "#/components/schemas/PushToken_ODYzMDYzOTA4" + }, + "type": "array" + } + }, + "required": [ + "tokens" + ], + "type": "object" + }, + "PushToken_ODYzMDYzOTA4": { + "description": "Native Push Token", + "properties": { + "app": { + "description": "Application", + "type": "string" + }, + "client": { + "description": "Client ID", + "type": "string" + }, + "token": { + "description": "Access Token", + "type": "string" + }, + "transport": { + "$ref": "#/components/schemas/Transport_NDk2NzU5NDIy" + } + }, + "required": [ + "transport", + "app", + "token", + "client" + ], + "type": "object" + }, + "PutApp_LTE4MDc1OTM4": { + "properties": { + "accent_id": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "assets": { + "items": { + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" + }, + "type": "array" + }, + "category": { + "description": "Category name (if uncertain, pick \"other\")", + "type": "string" + }, + "description": { + "maxLength": 300, + "minLength": 0, + "type": "string" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + } + }, + "type": "object" + }, + "QualifiedNewOtrMessage": { + "description": "This object can only be parsed from Protobuf.\nThe specification for the protobuf types is here: \nhttps://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto." + }, + "QualifiedUserClientPrekeyMapV4_MzcxOTAxMTYy": { + "properties": { + "failed_to_list": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "type": "array" + }, + "qualified_user_client_prekeys": { + "additionalProperties": { + "$ref": "#/components/schemas/UserClientPrekeyMap" + }, + "type": "object" + } + }, + "required": [ + "qualified_user_client_prekeys" + ], + "type": "object" + }, + "QualifiedUserClients": { + "additionalProperties": { + "additionalProperties": { + "items": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" + }, + "type": "array" + }, + "type": "object" + }, + "description": "Map of Domain to UserClients", + "example": { + "domain1.example.com": { + "1d51e2d6-9c70-605f-efc8-ff85c3dabdc7": [ + "60f85e4b15ad3786", + "6e323ab31554353b" + ] + } + }, + "type": "object" + }, + "QualifiedUserMap_Set_PubClient": { + "additionalProperties": { + "$ref": "#/components/schemas/UserMap_Set_PubClient" + }, + "description": "Map of Domain to (UserMap (Set_PubClient)).", + "example": { + "domain1.example.com": { + "1d51e2d6-9c70-605f-efc8-ff85c3dabdc7": [ + { + "class": "legalhold", + "id": "d0" + } + ] + } + }, + "type": "object" + }, + "Qualified_Handle_Nzg0MDE3Nzk4": { + "properties": { + "domain": { + "$ref": "#/components/schemas/Domain" + }, + "handle": { + "$ref": "#/components/schemas/Handle" + } + }, + "required": [ + "domain", + "handle" + ], + "type": "object" + }, + "Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5": { + "properties": { + "domain": { + "$ref": "#/components/schemas/Domain" + }, + "id": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "domain", + "id" + ], + "type": "object" + }, + "Qualified_Id_IdTag_Meeting_MjgxMDUyNjc3": { + "properties": { + "domain": { + "$ref": "#/components/schemas/Domain" + }, + "id": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "domain", + "id" + ], + "type": "object" + }, + "Qualified_Id_IdTag_User_LTQ1NTIwNDM1": { + "properties": { + "domain": { + "$ref": "#/components/schemas/Domain" + }, + "id": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "domain", + "id" + ], + "type": "object" + }, + "QueuedNotificationList_MTU0ODEyNTQ2": { + "description": "Zero or more notifications", + "properties": { + "has_more": { + "description": "Whether there are still more notifications.", + "type": "boolean" + }, + "notifications": { + "description": "Notifications", + "items": { + "$ref": "#/components/schemas/QueuedNotification_NTY2NzY2MTU2" + }, + "type": "array" + }, + "time": { + "$ref": "#/components/schemas/UTCTime" + } + }, + "required": [ + "notifications" + ], + "type": "object" + }, + "QueuedNotification_NTY2NzY2MTU2": { + "description": "A single notification", + "properties": { + "id": { + "$ref": "#/components/schemas/UUID" + }, + "payload": { + "description": "List of events", + "items": { + "$ref": "#/components/schemas/Object" + }, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "id", + "payload" + ], + "type": "object" + }, + "RTCConfiguration_LTIwOTc4OTk0": { + "description": "A subset of the WebRTC 'RTCConfiguration' dictionary", + "properties": { + "ice_servers": { + "description": "Array of 'RTCIceServer' objects", + "items": { + "$ref": "#/components/schemas/RTCIceServer_LTY1NzExODA0" + }, + "minItems": 1, + "type": "array" + }, + "is_federating": { + "description": "True if the client should connect to an SFT in the sft_servers_all and request it to federate", + "type": "boolean" + }, + "sft_servers": { + "description": "Array of 'SFTServer' objects (optional)", + "items": { + "$ref": "#/components/schemas/SFTServer_NDQ0NDkwNDE2" + }, + "minItems": 1, + "type": "array" + }, + "sft_servers_all": { + "description": "Array of all SFT servers", + "items": { + "$ref": "#/components/schemas/AuthSFTServer_LTY5MzcyOTE0" + }, + "type": "array" + }, + "ttl": { + "description": "Number of seconds after which the configuration should be refreshed (advisory)", + "format": "int32", + "maximum": 4294967295, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "ice_servers", + "ttl" + ], + "type": "object" + }, + "RTCIceServer_LTY1NzExODA0": { + "description": "A subset of the WebRTC 'RTCIceServer' object", + "properties": { + "credential": { + "$ref": "#/components/schemas/ASCII" + }, + "urls": { + "description": "Array of TURN server addresses of the form 'turn::'", + "items": { + "$ref": "#/components/schemas/TurnURI" + }, + "minItems": 1, + "type": "array" + }, + "username": { + "$ref": "#/components/schemas/TurnUsername" + } + }, + "required": [ + "urls", + "username", + "credential" + ], + "type": "object" + }, + "Recurrence_LTQ0OTc0ODE2": { + "description": "Recurrence pattern for meetings", + "properties": { + "frequency": { + "$ref": "#/components/schemas/Frequency_Mzk0ODQwOTM3" + }, + "interval": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "until": { + "$ref": "#/components/schemas/UTCTime" + } + }, + "required": [ + "frequency" + ], + "type": "object" + }, + "RedirectUrl": { + "description": "The URL must match the URL that was used to generate the authorization code.", + "type": "string" + }, + "RefreshAppCookieRequest_MjEyMDMyMTk5": { + "properties": { + "password": { + "description": "The password of the authenticated admin for verification. or if the user has only SAML credentials.", + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "type": "object" + }, + "RefreshAppCookieResponse_LTQ0MjU1NTIw": { + "properties": { + "cookie": { + "$ref": "#/components/schemas/SomeUserToken" + } + }, + "required": [ + "cookie" + ], + "type": "object" + }, + "RegisteredDomains_V10_NDYwNzYyMTMy": { + "properties": { + "registered_domains": { + "items": { + "$ref": "#/components/schemas/DomainRegistrationResponse_V10_MjE0NDkxODY4" + }, + "type": "array" + } + }, + "required": [ + "registered_domains" + ], + "type": "object" + }, + "Relation_LTE4OTU5MTk4": { + "enum": [ + "accepted", + "blocked", + "pending", + "ignored", + "sent", + "cancelled", + "missing-legalhold-consent" + ], + "type": "string" + }, + "RemoveBotResponse_LTUxNTQ4MDEy": { + "properties": { + "event": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "required": [ + "event" + ], + "type": "object" + }, + "RemoveCookies_OTYwMTI0NDMy": { + "description": "Data required to remove cookies", + "properties": { + "ids": { + "description": "A list of cookie IDs to revoke", + "items": { + "format": "int32", + "maximum": 4294967295, + "minimum": 0, + "type": "integer" + }, + "type": "array" + }, + "labels": { + "description": "A list of cookie labels for which to revoke the cookies", + "items": { + "type": "string" + }, + "type": "array" + }, + "password": { + "description": "The user's password", + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "required": [ + "password" + ], + "type": "object" + }, + "RemoveLegalHoldSettingsRequest_NzMzMzMyMDAz": { + "properties": { + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "type": "object" + }, + "RichField_LTgwMzc0MTg2": { + "properties": { + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "type", + "value" + ], + "type": "object" + }, + "RichInfoAssocList": { + "description": "json object with case-insensitive fields.", + "properties": { + "fields": { + "items": { + "$ref": "#/components/schemas/RichField_LTgwMzc0MTg2" + }, + "type": "array" + }, + "version": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + } + }, + "required": [ + "version", + "fields" + ], + "type": "object" + }, + "RmClient_MTQ5OTI2MDY3": { + "properties": { + "password": { + "description": "The password of the authenticated user for verification. The password is not required for deleting temporary clients. or if the user has only SAML credentials.", + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "type": "object" + }, + "RoleName": { + "description": "Role name, between 2 and 128 chars, 'wire_' prefix is reserved for roles designed by Wire (i.e., no custom roles can have the same prefix)", + "type": "string" + }, + "Role_LTIzMjAzMjky": { + "description": "Role of the invited user", + "enum": [ + "owner", + "admin", + "member", + "partner" + ], + "type": "string" + }, + "SFTServer_NDQ0NDkwNDE2": { + "description": "Inspired by WebRTC 'RTCIceServer' object, contains details of SFT servers", + "properties": { + "urls": { + "description": "Array containing exactly one SFT server address of the form 'https://:'", + "items": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "type": "array" + } + }, + "required": [ + "urls" + ], + "type": "object" + }, + "SFTUsername": { + "description": "String containing the SFT username", + "type": "string" + }, + "ScimTokenInfo_LTI5NjgwNzA1": { + "properties": { + "created_at": { + "$ref": "#/components/schemas/UTCTime" + }, + "description": { + "type": "string" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "idp": { + "$ref": "#/components/schemas/UUID" + }, + "name": { + "type": "string" + }, + "team": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "team", + "id", + "created_at", + "description", + "name" + ], + "type": "object" + }, + "ScimTokenList_NjQwNTYxOTAw": { + "properties": { + "tokens": { + "items": { + "$ref": "#/components/schemas/ScimTokenInfo_LTI5NjgwNzA1" + }, + "type": "array" + } + }, + "required": [ + "tokens" + ], + "type": "object" + }, + "ScimTokenName_LTgzOTM2OTI4": { + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "SearchResult_Contact_OTExNzg4MTE0": { + "properties": { + "documents": { + "description": "List of contacts found", + "items": { + "$ref": "#/components/schemas/Contact_LTcwODE3Mjc5" + }, + "type": "array" + }, + "found": { + "description": "Total number of hits", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "has_more": { + "description": "Indicates whether there are more results to be fetched", + "type": "boolean" + }, + "paging_state": { + "$ref": "#/components/schemas/PagingState" + }, + "returned": { + "description": "Total number of hits returned", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "search_policy": { + "$ref": "#/components/schemas/FederatedUserSearchPolicy_MzkwODA4MTM3" + }, + "took": { + "description": "Search time in ms", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + } + }, + "required": [ + "found", + "returned", + "took", + "documents", + "search_policy" + ], + "type": "object" + }, + "SearchResult_TeamContact_LTE0NjQ0NzMw": { + "properties": { + "documents": { + "description": "List of contacts found", + "items": { + "$ref": "#/components/schemas/TeamContact_LTI5MTIxODc0" + }, + "type": "array" + }, + "found": { + "description": "Total number of hits", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "has_more": { + "description": "Indicates whether there are more results to be fetched", + "type": "boolean" + }, + "paging_state": { + "$ref": "#/components/schemas/PagingState" + }, + "returned": { + "description": "Total number of hits returned", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "search_policy": { + "$ref": "#/components/schemas/FederatedUserSearchPolicy_MzkwODA4MTM3" + }, + "took": { + "description": "Search time in ms", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + } + }, + "required": [ + "found", + "returned", + "took", + "documents", + "search_policy" + ], + "type": "object" + }, + "SelfDeletingMessagesConfigB_Covered_Identity_LTY0NzQ4MzU1": { + "properties": { + "enforcedTimeoutSeconds": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + } + }, + "required": [ + "enforcedTimeoutSeconds" + ], + "type": "object" + }, + "SendActivationCode_LTgyNDAxNzEy": { + "description": "Data for requesting an email code to be sent. 'email' must be present.", + "properties": { + "email": { + "$ref": "#/components/schemas/Email" + }, + "locale": { + "$ref": "#/components/schemas/Locale" + } + }, + "required": [ + "email" + ], + "type": "object" + }, + "SendVerificationCode_MjgxNDgxODE2": { + "properties": { + "action": { + "$ref": "#/components/schemas/VerificationAction_LTU0MzYxNzUz" + }, + "email": { + "$ref": "#/components/schemas/Email" + } + }, + "required": [ + "action", + "email" + ], + "type": "object" + }, + "ServerTime_LTM4NTI3MzIx": { + "description": "The current server time", + "properties": { + "time": { + "$ref": "#/components/schemas/UTCTime" + } + }, + "required": [ + "time" + ], + "type": "object" + }, + "ServiceKeyPEM": { + "example": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+Kg/PHHU3atXrUbKnw0\nG06FliXcNt3lMwl2os5twEDcPPFw/feGiAKymxp+7JqZDrseS5D9THGrW+OQRIPH\nWvUBdiLfGrZqJO223DB6D8K2Su/odmnjZJ2z23rhXoEArTplu+Dg9K+c2LVeXTKV\nVPOaOzgtAB21XKRiQ4ermqgi3/njr03rXyq/qNkuNd6tNcg+HAfGxfGvvCSYBfiS\nbUKr/BeArYRcjzr/h5m1In6fG/if9GEI6m8dxHT9JbY53wiksowy6ajCuqskIFg8\n7X883H+LA/d6X5CTiPv1VMxXdBUiGPuC9IT/6CNQ1/LFt0P37ax58+LGYlaFo7la\nnQIDAQAB\n-----END PUBLIC KEY-----\n", + "type": "string" + }, + "ServiceKeyType_NTEzNzI4NTA2": { + "enum": [ + "rsa" + ], + "type": "string" + }, + "ServiceKey_NzY5NTY5NzYy": { + "properties": { + "pem": { + "$ref": "#/components/schemas/ServiceKeyPEM" + }, + "size": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "type": { + "$ref": "#/components/schemas/ServiceKeyType_NTEzNzI4NTA2" + } + }, + "required": [ + "type", + "size", + "pem" + ], + "type": "object" + }, + "ServiceProfilePage_Njg1NDQ5Njc4": { + "properties": { + "has_more": { + "type": "boolean" + }, + "services": { + "items": { + "$ref": "#/components/schemas/ServiceProfile_LTc2MDQzNTk3" + }, + "type": "array" + } + }, + "required": [ + "has_more", + "services" + ], + "type": "object" + }, + "ServiceProfile_LTc2MDQzNTk3": { + "properties": { + "assets": { + "items": { + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" + }, + "type": "array" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "provider": { + "$ref": "#/components/schemas/UUID" + }, + "summary": { + "type": "string" + }, + "tags": { + "items": { + "$ref": "#/components/schemas/ServiceTag_LTMyNTEzNjYy" + }, + "type": "array" + } + }, + "required": [ + "id", + "provider", + "name", + "summary", + "description", + "assets", + "tags", + "enabled" + ], + "type": "object" + }, + "ServiceRef_LTgxMjY3NzAz": { + "properties": { + "id": { + "$ref": "#/components/schemas/UUID" + }, + "provider": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "id", + "provider" + ], + "type": "object" + }, + "ServiceTagList": { + "items": { + "$ref": "#/components/schemas/ServiceTag_LTMyNTEzNjYy" + }, + "type": "array" + }, + "ServiceTag_LTMyNTEzNjYy": { + "enum": [ + "audio", + "books", + "business", + "design", + "education", + "entertainment", + "finance", + "fitness", + "food-drink", + "games", + "graphics", + "health", + "integration", + "lifestyle", + "media", + "medical", + "movies", + "music", + "news", + "photography", + "poll", + "productivity", + "quiz", + "rating", + "shopping", + "social", + "sports", + "travel", + "tutorial", + "video", + "weather" + ], + "type": "string" + }, + "Service_MjcyOTA5NjQx": { + "properties": { + "assets": { + "items": { + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" + }, + "type": "array" + }, + "auth_tokens": { + "items": { + "$ref": "#/components/schemas/ASCII" + }, + "minItems": 1, + "type": "array" + }, + "base_url": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "public_keys": { + "items": { + "$ref": "#/components/schemas/ServiceKey_NzY5NTY5NzYy" + }, + "minItems": 1, + "type": "array" + }, + "summary": { + "type": "string" + }, + "tags": { + "items": { + "$ref": "#/components/schemas/ServiceTag_LTMyNTEzNjYy" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "summary", + "description", + "base_url", + "auth_tokens", + "public_keys", + "assets", + "tags", + "enabled" + ], + "type": "object" + }, + "SetSearchable_NDAxODAxODI5": { + "properties": { + "set_searchable": { + "type": "boolean" + } + }, + "required": [ + "set_searchable" + ], + "type": "object" + }, + "SignedCertificate": { + "type": "string" + }, + "SimpleMember_NTY5MTcxMzcx": { + "properties": { + "conversation_role": { + "$ref": "#/components/schemas/RoleName" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + } + }, + "required": [ + "qualified_id" + ], + "type": "object" + }, + "SomeKey": {}, + "SomeUserToken": { + "type": "string" + }, + "SsoSettings": { + "properties": { + "default_sso_code": { + "$ref": "#/components/schemas/URI" + } + }, + "type": "object" + }, + "Sso_LTg1MDM5ODQ3": { + "properties": { + "issuer": { + "type": "string" + }, + "nameid": { + "type": "string" + } + }, + "required": [ + "issuer", + "nameid" + ], + "type": "object" + }, + "SupportedProtocolUpdate_LTE3Njk3MDM4": { + "properties": { + "supported_protocols": { + "items": { + "$ref": "#/components/schemas/BaseProtocolTag_LTM0MDE1NTEx" + }, + "type": "array" + } + }, + "required": [ + "supported_protocols" + ], + "type": "object" + }, + "SystemSettingsPublic_LTgwNTMxNjU2": { + "properties": { + "nomadProfiles": { + "description": "Whether Nomad client profiles are enabled; null or absence means not enabled.", + "type": "boolean" + }, + "setRestrictUserCreation": { + "description": "Do not allow certain user creation flows", + "type": "boolean" + } + }, + "required": [ + "setRestrictUserCreation" + ], + "type": "object" + }, + "SystemSettings_ODU3MDk5MTA3": { + "properties": { + "nomadProfiles": { + "description": "Whether Nomad client profiles are enabled; null or absence means not enabled.", + "type": "boolean" + }, + "setEnableMls": { + "description": "Whether MLS is enabled or not", + "type": "boolean" + }, + "setRestrictUserCreation": { + "description": "Do not allow certain user creation flows", + "type": "boolean" + }, + "ssoIdpChangeDetectionEnabled": { + "description": "Whether clients should compare the stored SSO IdP ID with the IdP ID of the current login and keep existing locally decrypted messages when they match.", + "type": "boolean" + } + }, + "required": [ + "setRestrictUserCreation", + "setEnableMls", + "ssoIdpChangeDetectionEnabled" + ], + "type": "object" + }, + "TeamBinding_LTE4NTM5MTc0": { + "deprecated": true, + "description": "Deprecated, please ignore.", + "enum": [ + true, + false + ], + "type": "boolean" + }, + "TeamCollaborator_LTI3MzM1MTYz": { + "properties": { + "permissions": { + "items": { + "$ref": "#/components/schemas/CollaboratorPermission_NDg5NTg2ODgy" + }, + "type": "array" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "user": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "user", + "team", + "permissions" + ], + "type": "object" + }, + "TeamContact_LTI5MTIxODc0": { + "properties": { + "accent_id": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "created_at": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "email": { + "$ref": "#/components/schemas/Email" + }, + "email_unvalidated": { + "$ref": "#/components/schemas/Email" + }, + "handle": { + "type": "string" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "managed_by": { + "$ref": "#/components/schemas/ManagedBy_NTI0ODc0NTQx" + }, + "name": { + "type": "string" + }, + "role": { + "$ref": "#/components/schemas/Role_LTIzMjAzMjky" + }, + "saml_idp": { + "type": "string" + }, + "scim_external_id": { + "type": "string" + }, + "searchable": { + "type": "boolean" + }, + "sso": { + "$ref": "#/components/schemas/Sso_LTg1MDM5ODQ3" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "type": { + "$ref": "#/components/schemas/UserType_LTU1OTU4OTM5" + }, + "user_groups": { + "description": "List of user group ids the user is a member of", + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + } + }, + "required": [ + "id", + "type", + "name", + "user_groups", + "searchable" + ], + "type": "object" + }, + "TeamConversationList_OTI3MzY3NzY0": { + "description": "Team conversation list", + "properties": { + "conversations": { + "items": { + "$ref": "#/components/schemas/TeamConversation_LTIwNzgyNTEz" + }, + "type": "array" + } + }, + "required": [ + "conversations" + ], + "type": "object" + }, + "TeamConversation_LTIwNzgyNTEz": { + "description": "Team conversation data", + "properties": { + "conversation": { + "$ref": "#/components/schemas/UUID" + }, + "managed": { + "description": "This field MUST NOT be used by clients. It is here only for backwards compatibility of the interface." + } + }, + "required": [ + "conversation", + "managed" + ], + "type": "object" + }, + "TeamDeleteData_ODI5NTU0ODE5": { + "properties": { + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + }, + "verification_code": { + "$ref": "#/components/schemas/ASCII" + } + }, + "type": "object" + }, + "TeamDomainRedirectTag_MjQwMjc1Mjk3": { + "enum": [ + "no-registration", + "none" + ], + "type": "string" + }, + "TeamInviteConfig_MTg4Nzk4NzMz": { + "properties": { + "domain_redirect": { + "$ref": "#/components/schemas/TeamDomainRedirectTag_MjQwMjc1Mjk3" + }, + "sso": { + "example": "99db9768-04e3-4b5d-9268-831b6a25c4ab", + "format": "uuid", + "type": "string" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "team_invite": { + "$ref": "#/components/schemas/TeamInviteTag_LTQyNTMyNzA0" + } + }, + "required": [ + "team_invite", + "team" + ], + "type": "object" + }, + "TeamInviteTag_LTQyNTMyNzA0": { + "enum": [ + "allowed", + "not-allowed", + "team" + ], + "type": "string" + }, + "TeamMemberDeleteData_LTg2OTEyOTI4": { + "description": "Data for a team member deletion request in case of binding teams.", + "properties": { + "password": { + "description": "The account password to authorise the deletion.", + "maxLength": 1024, + "minLength": 6, + "type": "string" + } + }, + "type": "object" + }, + "TeamMemberList_Optional_LTM1ODE2MzM0": { + "description": "list of team member", + "properties": { + "hasMore": { + "$ref": "#/components/schemas/ListType_LTkyMDM4MzA1" + }, + "members": { + "description": "the array of team members", + "items": { + "$ref": "#/components/schemas/TeamMember_Optional_NTU0MDcyNzI1" + }, + "type": "array" + } + }, + "required": [ + "members", + "hasMore" + ], + "type": "object" + }, + "TeamMember_Optional_NTU0MDcyNzI1": { + "description": "team member data", + "properties": { + "created_at": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "created_by": { + "$ref": "#/components/schemas/UUID" + }, + "legalhold_status": { + "$ref": "#/components/schemas/UserLegalHoldStatus_LTQ2ODA2NTU5" + }, + "permissions": { + "$ref": "#/components/schemas/Permissions_NDE0ODM5NDUx" + }, + "user": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "user" + ], + "type": "object" + }, + "TeamMembersPage_NzYwNDIxODgx": { + "properties": { + "hasMore": { + "type": "boolean" + }, + "members": { + "items": { + "$ref": "#/components/schemas/TeamMember_Optional_NTU0MDcyNzI1" + }, + "type": "array" + }, + "pagingState": { + "$ref": "#/components/schemas/TeamMembers_PagingState" + } + }, + "required": [ + "members", + "hasMore", + "pagingState" + ], + "type": "object" + }, + "TeamMembers_PagingState": { + "type": "string" + }, + "TeamSearchVisibilityView_Mzg3MzMzMTk3": { + "description": "Search visibility value for the team", + "properties": { + "search_visibility": { + "$ref": "#/components/schemas/TeamSearchVisibility_LTIzODE2Njk3" + } + }, + "required": [ + "search_visibility" + ], + "type": "object" + }, + "TeamSearchVisibility_LTIzODE2Njk3": { + "description": "value of visibility", + "enum": [ + "standard", + "no-name-outside-team" + ], + "type": "string" + }, + "TeamSize_LTMzMzk2MTk1": { + "description": "Team member counts broken down by user type.", + "properties": { + "teamSize": { + "description": "Total team members (teamSizeRegulars + teamSizeApps).", + "exclusiveMinimum": false, + "minimum": 0, + "type": "integer" + }, + "teamSizeApps": { + "description": "Number of apps in team.", + "exclusiveMinimum": false, + "minimum": 0, + "type": "integer" + }, + "teamSizeRegulars": { + "description": "Number of regular users in team.", + "exclusiveMinimum": false, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "teamSizeRegulars", + "teamSizeApps" + ], + "type": "object" + }, + "TeamUpdateData_LTE0NTM2NTU5": { + "properties": { + "icon": { + "$ref": "#/components/schemas/Icon" + }, + "icon_key": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "name": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "splash_screen": { + "$ref": "#/components/schemas/Icon" + } + }, + "type": "object" + }, + "Team_NDg4MjQwOTIw": { + "description": "`binding` is deprecated, and should be ignored. The non-binding teams API is not used (and will not be supported from API version V4 onwards), and `binding` will always be `true`.", + "properties": { + "binding": { + "$ref": "#/components/schemas/TeamBinding_LTE4NTM5MTc0" + }, + "creator": { + "$ref": "#/components/schemas/UUID" + }, + "icon": { + "$ref": "#/components/schemas/Icon" + }, + "icon_key": { + "type": "string" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "name": { + "type": "string" + }, + "splash_screen": { + "$ref": "#/components/schemas/Icon" + } + }, + "required": [ + "id", + "creator", + "name", + "icon" + ], + "type": "object" + }, + "Time": { + "properties": { + "time": { + "$ref": "#/components/schemas/UTCTime" + } + }, + "required": [ + "time" + ], + "type": "object" + }, + "TimeZone": { + "type": "string" + }, + "Token": { + "example": "ZXhhbXBsZQo=", + "type": "string" + }, + "TokenType_NTkyMzk4MjIz": { + "enum": [ + "Bearer" + ], + "type": "string" + }, + "Transport_NDk2NzU5NDIy": { + "description": "Transport", + "enum": [ + "GCM", + "APNS", + "APNS_SANDBOX", + "APNS_VOIP", + "APNS_VOIP_SANDBOX" + ], + "type": "string" + }, + "TurnURI": { + "type": "string" + }, + "TurnUsername": { + "description": "Username to use for authenticating against the given TURN servers", + "type": "string" + }, + "TypingStatus_LTg5MzcyNDMy": { + "enum": [ + "started", + "stopped" + ], + "type": "string" + }, + "URI": { + "type": "string" + }, + "URIRef_Absolute": { + "description": "URL of the invitation link to be sent to the invitee", + "type": "string" + }, + "UTCTime": { + "example": "2021-05-12T10:52:02Z", + "format": "yyyy-mm-ddThh:MM:ssZ", + "type": "string" + }, + "UTCTimeMillis": { + "description": "The time when the session was created", + "example": "2021-05-12T10:52:02.671Z", + "format": "yyyy-mm-ddThh:MM:ss.qqqZ", + "type": "string" + }, + "UUID": { + "description": "The OAuth client's ID", + "example": "99db9768-04e3-4b5d-9268-831b6a25c4ab", + "format": "uuid", + "type": "string" + }, + "UncheckedPrekeyBundle_LTU1MzQzOTgy": { + "properties": { + "id": { + "maximum": 65535, + "minimum": 0, + "type": "integer" + }, + "key": { + "type": "string" + } + }, + "required": [ + "id", + "key" + ], + "type": "object" + }, + "UpdateBotPrekeys_LTg3NzYxODg0": { + "properties": { + "prekeys": { + "items": { + "$ref": "#/components/schemas/UncheckedPrekeyBundle_LTU1MzQzOTgy" + }, + "type": "array" + } + }, + "required": [ + "prekeys" + ], + "type": "object" + }, + "UpdateClient_NzU5MjA4MzI1": { + "properties": { + "capabilities": { + "$ref": "#/components/schemas/ClientCapabilityList" + }, + "label": { + "description": "A new name for this client.", + "type": "string" + }, + "lastkey": { + "$ref": "#/components/schemas/UncheckedPrekeyBundle_LTU1MzQzOTgy" + }, + "mls_public_keys": { + "$ref": "#/components/schemas/MLSPublicKeys" + }, + "prekeys": { + "description": "New prekeys for other clients to establish OTR sessions.", + "items": { + "$ref": "#/components/schemas/UncheckedPrekeyBundle_LTU1MzQzOTgy" + }, + "type": "array" + } + }, + "type": "object" + }, + "UpdateMeeting_NTExNzYxMTcz": { + "description": "Request to update a meeting", + "properties": { + "end_time": { + "$ref": "#/components/schemas/UTCTime" + }, + "recurrence": { + "$ref": "#/components/schemas/Recurrence_LTQ0OTc0ODE2" + }, + "start_time": { + "$ref": "#/components/schemas/UTCTime" + }, + "title": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "tzid": { + "$ref": "#/components/schemas/TimeZone" + } + }, + "type": "object" + }, + "UpdateProvider_LTQwMjY4MDgy": { + "properties": { + "description": { + "type": "string" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "url": { + "$ref": "#/components/schemas/HttpsUrl" + } + }, + "type": "object" + }, + "UpdateServiceConn_LTQ1OTYwNjIz": { + "properties": { + "auth_tokens": { + "items": { + "$ref": "#/components/schemas/ASCII" + }, + "maxItems": 2, + "minItems": 1, + "type": "array" + }, + "base_url": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "enabled": { + "type": "boolean" + }, + "password": { + "maxLength": 1024, + "minLength": 6, + "type": "string" + }, + "public_keys": { + "items": { + "$ref": "#/components/schemas/ServiceKeyPEM" + }, + "maxItems": 2, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "password" + ], + "type": "object" + }, + "UpdateServiceWhitelist_LTU5MDAwMTIw": { + "properties": { + "id": { + "$ref": "#/components/schemas/UUID" + }, + "provider": { + "$ref": "#/components/schemas/UUID" + }, + "whitelisted": { + "type": "boolean" + } + }, + "required": [ + "provider", + "id", + "whitelisted" + ], + "type": "object" + }, + "UpdateService_MjAxNzQ2Njkz": { + "properties": { + "assets": { + "items": { + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" + }, + "type": "array" + }, + "description": { + "maxLength": 1024, + "minLength": 1, + "type": "string" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "summary": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "tags": { + "items": { + "$ref": "#/components/schemas/ServiceTag_LTMyNTEzNjYy" + }, + "maxItems": 3, + "minItems": 1, + "type": "array" + } + }, + "type": "object" + }, + "UpdateUserGroupChannels_LTIyMjcwMTMx": { + "properties": { + "channels": { + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + } + }, + "required": [ + "channels" + ], + "type": "object" + }, + "UpdateUserGroupMembers_LTg1MzQ2NDY3": { + "properties": { + "members": { + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + } + }, + "required": [ + "members" + ], + "type": "object" + }, + "UserClientMap": { + "additionalProperties": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "type": "object" + }, + "UserClientPrekeyMap": { + "additionalProperties": { + "additionalProperties": { + "properties": { + "id": { + "maximum": 65535, + "minimum": 0, + "type": "integer" + }, + "key": { + "type": "string" + } + }, + "required": [ + "id", + "key" + ], + "type": "object" + }, + "type": "object" + }, + "example": { + "1d51e2d6-9c70-605f-efc8-ff85c3dabdc7": { + "44901fb0712e588f": { + "id": 1, + "key": "pQABAQECoQBYIOjl7hw0D8YRNq..." + } + } + }, + "type": "object" + }, + "UserClients": { + "additionalProperties": { + "items": { + "description": "A 64-bit unsigned integer, represented as a hexadecimal numeral. Any valid hexadecimal numeral is accepted, but the backend will only produce representations with lowercase digits and no leading zeros", + "type": "string" + }, + "type": "array" + }, + "description": "Map of user id to list of client ids.", + "example": { + "1d51e2d6-9c70-605f-efc8-ff85c3dabdc7": [ + "60f85e4b15ad3786", + "6e323ab31554353b" + ] + }, + "type": "object" + }, + "UserConnection_LTY3NzU1ODg0": { + "properties": { + "conversation": { + "$ref": "#/components/schemas/UUID" + }, + "from": { + "$ref": "#/components/schemas/UUID" + }, + "last_update": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "qualified_conversation": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "qualified_to": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "status": { + "$ref": "#/components/schemas/Relation_LTE4OTU5MTk4" + }, + "to": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "from", + "qualified_to", + "status", + "last_update" + ], + "type": "object" + }, + "UserGroupAddUsers_LTgzOTYzNzk0": { + "properties": { + "members": { + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + } + }, + "required": [ + "members" + ], + "type": "object" + }, + "UserGroupNameAvailability_LTYzMDE1NTk4": { + "properties": { + "name_available": { + "type": "boolean" + } + }, + "required": [ + "name_available" + ], + "type": "object" + }, + "UserGroupPage_UserGroup_Const_LTMxNDg5MDAy": { + "description": "This is the last page if it contains fewer rows than requested. There may be 0 rows on a page.", + "properties": { + "page": { + "items": { + "$ref": "#/components/schemas/UserGroup_Const_NTMzOTAzMzA1" + }, + "type": "array" + }, + "total": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + } + }, + "required": [ + "page", + "total" + ], + "type": "object" + }, + "UserGroupUpdate_MjUyNTA3Mjgy": { + "properties": { + "name": { + "maxLength": 4000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "UserGroup_Const_NTMzOTAzMzA1": { + "properties": { + "channels": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "type": "array" + }, + "channelsCount": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "createdAt": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "managedBy": { + "$ref": "#/components/schemas/ManagedBy_NTI0ODc0NTQx" + }, + "membersCount": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "maxLength": 4000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "id", + "name", + "managedBy", + "createdAt" + ], + "type": "object" + }, + "UserGroup_Identity_NTg4MTY1MjEx": { + "properties": { + "channels": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "type": "array" + }, + "channelsCount": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "createdAt": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "managedBy": { + "$ref": "#/components/schemas/ManagedBy_NTI0ODc0NTQx" + }, + "members": { + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + }, + "membersCount": { + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "maxLength": 4000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "id", + "name", + "members", + "managedBy", + "createdAt" + ], + "type": "object" + }, + "UserIdList_MzA1MTI1Njgx": { + "properties": { + "user_ids": { + "items": { + "$ref": "#/components/schemas/UUID" + }, + "type": "array" + } + }, + "required": [ + "user_ids" + ], + "type": "object" + }, + "UserLegalHoldStatusResponse_LTQ1MzUxMTE3": { + "properties": { + "client": { + "$ref": "#/components/schemas/IdObject_ClientId_LTM3NjQyODM5" + }, + "last_prekey": { + "$ref": "#/components/schemas/UncheckedPrekeyBundle_LTU1MzQzOTgy" + }, + "status": { + "$ref": "#/components/schemas/UserLegalHoldStatus_LTQ2ODA2NTU5" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "UserLegalHoldStatus_LTQ2ODA2NTU5": { + "description": "The state of Legal Hold compliance for the member", + "enum": [ + "enabled", + "pending", + "disabled", + "no_consent" + ], + "type": "string" + }, + "UserMap_Set_PubClient": { + "additionalProperties": { + "items": { + "$ref": "#/components/schemas/PubClient" + }, + "type": "array", + "uniqueItems": true + }, + "description": "Map of UserId to (Set PubClient)", + "example": { + "1d51e2d6-9c70-605f-efc8-ff85c3dabdc7": [ + { + "class": "legalhold", + "id": "d0" + } + ] + }, + "type": "object" + }, + "UserProfile_LTQzMTQxMTE1": { + "properties": { + "accent_id": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "app": { + "$ref": "#/components/schemas/AppInfo_MjgwNTkwOTUz" + }, + "assets": { + "items": { + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" + }, + "type": "array" + }, + "contact_status": { + "$ref": "#/components/schemas/ContactStatus_LTUzNzk1MzM4" + }, + "deleted": { + "type": "boolean" + }, + "email": { + "$ref": "#/components/schemas/Email" + }, + "expires_at": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "handle": { + "$ref": "#/components/schemas/Handle" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "legalhold_status": { + "$ref": "#/components/schemas/UserLegalHoldStatus_LTQ2ODA2NTU5" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "picture": { + "$ref": "#/components/schemas/Pict_DEPRECATED_USE_ASSETS_INSTEAD" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "searchable": { + "type": "boolean" + }, + "service": { + "$ref": "#/components/schemas/ServiceRef_LTgxMjY3NzAz" + }, + "supported_protocols": { + "items": { + "$ref": "#/components/schemas/BaseProtocolTag_LTM0MDE1NTEx" + }, + "type": "array" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "text_status": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "type": { + "$ref": "#/components/schemas/UserType_LTU1OTU4OTM5" + } + }, + "required": [ + "qualified_id", + "name", + "accent_id", + "legalhold_status" + ], + "type": "object" + }, + "UserSSOId": { + "properties": { + "scim_external_id": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "tenant": { + "type": "string" + } + }, + "type": "object" + }, + "UserType_LTU1OTU4OTM5": { + "enum": [ + "regular", + "app", + "bot" + ], + "type": "string" + }, + "UserUpdate_MjQ4NTEwOTQz": { + "properties": { + "accent_id": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "assets": { + "items": { + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" + }, + "type": "array" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "picture": { + "$ref": "#/components/schemas/Pict_DEPRECATED_USE_ASSETS_INSTEAD" + }, + "text_status": { + "maxLength": 256, + "minLength": 1, + "type": "string" + } + }, + "type": "object" + }, + "User_NjA4OTQwMTQ4": { + "properties": { + "accent_id": { + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "assets": { + "items": { + "$ref": "#/components/schemas/Asset_LTIyMjc1NDEz" + }, + "type": "array" + }, + "deleted": { + "type": "boolean" + }, + "email": { + "$ref": "#/components/schemas/Email" + }, + "email_unvalidated": { + "$ref": "#/components/schemas/Email" + }, + "expires_at": { + "$ref": "#/components/schemas/UTCTimeMillis" + }, + "handle": { + "$ref": "#/components/schemas/Handle" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "locale": { + "$ref": "#/components/schemas/Locale" + }, + "managed_by": { + "$ref": "#/components/schemas/ManagedBy_NTI0ODc0NTQx" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "type": "string" + }, + "picture": { + "$ref": "#/components/schemas/Pict_DEPRECATED_USE_ASSETS_INSTEAD" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "searchable": { + "type": "boolean" + }, + "service": { + "$ref": "#/components/schemas/ServiceRef_LTgxMjY3NzAz" + }, + "sso_id": { + "$ref": "#/components/schemas/UserSSOId" + }, + "status": { + "$ref": "#/components/schemas/AccountStatus_NzkzNDU1ODU5" + }, + "supported_protocols": { + "items": { + "$ref": "#/components/schemas/BaseProtocolTag_LTM0MDE1NTEx" + }, + "type": "array" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "text_status": { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "type": { + "$ref": "#/components/schemas/UserType_LTU1OTU4OTM5" + } + }, + "required": [ + "qualified_id", + "type", + "name", + "accent_id", + "status", + "locale" + ], + "type": "object" + }, + "VerificationAction_LTU0MzYxNzUz": { + "enum": [ + "create_scim_token", + "login", + "delete_team" + ], + "type": "string" + }, + "VerifyDeleteUser_Njc1NDQ1MDIy": { + "description": "Data for verifying an account deletion.", + "properties": { + "code": { + "$ref": "#/components/schemas/ASCII" + }, + "key": { + "$ref": "#/components/schemas/ASCII" + } + }, + "required": [ + "key", + "code" + ], + "type": "object" + }, + "VersionInfo_NTEzMTgzNDQ0": { + "example": { + "development": [ + 18 + ], + "domain": "example.com", + "federation": false, + "supported": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18 + ] + }, + "properties": { + "development": { + "items": { + "$ref": "#/components/schemas/VersionNumber_Njk2NzI5Njk1" + }, + "type": "array" + }, + "domain": { + "$ref": "#/components/schemas/Domain" + }, + "federation": { + "type": "boolean" + }, + "supported": { + "items": { + "$ref": "#/components/schemas/VersionNumber_Njk2NzI5Njk1" + }, + "type": "array" + } + }, + "required": [ + "supported", + "development", + "federation", + "domain" + ], + "type": "object" + }, + "VersionNumber_Njk2NzI5Njk1": { + "enum": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18 + ], + "type": "integer" + }, + "Versiond_18_PvtAmlGupCfgBaIy_LTUyNzk3MzUx": { + "properties": { + "deletionTimeoutDuration": { + "type": "string" + }, + "promotionStrategy": { + "$ref": "#/components/schemas/PreventAdminlessGroupsPromotionStrategy_Mjc1ODA2MDU1" + }, + "reminderTimeoutDurations": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "promotionStrategy", + "deletionTimeoutDuration", + "reminderTimeoutDurations" + ], + "type": "object" + }, + "ViewLegalHoldServiceInfo_LTc3NjI2MzQ3": { + "properties": { + "auth_token": { + "$ref": "#/components/schemas/ASCII" + }, + "base_url": { + "$ref": "#/components/schemas/HttpsUrl" + }, + "fingerprint": { + "$ref": "#/components/schemas/Fingerprint" + }, + "public_key": { + "$ref": "#/components/schemas/ServiceKeyPEM" + }, + "team_id": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "team_id", + "base_url", + "fingerprint", + "auth_token", + "public_key" + ], + "type": "object" + }, + "ViewLegalHoldService_LTE3MzQzNDkw": { + "properties": { + "settings": { + "$ref": "#/components/schemas/ViewLegalHoldServiceInfo_LTc3NjI2MzQ3" + }, + "status": { + "$ref": "#/components/schemas/LHServiceStatus_ODc3NzE0Mjg3" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "WireIdPAPIVersion_NTEyMzIwNTU3": { + "enum": [ + "WireIdPAPIV1", + "WireIdPAPIV2" + ], + "type": "string" + }, + "WireIdP_ODMzOTExMzYw": { + "properties": { + "apiVersion": { + "enum": [ + "WireIdPAPIV1", + "WireIdPAPIV2" + ], + "type": "string" + }, + "domain": { + "example": "example.com", + "type": "string" + }, + "handle": { + "type": "string" + }, + "oldIssuers": { + "items": { + "$ref": "#/components/schemas/URI" + }, + "type": "array" + }, + "replacedBy": { + "type": "string" + }, + "team": { + "$ref": "#/components/schemas/UUID" + } + }, + "required": [ + "team", + "apiVersion", + "oldIssuers", + "replacedBy", + "handle", + "domain" + ], + "type": "object" + }, + "v2_ConversationAccessData_MjMxMTI5ODc3": { + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "$ref": "#/components/schemas/AccessRoleLegacy_LTYwOTAxMDI1" + }, + "access_role_v2": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + } + }, + "required": [ + "access" + ], + "type": "object" + }, + "v2_OwnConversation_GroupConvTypeLegacy_MjQ0OTcyNjQ3": { + "description": "A conversation object as returned from the server", + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "$ref": "#/components/schemas/AccessRoleLegacy_LTYwOTAxMDI1" + }, + "access_role_v2": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" + }, + "cipher_suite": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "creator": { + "$ref": "#/components/schemas/UUID" + }, + "epoch": { + "description": "The epoch number of the corresponding MLS group", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "epoch_timestamp": { + "$ref": "#/components/schemas/EpochTimestamp" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvTypeLegacy_NTUxMDI2Mzkw" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "history": { + "$ref": "#/components/schemas/History" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "last_event": { + "type": "string" + }, + "last_event_time": { + "type": "string" + }, + "members": { + "$ref": "#/components/schemas/OwnConvMembers_LTEwMzUzODMy" + }, + "message_timer": { + "description": "Per-conversation message timer (can be null)", + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "type": "string" + }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, + "protocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "receipt_mode": { + "description": "Conversation receipt mode", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "type": { + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" + } + }, + "required": [ + "qualified_id", + "type", + "access", + "members", + "group_id", + "epoch", + "epoch_timestamp", + "cipher_suite" + ], + "type": "object" + }, + "v2_OwnConversation_GroupConvType_LTU2MzYxNTg0": { + "description": "A conversation object as returned from the server", + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "$ref": "#/components/schemas/AccessRoleLegacy_LTYwOTAxMDI1" + }, + "access_role_v2": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" + }, + "cipher_suite": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "creator": { + "$ref": "#/components/schemas/UUID" + }, + "epoch": { + "description": "The epoch number of the corresponding MLS group", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "epoch_timestamp": { + "$ref": "#/components/schemas/EpochTimestamp" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "history": { + "$ref": "#/components/schemas/History" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "last_event": { + "type": "string" + }, + "last_event_time": { + "type": "string" + }, + "members": { + "$ref": "#/components/schemas/OwnConvMembers_LTEwMzUzODMy" + }, + "message_timer": { + "description": "Per-conversation message timer (can be null)", + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "type": "string" + }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, + "protocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "receipt_mode": { + "description": "Conversation receipt mode", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "type": { + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" + } + }, + "required": [ + "qualified_id", + "type", + "access", + "members", + "group_id", + "epoch", + "epoch_timestamp", + "cipher_suite" + ], + "type": "object" + }, + "v3_OwnConversation_GroupConvType_LTU2MzYxNTg0V3": { + "description": "A conversation object as returned from the server", + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" + }, + "cipher_suite": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "creator": { + "$ref": "#/components/schemas/UUID" + }, + "epoch": { + "description": "The epoch number of the corresponding MLS group", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "epoch_timestamp": { + "$ref": "#/components/schemas/EpochTimestamp" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "history": { + "$ref": "#/components/schemas/History" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "last_event": { + "type": "string" + }, + "last_event_time": { + "type": "string" + }, + "members": { + "$ref": "#/components/schemas/OwnConvMembers_LTEwMzUzODMy" + }, + "message_timer": { + "description": "Per-conversation message timer (can be null)", + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "type": "string" + }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, + "protocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "receipt_mode": { + "description": "Conversation receipt mode", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "type": { + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" + } + }, + "required": [ + "qualified_id", + "type", + "access", + "access_role", + "members", + "group_id", + "epoch", + "epoch_timestamp", + "cipher_suite" + ], + "type": "object" + }, + "v6_OwnConversation_GroupConvType_LTU2MzYxNTg0V6": { + "description": "A conversation object as returned from the server", + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" + }, + "cipher_suite": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "creator": { + "$ref": "#/components/schemas/UUID" + }, + "epoch": { + "description": "The epoch number of the corresponding MLS group", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "epoch_timestamp": { + "$ref": "#/components/schemas/UTCTime" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "history": { + "$ref": "#/components/schemas/History" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "last_event": { + "type": "string" + }, + "last_event_time": { + "type": "string" + }, + "members": { + "$ref": "#/components/schemas/OwnConvMembers_LTEwMzUzODMy" + }, + "message_timer": { + "description": "Per-conversation message timer (can be null)", + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "type": "string" + }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, + "protocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "receipt_mode": { + "description": "Conversation receipt mode", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "type": { + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" + } + }, + "required": [ + "qualified_id", + "type", + "access", + "access_role", + "members", + "group_id", + "epoch" + ], + "type": "object" + }, + "v9_OwnConversation_GroupConvType_LTU2MzYxNTg0": { + "description": "A conversation object as returned from the server", + "properties": { + "access": { + "items": { + "$ref": "#/components/schemas/Access_NjkyMzE5ODc0" + }, + "type": "array" + }, + "access_role": { + "items": { + "$ref": "#/components/schemas/AccessRole_Mzk3MDYzMzcw" + }, + "type": "array" + }, + "add_permission": { + "$ref": "#/components/schemas/AddPermission_LTE1MzgzNzE3" + }, + "cells_state": { + "$ref": "#/components/schemas/CellsState_LTg4MDEwNDA5" + }, + "cipher_suite": { + "$ref": "#/components/schemas/CipherSuiteTag" + }, + "creator": { + "$ref": "#/components/schemas/UUID" + }, + "epoch": { + "description": "The epoch number of the corresponding MLS group", + "format": "int64", + "maximum": 18446744073709551615, + "minimum": 0, + "type": "integer" + }, + "epoch_timestamp": { + "$ref": "#/components/schemas/UTCTime" + }, + "group_conv_type": { + "$ref": "#/components/schemas/GroupConvType_LTU4NjU0MTY5" + }, + "group_id": { + "$ref": "#/components/schemas/GroupId" + }, + "history": { + "$ref": "#/components/schemas/History" + }, + "id": { + "$ref": "#/components/schemas/UUID" + }, + "last_event": { + "type": "string" + }, + "last_event_time": { + "type": "string" + }, + "members": { + "$ref": "#/components/schemas/OwnConvMembers_LTEwMzUzODMy" + }, + "message_timer": { + "description": "Per-conversation message timer (can be null)", + "format": "int64", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808, + "type": "integer" + }, + "name": { + "type": "string" + }, + "parent": { + "$ref": "#/components/schemas/UUID" + }, + "protocol": { + "$ref": "#/components/schemas/ProtocolTag_ODg1MTE5NjEw" + }, + "qualified_id": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_Conversation_LTQ5NDQwNjc5" + }, + "receipt_mode": { + "description": "Conversation receipt mode", + "format": "int32", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "team": { + "$ref": "#/components/schemas/UUID" + }, + "type": { + "$ref": "#/components/schemas/ConvType_MzM0NTE3ODE5" + } + }, + "required": [ + "qualified_id", + "type", + "access", + "access_role", + "members", + "group_id", + "epoch" + ], + "type": "object" + } + }, + "securitySchemes": { + "ZAuth": { + "description": "Must be a token retrieved by calling 'POST /login' or 'POST /access'. It must be presented in this format: 'Bearer \\'.", + "in": "header", + "name": "Authorization", + "type": "apiKey" + } + } + }, + "info": { + "description": "## Authentication / Authorization\n\nThe end-points in this API support differing authorization protocols:\nsome are unauthenticated (`/api-version`, `/login`), some require\n[zauth](), and some support both [zauth]() and [oauth]().\n\nThe end-points that require zauth are labelled so in the description\nbelow. The end-points that support oauth as an alternative to zauth\nhave the required oauth scopes listed in the same description.\n\nFuther reading:\n- https://docs.wire.com/developer/reference/oauth.html\n- https://github.com/wireapp/wire-server/blob/develop/libs/wire-api/src/Wire/API/Routes/Public.hs (search for HasSwagger instances)\n- `curl https://staging-nginz-https.zinfra.io/v4/api/swagger.json | jq '.security, .securityDefinitions`\n\n### SSO Endpoints\n\n#### Overview\n\n`/sso/metadata` will be requested by the IdPs to learn how to talk to wire.\n\n`/sso/initiate-login`, `/sso/finalize-login` are for the SAML authentication handshake performed by a user in order to log into wire. They are not exactly standard in their details: they may return HTML or XML; redirect to error URLs instead of throwing errors, etc.\n\n`/identity-providers` end-points are for use in the team settings page when IdPs are registered. They talk json.\n\n\n#### Configuring IdPs\n\nIdPs usually allow you to copy the metadata into your clipboard. That should contain all the details you need to post the idp in your team under `/identity-providers`. (Team id is derived from the authorization credentials of the request.)\n\n##### okta.com\n\nOkta will ask you to provide two URLs when you set it up for talking to wireapp:\n\n1. The `Single sign on URL`. This is the end-point that accepts the user's credentials after successful authentication against the IdP. Choose `/sso/finalize-login` with schema and hostname of the wire server you are configuring.\n\n2. The `Audience URI`. You can find this in the metadata returned by the `/sso/metadata` end-point. It is the contents of the `md:OrganizationURL` element.\n\n##### centrify.com\n\nCentrify allows you to upload the metadata xml document that you get from the `/sso/metadata` end-point. You can also enter the metadata url and have centrify retrieve the xml, but to guarantee integrity of the setup, the metadata should be copied from the team settings page and pasted into the centrify setup page without any URL indirections.\n\n## Federation errors\n\nEndpoints involving federated calls to other domains can return some extra failure responses, common to all endpoints. Instead of listing them as possible responses for each endpoint, we document them here.\n\nFor errors that are more likely to be transient, we suggest clients to retry whatever request resulted in the error. Transient errors are indicated explicitly below.\n\n**Note**: when a failure occurs as a result of making a federated RPC to another backend, the error response contains the following extra fields:\n\n - `type`: \"federation\" (just the literal string in quotes, which can be used as an error type identifier when parsing errors)\n - `domain`: the target backend of the RPC that failed;\n - `path`: the path of the RPC that failed.\n\n### Domain errors\n\nErrors in this category result from trying to communicate with a backend that is considered non-existent or invalid. They can result from invalid user input or client issues, but they can also be a symptom of misconfiguration in one or multiple backends. These errors have a 4xx status code.\n\n - **Remote backend not found** (status: 422, label: `invalid-domain`): This backend attempted to contact a backend which does not exist or is not properly configured. For the most part, clients can consider this error equivalent to a domain not existing, although it should be noted that certain mistakes in the DNS configuration on a remote backend can lead to the backend not being recognized, and hence to this error. It is therefore not advisable to take any destructive action upon encountering this error, such as deleting remote users from conversations.\n - **Federation denied locally** (status: 400, label: `federation-denied`): This backend attempted an RPC to a non-whitelisted backend. Similar considerations as for the previous error apply.\n - **Federation not enabled** (status: 400, label: `federation-not-enabled`): Federation has not been configured for this backend. This will happen if a federation-aware client tries to talk to a backend for which federation is disabled, or if federation was disabled on the backend after reaching a federation-specific state (e.g. conversations with remote users). There is no way to cleanly recover from these errors at this point.\n\n### Local federation errors\n\nAn error in this category likely indicates an issue with the configuration of federation on the local backend. Possibly transient errors are indicated explicitly below. All these errors have a 500 status code.\n\n - **Federation unavailable** (status: 500, label: `federation-not-available`): Federation is configured for this backend, but the local federator cannot be reached. This can be transient, so clients should retry the request.\n - **Federation not implemented** (status: 422, label: `federation-not-implemented`): Federated behaviour for a certain endpoint is not yet implemented.\n - **Federator discovery failed** (status: 400, label: `discovery-failure`): A DNS error occurred during discovery of a remote backend. This can be transient, so clients should retry the request.\n - **Local federation error** (status: 500, label: `federation-local-error`): An error occurred in the communication between this backend and its local federator. These errors are most likely caused by bugs in the backend, and should be reported as such.\n\n### Remote federation errors\n\nErrors in this category are returned in case of communication issues between the local backend and a remote one, or if the remote side encountered an error while processing an RPC. Some errors in this category might be caused by incorrect client behaviour, wrong user input, or incorrect certificate configuration. Possibly transient errors are indicated explicitly. We use non-standard 5xx status codes for these errors.\n\n - **HTTP2 error** (status: 533, label: `federation-http2-error`): The current federator encountered an error when making an HTTP2 request to a remote one. Check the error message for more details.\n - **Connection refused** (status: 521, label: `federation-connection-refused`): The local federator could not connect to a remote one. This could be transient, so clients should retry the request.\n - **TLS failure**: (status: 525, label: `federation-tls-error`): An error occurred during the TLS handshake between the local federator and a remote one. This is most likely due to an issue with the certificate on the remote end.\n - **Remote federation error** (status: 533, label: `federation-remote-error`): The remote backend could not process a request coming from this backend. Check the error message for more details.\n - **Version negotiation error** (status: 533, label: `federation-version-error`): The remote backend returned invalid version information.\n\n### Backend compatibility errors\n\nAn error in this category will be returned when this backend makes an invalid or unsupported RPC to another backend. This can indicate some incompatibility between backends or a backend bug. These errors are unlikely to be transient, so retrying requests is *not* advised.\n\n - **Version mismatch** (status: 531, label: `federation-version-mismatch`): A remote backend is running an unsupported version of the federator.\n - **Invalid content type** (status: 533, label: `federation-invalid-content-type`): An RPC to another backend returned with an invalid content type.\n - **Unsupported content type** (status: 533, label: `federation-unsupported-content-type`): An RPC to another backend returned with an unsupported content type.\n", + "title": "Wire-Server API", + "version": "" + }, + "openapi": "3.0.0", + "paths": { + "/access": { + "post": { + "description": " [internal route ID: \"access\"]\n\nYou can provide only a cookie or a cookie and token. Every other combination is invalid. Access tokens can be given as query parameter or authorisation header, with the latter being preferred.", + "operationId": "access", + "parameters": [ + { + "in": "query", + "name": "client_id", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccessToken_ODIyMTczMjMw" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/AccessToken_ODIyMTczMjMw" + } + } + }, + "description": "OK", + "headers": { + "Set-Cookie": { + "schema": { + "type": "string" + } + } + } + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Authentication failed (label: `invalid-credentials`)" + } + }, + "summary": "Obtain an access tokens for a cookie" + } + }, + "/access/logout": { + "post": { + "description": " [internal route ID: \"logout\"]\n\nCalling this endpoint will effectively revoke the given cookie and subsequent calls to /access with the same cookie will result in a 403.", + "operationId": "logout", + "responses": { + "200": { + "description": "Logout" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Authentication failed (label: `invalid-credentials`)" + } + }, + "summary": "Log out in order to remove a cookie from the server" + } + }, + "/access/self/email": { + "put": { + "description": " [internal route ID: \"change-self-email\"]\n\n", + "operationId": "change-self-email", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/EmailUpdate_NjQ5MDg1OTY0" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + } + }, + "description": "Update accepted and pending activation of the new email" + }, + "204": { + "content": { + "application/json": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + } + }, + "description": "No update, current and new email address are the same\n\nEmail address activated" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-email", + "message": "Invalid e-mail address." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-email" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid e-mail address. (label: `invalid-email`) or `body`" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials", + "blacklisted-email" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Authentication failed (label: `invalid-credentials`)\n\nThe given e-mail address has been blacklisted due to a permanent bounce or a complaint. (label: `blacklisted-email`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "key-exists", + "message": "The given e-mail address is in use." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "key-exists" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The given e-mail address is in use. (label: `key-exists`)" + } + }, + "summary": "Change your email address" + } + }, + "/activate": { + "get": { + "description": " [internal route ID: \"get-activate\"]\n\nSee also 'POST /activate' which has a larger feature set.", + "operationId": "get-activate", + "parameters": [ + { + "description": "Activation key", + "in": "query", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Activation code", + "in": "query", + "name": "code", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActivationResponse_LTIyOTY5NDE3" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ActivationResponse_LTIyOTY5NDE3" + } + } + }, + "description": "Activation successful.\n\nActivation successful. (Dry run)\n\nActivation successful." + }, + "204": { + "description": "A recent activation was already successful." + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-phone", + "message": "Invalid mobile phone number" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-phone", + "invalid-email" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `code` or `key`\n\nInvalid mobile phone number (label: `invalid-phone`)\n\nInvalid e-mail address. (label: `invalid-email`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "invalid-code", + "message": "Invalid activation code" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid activation code (label: `invalid-code`)\n\nUser does not exist (label: `invalid-code`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "key-exists", + "message": "The given e-mail address is in use." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "key-exists" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The given e-mail address is in use. (label: `key-exists`)" + } + }, + "summary": "Activate (i.e. confirm) an email address." + }, + "post": { + "description": " [internal route ID: \"post-activate\"]\n\nActivation only succeeds once and the number of failed attempts for a valid key is limited.", + "operationId": "post-activate", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Activate_MzUzNzIxODUw" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActivationResponse_LTIyOTY5NDE3" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ActivationResponse_LTIyOTY5NDE3" + } + } + }, + "description": "Activation successful.\n\nActivation successful. (Dry run)\n\nActivation successful." + }, + "204": { + "description": "A recent activation was already successful." + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-phone", + "message": "Invalid mobile phone number" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-phone", + "invalid-email" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid mobile phone number (label: `invalid-phone`)\n\nInvalid e-mail address. (label: `invalid-email`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "invalid-code", + "message": "Invalid activation code" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid activation code (label: `invalid-code`)\n\nUser does not exist (label: `invalid-code`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "key-exists", + "message": "The given e-mail address is in use." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "key-exists" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The given e-mail address is in use. (label: `key-exists`)" + } + }, + "summary": "Activate (i.e. confirm) an email address." + } + }, + "/activate/send": { + "post": { + "description": " [internal route ID: \"post-activate-send\"]\n\n", + "operationId": "post-activate-send", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/SendActivationCode_LTgyNDAxNzEy" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Activation code sent." + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-email", + "message": "Invalid e-mail address." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-email" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid e-mail address. (label: `invalid-email`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "blacklisted-email", + "message": "The given e-mail address has been blacklisted due to a permanent bounce or a complaint." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "blacklisted-email" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The given e-mail address has been blacklisted due to a permanent bounce or a complaint. (label: `blacklisted-email`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "key-exists", + "message": "The given e-mail address is in use." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "key-exists" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The given e-mail address is in use. (label: `key-exists`)" + }, + "451": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 451, + "label": "domain-blocked-for-registration", + "message": "[Customer extension] The email domain has been blocked for Wire users. Please contact your IT department." + }, + "properties": { + "code": { + "enum": [ + 451 + ], + "type": "integer" + }, + "label": { + "enum": [ + "domain-blocked-for-registration" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "[Customer extension] The email domain has been blocked for Wire users. Please contact your IT department. (label: `domain-blocked-for-registration`)" + } + }, + "summary": "Send (or resend) an email activation code." + } + }, + "/api-version": { + "get": { + "description": " [internal route ID: \"get-version\"]\n\n", + "operationId": "get-version", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/VersionInfo_NTEzMTgzNDQ0" + } + } + }, + "description": "" + } + } + } + }, + "/assets": { + "post": { + "description": " [internal route ID: \"assets-upload\"]\n\n

Construct the request as multipart/mixed; set header Content-Type: multipart/mixed; boundary=<boundary>.

Use exactly two parts in this order:

  1. application/json metadata (AssetSettings)
  2. application/octet-stream asset bytes

Each part must include Content-Type and Content-Length; the second part may include Content-MD5. Use CRLF between headers and bodies.

When asset audit logging is enabled, the JSON metadata must include:

  • convId: object { id: UUID, domain: String } (qualified conversation ID)
  • filename: String
  • filetype: String MIME type (e.g. image/png, application/pdf)

Optional metadata: public (Bool, default false), retention (one of eternal, persistent, volatile, eternal-infrequent_access, expiring).

For profile pictures or team icons without a conversation, set convId.id to 00000000-0000-0000-0000-000000000000 and convId.domain to the tenant’s domain; use any reasonable filename.

Note: the server treats the asset bytes as application/octet-stream; filetype is used for auditing only.

Example body (boundary=frontier):

Content-Type: multipart/mixed; boundary=frontier

--frontier
Content-Type: application/json
Content-Length: 191

{\"public\":false,\"retention\":\"volatile\",\"convId\":{\"id\":\"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\",\"domain\":\"example.com\"},\"filename\":\"report.pdf\",\"filetype\":\"application/pdf\"}
--frontier
Content-Type: application/octet-stream
Content-Length: 11

Hello Audit
--frontier--
", + "operationId": "assets-upload", + "requestBody": { + "content": { + "multipart/mixed": { + "schema": { + "$ref": "#/components/schemas/AssetSource" + } + } + }, + "description": "A body with content type `multipart/mixed body`. The first section's content type should be `application/json`. The second section's content type should be always be `application/octet-stream`. Other content types will be ignored by the server." + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Asset_Qualified_AssetKey_MzU1MjMxNTA5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Asset_Qualified_AssetKey_MzU1MjMxNTA5" + } + } + }, + "description": "Asset posted", + "headers": { + "Location": { + "description": "Asset location", + "schema": { + "format": "url", + "type": "string" + } + } + } + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "incomplete-body", + "message": "HTTP content-length header does not match body size" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "incomplete-body", + "invalid-length" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nHTTP content-length header does not match body size (label: `incomplete-body`)\n\nInvalid content length (label: `invalid-length`)" + }, + "413": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 413, + "label": "client-error", + "message": "Asset too large" + }, + "properties": { + "code": { + "enum": [ + 413 + ], + "type": "integer" + }, + "label": { + "enum": [ + "client-error" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Asset too large (label: `client-error`)" + } + }, + "summary": "Upload an asset" + } + }, + "/assets/{key_domain}/{key}": { + "delete": { + "description": " [internal route ID: \"assets-delete\"]\n\n**Note**: only local assets can be deleted.", + "operationId": "assets-delete", + "parameters": [ + { + "in": "path", + "name": "key_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Asset deleted" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "unauthorised", + "message": "Unauthorised operation" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unauthorised" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unauthorised operation (label: `unauthorised`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Asset not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`key_domain` or `key` not found\n\nAsset not found (label: `not-found`)" + } + }, + "summary": "Delete an asset" + }, + "get": { + "description": " [internal route ID: \"assets-download\"]\n\n**Note**: local assets result in a redirect, while remote assets are streamed directly.", + "operationId": "assets-download", + "parameters": [ + { + "in": "path", + "name": "key_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "header", + "name": "Asset-Token", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "asset_token", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Asset returned directly with content type `application/octet-stream`" + }, + "302": { + "description": "Asset found", + "headers": { + "Location": { + "description": "Asset location", + "schema": { + "format": "url", + "type": "string" + } + } + } + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Asset not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`key_domain` or `key` or Asset not found (label: `not-found`)\n\nAsset not found (label: `not-found`)" + } + }, + "summary": "Download an asset" + } + }, + "/assets/{key}/token": { + "delete": { + "description": " [internal route ID: \"tokens-delete\"]\n\n**Note**: deleting the token makes the asset public.", + "operationId": "tokens-delete", + "parameters": [ + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Asset token deleted" + } + }, + "summary": "Delete an asset token" + }, + "post": { + "description": " [internal route ID: \"tokens-renew\"]\n\n", + "operationId": "tokens-renew", + "parameters": [ + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewAssetToken_NTAwMDQwODYy" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "unauthorised", + "message": "Unauthorised operation" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unauthorised" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unauthorised operation (label: `unauthorised`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Asset not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`key` not found\n\nAsset not found (label: `not-found`)" + } + }, + "summary": "Renew an asset token" + } + }, + "/await": { + "get": { + "description": " [internal route ID: \"await-notifications\"]\n\n", + "externalDocs": { + "description": "RFC 6455", + "url": "https://datatracker.ietf.org/doc/html/rfc6455" + }, + "operationId": "await-notifications", + "parameters": [ + { + "description": "Client ID", + "in": "query", + "name": "client", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "101": { + "description": "Connection upgraded." + }, + "426": { + "description": "Upgrade required." + } + }, + "summary": "Establish websocket connection" + } + }, + "/bot/assets": { + "post": { + "description": " [internal route ID: (\"assets-upload-v3\", bot)]\n\n

Construct the request as multipart/mixed; set header Content-Type: multipart/mixed; boundary=<boundary>.

Use exactly two parts in this order:

  1. application/json metadata (AssetSettings)
  2. application/octet-stream asset bytes

Each part must include Content-Type and Content-Length; the second part may include Content-MD5. Use CRLF between headers and bodies.

When asset audit logging is enabled, the JSON metadata must include:

  • convId: object { id: UUID, domain: String } (qualified conversation ID)
  • filename: String
  • filetype: String MIME type (e.g. image/png, application/pdf)

Optional metadata: public (Bool, default false), retention (one of eternal, persistent, volatile, eternal-infrequent_access, expiring).

For profile pictures or team icons without a conversation, set convId.id to 00000000-0000-0000-0000-000000000000 and convId.domain to the tenant’s domain; use any reasonable filename.

Note: the server treats the asset bytes as application/octet-stream; filetype is used for auditing only.

Example body (boundary=frontier):

Content-Type: multipart/mixed; boundary=frontier

--frontier
Content-Type: application/json
Content-Length: 191

{\"public\":false,\"retention\":\"volatile\",\"convId\":{\"id\":\"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\",\"domain\":\"example.com\"},\"filename\":\"report.pdf\",\"filetype\":\"application/pdf\"}
--frontier
Content-Type: application/octet-stream
Content-Length: 11

Hello Audit
--frontier--
", + "operationId": "assets-upload-v3_bot", + "requestBody": { + "content": { + "multipart/mixed": { + "schema": { + "$ref": "#/components/schemas/AssetSource" + } + } + }, + "description": "A body with content type `multipart/mixed body`. The first section's content type should be `application/json`. The second section's content type should be always be `application/octet-stream`. Other content types will be ignored by the server." + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Asset_Qualified_AssetKey_MzU1MjMxNTA5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Asset_Qualified_AssetKey_MzU1MjMxNTA5" + } + } + }, + "description": "Asset posted", + "headers": { + "Location": { + "description": "Asset location", + "schema": { + "format": "url", + "type": "string" + } + } + } + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "incomplete-body", + "message": "HTTP content-length header does not match body size" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "incomplete-body", + "invalid-length" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nHTTP content-length header does not match body size (label: `incomplete-body`)\n\nInvalid content length (label: `invalid-length`)" + }, + "413": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 413, + "label": "client-error", + "message": "Asset too large" + }, + "properties": { + "code": { + "enum": [ + 413 + ], + "type": "integer" + }, + "label": { + "enum": [ + "client-error" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Asset too large (label: `client-error`)" + } + }, + "summary": "Upload an asset" + } + }, + "/bot/assets/{key}": { + "delete": { + "description": " [internal route ID: (\"assets-delete-v3\", bot)]\n\n", + "operationId": "assets-delete-v3_bot", + "parameters": [ + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Asset deleted" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "unauthorised", + "message": "Unauthorised operation" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unauthorised" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unauthorised operation (label: `unauthorised`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Asset not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`key` not found\n\nAsset not found (label: `not-found`)" + } + }, + "summary": "Delete an asset" + }, + "get": { + "description": " [internal route ID: (\"assets-download-v3\", bot)]\n\n", + "operationId": "assets-download-v3_bot", + "parameters": [ + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "header", + "name": "Asset-Token", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "asset_token", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "302": { + "description": "Asset found", + "headers": { + "Location": { + "description": "Asset location", + "schema": { + "format": "url", + "type": "string" + } + } + } + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Asset not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Asset not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`key` or Asset not found (label: `not-found`)" + } + }, + "summary": "Download an asset" + } + }, + "/bot/client": { + "get": { + "description": " [internal route ID: \"bot-get-client\"]\n\n", + "operationId": "bot-get-client", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Client_MTM1OTcwOTQ1" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Client_MTM1OTcwOTQ1" + } + } + }, + "description": "Client found" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "client-not-found", + "message": "Client not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "client-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "client-not-found", + "message": "Client not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "client-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Client not found (label: `client-not-found`)\n\nClient not found (label: `client-not-found`)" + } + }, + "summary": "Get client for bot" + } + }, + "/bot/client/prekeys": { + "get": { + "description": " [internal route ID: \"bot-list-prekeys\"]\n\n", + "operationId": "bot-list-prekeys", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "items": { + "maximum": 65535, + "minimum": 0, + "type": "integer" + }, + "type": "array" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + } + }, + "summary": "List prekeys for bot" + }, + "post": { + "description": " [internal route ID: \"bot-update-prekeys\"]\n\n", + "operationId": "bot-update-prekeys", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UpdateBotPrekeys_LTg3NzYxODg0" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "client-not-found", + "message": "Client not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "client-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Client not found (label: `client-not-found`)" + } + }, + "summary": "Update prekeys for bot" + } + }, + "/bot/conversation": { + "get": { + "description": " [internal route ID: \"get-bot-conversation\"]\n\n", + "operationId": "get-bot-conversation", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/BotConvView_LTYzMjIzMjQz" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)\n\nYou do not have permission to access this resource (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team", + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Team not found (label: `no-team`)\n\nConversation not found (label: `no-conversation`)" + } + } + } + }, + "/bot/conversations/{conv}": { + "post": { + "description": " [internal route ID: \"add-bot\"]\n\n", + "operationId": "add-bot", + "parameters": [ + { + "in": "path", + "name": "conv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/AddBot_NjI0ODkyODk3" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddBotResponse_ODA5MzA2NTA1" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/AddBotResponse_ODA5MzA2NTA1" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "service-disabled", + "message": "The desired service is currently disabled." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "service-disabled", + "too-many-members", + "invalid-conversation", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The desired service is currently disabled. (label: `service-disabled`)\n\nMaximum number of members per conversation reached. (label: `too-many-members`)\n\nThe operation is not allowed in this conversation. (label: `invalid-conversation`)\n\nAccess denied. (label: `access-denied`)" + } + }, + "summary": "Add bot" + } + }, + "/bot/conversations/{conv}/{bot}": { + "delete": { + "description": " [internal route ID: \"remove-bot\"]\n\n", + "operationId": "remove-bot", + "parameters": [ + { + "in": "path", + "name": "conv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "bot", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoveBotResponse_LTUxNTQ4MDEy" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/RemoveBotResponse_LTUxNTQ4MDEy" + } + } + }, + "description": "User found" + }, + "204": { + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-conversation", + "message": "The operation is not allowed in this conversation." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-conversation", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The operation is not allowed in this conversation. (label: `invalid-conversation`)\n\nAccess denied. (label: `access-denied`)" + } + }, + "summary": "Remove bot" + } + }, + "/bot/messages": { + "post": { + "description": " [internal route ID: \"post-bot-message-unqualified\"]\n\n", + "operationId": "post-bot-message-unqualified", + "parameters": [ + { + "in": "query", + "name": "ignore_missing", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "report_missing", + "required": false, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewOtrMessage_LTUyMTE5MTMw" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + } + }, + "description": "Message sent" + }, + "403": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unknown Client (label: `unknown-client`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation not found (label: `no-conversation`)\n\nConversation not found (label: `no-conversation`)" + }, + "412": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + } + }, + "description": "Missing clients" + } + } + } + }, + "/bot/self": { + "delete": { + "description": " [internal route ID: \"bot-delete-self\"]\n\n", + "operationId": "bot-delete-self", + "responses": { + "200": { + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-bot", + "message": "The targeted user is not a bot." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-bot", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The targeted user is not a bot. (label: `invalid-bot`)\n\nAccess denied. (label: `access-denied`)" + } + }, + "summary": "Delete self" + }, + "get": { + "description": " [internal route ID: \"bot-get-self\"]\n\n", + "operationId": "bot-get-self", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserProfile_LTQzMTQxMTE1" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "User not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "User not found (label: `not-found`)" + } + }, + "summary": "Get self" + } + }, + "/bot/users": { + "get": { + "description": " [internal route ID: \"bot-list-users\"]\n\n", + "operationId": "bot-list-users", + "parameters": [ + { + "in": "query", + "name": "ids", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/BotUserView_LTE2MTkwMTcw" + }, + "type": "array" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + } + }, + "summary": "List users" + } + }, + "/bot/users/prekeys": { + "post": { + "description": " [internal route ID: \"bot-claim-users-prekeys\"]\n\n", + "operationId": "bot-claim-users-prekeys", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserClients" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserClientPrekeyMap" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "missing-legalhold-consent", + "message": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "missing-legalhold-consent", + "missing-legalhold-consent-old-clients", + "too-many-clients", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)\n\nToo many clients (label: `too-many-clients`)\n\nAccess denied. (label: `access-denied`)" + } + }, + "summary": "Claim users prekeys" + } + }, + "/bot/users/{user}/clients": { + "get": { + "description": " [internal route ID: \"bot-get-user-clients\"]\n\n", + "operationId": "bot-get-user-clients", + "parameters": [ + { + "in": "path", + "name": "user", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/PubClient" + }, + "type": "array" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + } + }, + "summary": "Get user clients" + } + }, + "/broadcast/otr/messages": { + "post": { + "description": " [internal route ID: \"post-otr-broadcast-unqualified\"]\n\nThis endpoint ensures that the list of clients is correct and only sends the message if the list is correct.\nTo override this, the endpoint accepts two query params:\n- `ignore_missing`: Can be 'true' 'false' or a comma separated list of user IDs.\n - When 'true' all missing clients are ignored.\n - When 'false' all missing clients are reported.\n - When comma separated list of user-ids, only clients for listed users are ignored.\n- `report_missing`: Can be 'true' 'false' or a comma separated list of user IDs.\n - When 'true' all missing clients are reported.\n - When 'false' all missing clients are ignored.\n - When comma separated list of user-ids, only clients for listed users are reported.\n\nApart from these, the request body also accepts `report_missing` which can only be a list of user ids and behaves the same way as the query parameter.\n\nAll three of these should be considered mutually exclusive. The server however does not error if more than one is specified, it reads them in this order of precedence:\n- `report_missing` in the request body has highest precedence.\n- `ignore_missing` in the query param is the next.\n- `report_missing` in the query param has the lowest precedence.\n\nThis endpoint can lead to OtrMessageAdd event being sent to the recipients.\n\n**NOTE:** The protobuf definitions of the request body can be found at https://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto.", + "operationId": "post-otr-broadcast-unqualified", + "parameters": [ + { + "in": "query", + "name": "ignore_missing", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "report_missing", + "required": false, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewOtrMessage_LTUyMTE5MTMw" + } + }, + "application/x-protobuf": { + "schema": { + "$ref": "#/components/schemas/NewOtrMessage_LTUyMTE5MTMw" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + } + }, + "description": "Message sent" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "too-many-users-to-broadcast", + "message": "Too many users to fan out the broadcast event to" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "too-many-users-to-broadcast" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body` or `report_missing` or `ignore_missing`\n\nToo many users to fan out the broadcast event to (label: `too-many-users-to-broadcast`)" + }, + "403": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unknown Client (label: `unknown-client`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation", + "non-binding-team", + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation not found (label: `no-conversation`)\n\nNot a member of a binding team (label: `non-binding-team`)\n\nTeam not found (label: `no-team`)" + }, + "412": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + } + }, + "description": "Missing clients" + } + }, + "summary": "Broadcast an encrypted message to all team members and all contacts (accepts JSON or Protobuf)" + } + }, + "/broadcast/proteus/messages": { + "post": { + "description": " [internal route ID: \"post-proteus-broadcast\"]\n\nThis endpoint ensures that the list of clients is correct and only sends the message if the list is correct.\nTo override this, the endpoint accepts `client_mismatch_strategy` in the body. It can have these values:\n- `report_all`: When set, the message is not sent if any clients are missing. The missing clients are reported in the response.\n- `ignore_all`: When set, no checks about missing clients are carried out.\n- `report_only`: Takes a list of qualified UserIDs. If any clients of the listed users are missing, the message is not sent. The missing clients are reported in the response.\n- `ignore_only`: Takes a list of qualified UserIDs. If any clients of the non-listed users are missing, the message is not sent. The missing clients are reported in the response.\n\nThe sending of messages in a federated conversation could theoretically fail partially. To make this case unlikely, the backend first gets a list of clients from all the involved backends and then tries to send a message. So, if any backend is down, the message is not propagated to anyone. But the actual message fan out to multiple backends could still fail partially. This type of failure is reported as a 201, the clients for which the message sending failed are part of the response body.\n\nThis endpoint can lead to OtrMessageAdd event being sent to the recipients.\n\n**NOTE:** The protobuf definitions of the request body can be found at https://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto.", + "operationId": "post-proteus-broadcast", + "requestBody": { + "content": { + "application/x-protobuf": { + "schema": { + "$ref": "#/components/schemas/QualifiedNewOtrMessage" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageSendingStatus_ODg0NDgyNDk4" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MessageSendingStatus_ODg0NDgyNDk4" + } + } + }, + "description": "Message sent" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "too-many-users-to-broadcast", + "message": "Too many users to fan out the broadcast event to" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "too-many-users-to-broadcast" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nToo many users to fan out the broadcast event to (label: `too-many-users-to-broadcast`)" + }, + "403": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unknown Client (label: `unknown-client`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation", + "non-binding-team", + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation not found (label: `no-conversation`)\n\nNot a member of a binding team (label: `non-binding-team`)\n\nTeam not found (label: `no-team`)" + }, + "412": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageSendingStatus_ODg0NDgyNDk4" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MessageSendingStatus_ODg0NDgyNDk4" + } + } + }, + "description": "Missing clients" + } + }, + "summary": "Post an encrypted message to all team members and all contacts (accepts only Protobuf)" + } + }, + "/calls/config/v2": { + "get": { + "description": " [internal route ID: \"get-calls-config-v2\"]\n\n", + "operationId": "get-calls-config-v2", + "parameters": [ + { + "description": "Limit resulting list. Allowed values [1..10]", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "maximum": 10, + "minimum": 1, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/RTCConfiguration_LTIwOTc4OTk0" + } + } + }, + "description": "" + } + }, + "summary": "Retrieve all TURN server addresses and credentials. Clients are expected to do a DNS lookup to resolve the IP addresses of the given hostnames " + } + }, + "/clients": { + "get": { + "description": " [internal route ID: \"list-clients\"]\n\n", + "operationId": "list-clients", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/Client_MTM1OTcwOTQ1" + }, + "type": "array" + } + }, + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/Client_MTM1OTcwOTQ1" + }, + "type": "array" + } + } + }, + "description": "List of clients" + } + }, + "summary": "List the registered clients" + }, + "post": { + "description": " [internal route ID: \"add-client\"]\n\n", + "operationId": "add-client", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewClient_ODg1NjY4Njgy" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Client_MTM1OTcwOTQ1" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Client_MTM1OTcwOTQ1" + } + } + }, + "description": "Client registered", + "headers": { + "Location": { + "description": "Client ID", + "schema": { + "type": "string" + } + } + } + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "bad-request", + "message": "Malformed prekeys uploaded" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "bad-request" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nMalformed prekeys uploaded (label: `bad-request`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "code-authentication-required", + "message": "Code authentication is required" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "code-authentication-required", + "code-authentication-failed", + "missing-auth", + "too-many-clients" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Code authentication is required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nRe-authentication via password required (label: `missing-auth`)\n\nToo many clients (label: `too-many-clients`)" + } + }, + "summary": "Register a new client" + } + }, + "/clients/{cid}/access-token": { + "post": { + "description": " [internal route ID: \"create-access-token\"]\n\nCreate an JWT DPoP access token for the client CSR, given a JWT DPoP proof, specified in the `DPoP` header. The access token will be returned in the JSON response body as a JWT DPoP token.", + "operationId": "create-access-token", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "cid", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "header", + "name": "DPoP", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DPoPAccessTokenResponse_LTgyODU5MDE3" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DPoPAccessTokenResponse_LTgyODU5MDE3" + } + } + }, + "description": "Access token created", + "headers": { + "Cache-Control": { + "schema": { + "type": "string" + } + } + } + } + }, + "summary": "Create a JWT DPoP access token" + } + }, + "/clients/{client}": { + "delete": { + "description": " [internal route ID: \"delete-client\"]\n\n", + "operationId": "delete-client", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/RmClient_MTQ5OTI2MDY3" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Client deleted" + } + }, + "summary": "Delete an existing client" + }, + "get": { + "description": " [internal route ID: \"get-client\"]\n\n", + "operationId": "get-client", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Client_MTM1OTcwOTQ1" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Client_MTM1OTcwOTQ1" + } + } + }, + "description": "Client found" + }, + "404": { + "description": "`client` or Client not found(**Note**: This error has an empty body for legacy reasons)" + } + }, + "summary": "Get a registered client by ID" + }, + "put": { + "description": " [internal route ID: \"update-client\"]\n\n", + "operationId": "update-client", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UpdateClient_NzU5MjA4MzI1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Client updated" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-duplicate-public-key", + "message": "MLS public key for the given signature scheme already exists" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-duplicate-public-key", + "bad-request" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nMLS public key for the given signature scheme already exists (label: `mls-duplicate-public-key`)\n\nMalformed prekeys uploaded (label: `bad-request`)" + } + }, + "summary": "Update a registered client" + } + }, + "/clients/{client}/capabilities": { + "get": { + "description": " [internal route ID: \"get-client-capabilities\"]\n\n", + "operationId": "get-client-capabilities", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ClientCapabilityList" + } + } + }, + "description": "" + } + }, + "summary": "Read back what the client has been posting about itself" + } + }, + "/clients/{client}/nonce": { + "get": { + "description": " [internal route ID: \"get-nonce\"]\n\nGet a new nonce for a client CSR, specified in the response header `Replay-Nonce` as a uuidv4 in base64url encoding.", + "operationId": "get-nonce", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "No Content", + "headers": { + "Cache-Control": { + "schema": { + "type": "string" + } + }, + "Replay-Nonce": { + "schema": { + "type": "string" + } + } + } + } + }, + "summary": "Get a new nonce for a client CSR" + }, + "head": { + "description": " [internal route ID: \"head-nonce\"]\n\nGet a new nonce for a client CSR, specified in the response header `Replay-Nonce` as a uuidv4 in base64url encoding.", + "operationId": "head-nonce", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "No Content", + "headers": { + "Cache-Control": { + "schema": { + "type": "string" + } + }, + "Replay-Nonce": { + "schema": { + "type": "string" + } + } + } + } + }, + "summary": "Get a new nonce for a client CSR" + } + }, + "/clients/{client}/prekeys": { + "get": { + "description": " [internal route ID: \"get-client-prekeys\"]\n\n", + "operationId": "get-client-prekeys", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "items": { + "maximum": 65535, + "minimum": 0, + "type": "integer" + }, + "type": "array" + } + } + }, + "description": "" + } + }, + "summary": "List the remaining prekey IDs of a client" + } + }, + "/connections/{uid_domain}/{uid}": { + "get": { + "description": " [internal route ID: \"get-connection\"]\n\n", + "operationId": "get-connection", + "parameters": [ + { + "in": "path", + "name": "uid_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User Id", + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + } + } + }, + "description": "Connection found" + }, + "404": { + "description": "`uid_domain` or `uid` or Connection not found(**Note**: This error has an empty body for legacy reasons)" + } + }, + "summary": "Get an existing connection to another user (local or remote)" + }, + "post": { + "description": " [internal route ID: \"create-connection\"]\n\nYou can have no more than 1000 connections in accepted or sent state", + "operationId": "create-connection", + "parameters": [ + { + "in": "path", + "name": "uid_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User Id", + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + } + } + }, + "description": "Connection existed" + }, + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + } + } + }, + "description": "Connection was created" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-user", + "message": "Invalid user" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-user" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid user (label: `invalid-user`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-identity", + "message": "The user has no verified email" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-identity", + "connection-limit", + "missing-legalhold-consent", + "missing-legalhold-consent-old-clients" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The user has no verified email (label: `no-identity`)\n\nToo many sent/accepted connections (label: `connection-limit`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)" + } + }, + "summary": "Create a connection to another user" + }, + "put": { + "description": " [internal route ID: \"update-connection\"]\n\n", + "operationId": "update-connection", + "parameters": [ + { + "in": "path", + "name": "uid_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User Id", + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConnectionUpdate_LTU3MTA1OTA5" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserConnection_LTY3NzU1ODg0" + } + } + }, + "description": "Connection updated" + }, + "204": { + "description": "Connection unchanged" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-user", + "message": "Invalid user" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-user" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid user (label: `invalid-user`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-identity", + "message": "The user has no verified email" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-identity", + "bad-conn-update", + "not-connected", + "connection-limit", + "missing-legalhold-consent", + "missing-legalhold-consent-old-clients" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The user has no verified email (label: `no-identity`)\n\nInvalid status transition (label: `bad-conn-update`)\n\nUsers are not connected (label: `not-connected`)\n\nToo many sent/accepted connections (label: `connection-limit`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)" + } + }, + "summary": "Update a connection to another user" + } + }, + "/conversations": { + "post": { + "description": " [internal route ID: \"create-group-conversation\"]\n\nThis returns 201 when a new conversation is created, and 200 when the conversation already existed\nOAuth scope: `write:conversations`", + "operationId": "create-group-conversation", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewConv_LTgzNTk1NDQx" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGroupConversation_GroupConvType_MTQ3OTc4NDk3" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CreateGroupConversation_GroupConvType_MTQ3OTc4NDk3" + } + } + }, + "description": "Conversation created", + "headers": { + "Location": { + "description": "Conversation ID", + "schema": { + "format": "uuid", + "type": "string" + } + } + } + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "history-not-supported", + "message": "Shared history is not supported on this conversation" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "history-not-supported", + "mls-not-enabled", + "non-empty-member-list" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nShared history is not supported on this conversation (label: `history-not-supported`)\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)\n\nAttempting to add group members outside MLS (label: `non-empty-member-list`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "channels-not-enabled", + "message": "The channels feature is not enabled for this team" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "channels-not-enabled", + "not-mls-conversation", + "missing-legalhold-consent", + "operation-denied", + "no-team-member", + "not-connected", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The channels feature is not enabled for this team (label: `channels-not-enabled`)\n\nThis operation requires an MLS conversation (label: `not-mls-conversation`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nInsufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nUsers are not connected (label: `not-connected`)\n\nConversation access denied (label: `access-denied`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "non_federating_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "non_federating_backends" + ], + "type": "object" + } + } + }, + "description": "Adding members to the conversation is not possible because the backends involved do not form a fully connected graph" + }, + "533": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "unreachable_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "unreachable_backends" + ], + "type": "object" + } + } + }, + "description": "Some domains are unreachable" + } + }, + "summary": "Create a new conversation" + } + }, + "/conversations/code-check": { + "post": { + "description": " [internal route ID: \"code-check\"]\n\nIf the guest links team feature is disabled, this will fail with 404 CodeNotFound.Note that this is currently inconsistent (for backwards compatibility reasons) with `POST /conversations/join` which responds with 409 GuestLinksDisabled if guest links are disabled.", + "operationId": "code-check", + "parameters": [ + { + "in": "header", + "name": "X-Forwarded-For", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationCode_Mjg3OTI1NTMx" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Valid" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-conversation-password", + "message": "Invalid conversation password" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-conversation-password" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid conversation password (label: `invalid-conversation-password`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation", + "no-conversation-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation not found (label: `no-conversation`)\n\nConversation code not found (label: `no-conversation-code`)" + } + }, + "summary": "Check validity of a conversation code." + } + }, + "/conversations/join": { + "get": { + "description": " [internal route ID: \"get-conversation-by-reusable-code\"]\n\n", + "operationId": "get-conversation-by-reusable-code", + "parameters": [ + { + "in": "query", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "code", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationCoverView_LTMwNDkxMTA1" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "access-denied", + "invalid-conversation-password" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nConversation access denied (label: `access-denied`)\n\nInvalid conversation password (label: `invalid-conversation-password`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation", + "no-conversation-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation not found (label: `no-conversation`)\n\nConversation code not found (label: `no-conversation-code`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "guest-links-disabled", + "message": "The guest link feature is disabled and all guest links have been revoked" + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "guest-links-disabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The guest link feature is disabled and all guest links have been revoked (label: `guest-links-disabled`)" + } + }, + "summary": "Get limited conversation information by key/code pair" + }, + "post": { + "description": " [internal route ID: \"join-conversation-by-code-unqualified\"]\n\nIf the guest links team feature is disabled, this will fail with 409 GuestLinksDisabled.Note that this is currently inconsistent (for backwards compatibility reasons) with `POST /conversations/code-check` which responds with 404 CodeNotFound if guest links are disabled.", + "operationId": "join-conversation-by-code-unqualified", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/JoinConversationByCode_NjgzMzM4Mjg5" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "Conversation joined" + }, + "204": { + "description": "Conversation unchanged" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "too-many-members", + "message": "Maximum number of members per conversation reached" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "too-many-members", + "no-team-member", + "invalid-op", + "access-denied", + "invalid-conversation-password" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Maximum number of members per conversation reached (label: `too-many-members`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInvalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)\n\nInvalid conversation password (label: `invalid-conversation-password`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation", + "no-conversation-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation not found (label: `no-conversation`)\n\nConversation code not found (label: `no-conversation-code`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "guest-links-disabled", + "message": "The guest link feature is disabled and all guest links have been revoked" + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "guest-links-disabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The guest link feature is disabled and all guest links have been revoked (label: `guest-links-disabled`)" + } + }, + "summary": "Join a conversation using a reusable code" + } + }, + "/conversations/list": { + "post": { + "description": " [internal route ID: \"list-conversations\"]\n\n", + "operationId": "list-conversations", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ListConversations_MjkxMTIwODMz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationsResponse_GroupConvType_ODkxMjM2ODM0" + } + } + }, + "description": "" + } + }, + "summary": "Get conversation metadata for a list of conversation ids" + } + }, + "/conversations/list-ids": { + "post": { + "description": " [internal route ID: \"list-conversation-ids\"]\n\nThe IDs returned by this endpoint are paginated. To get the first page, make a call with the `paging_state` field set to `null` (or omitted). Whenever the `has_more` field of the response is set to `true`, more results are available, and they can be obtained by calling the endpoint again, but this time passing the value of `paging_state` returned by the previous call. One can continue in this fashion until all results are returned, which is indicated by `has_more` being `false`. Note that `paging_state` should be considered an opaque token. It should not be inspected, or stored, or reused across multiple unrelated invocations of the endpoint.", + "operationId": "list-conversation-ids", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/GetMuliTabPgRqs_ConvrIdLcOm10_ODU0NjQ1NDMz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MultiTabePg_ConvrsIdqf_cLORm_Q_Mzg0MjYzNzM0" + } + } + }, + "description": "" + } + }, + "summary": "Get all conversation IDs." + } + }, + "/conversations/mls-self": { + "get": { + "description": " [internal route ID: \"get-mls-self-conversation\"]\n\n", + "operationId": "get-mls-self-conversation", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/v9_OwnConversation_GroupConvType_LTU2MzYxNTg0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/v9_OwnConversation_GroupConvType_LTU2MzYxNTg0" + } + } + }, + "description": "The MLS self-conversation" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-not-enabled", + "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-not-enabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" + } + }, + "summary": "Get the user's MLS self-conversation" + } + }, + "/conversations/self": { + "post": { + "description": " [internal route ID: \"create-self-conversation\"]\n\n", + "operationId": "create-self-conversation", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/v6_OwnConversation_GroupConvType_LTU2MzYxNTg0V6" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/v6_OwnConversation_GroupConvType_LTU2MzYxNTg0V6" + } + } + }, + "description": "Conversation existed", + "headers": { + "Location": { + "description": "Conversation ID", + "schema": { + "format": "uuid", + "type": "string" + } + } + } + }, + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/v6_OwnConversation_GroupConvType_LTU2MzYxNTg0V6" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/v6_OwnConversation_GroupConvType_LTU2MzYxNTg0V6" + } + } + }, + "description": "Conversation created", + "headers": { + "Location": { + "description": "Conversation ID", + "schema": { + "format": "uuid", + "type": "string" + } + } + } + } + }, + "summary": "Create a self-conversation" + } + }, + "/conversations/{cnv_domain}/{cnv}": { + "get": { + "description": " [internal route ID: \"get-conversation\"]\n\n", + "operationId": "get-conversation", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Conversation_GroupConvType_MzQzMTQ1OTg3" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Conversation access denied" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation access denied (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Get a conversation by ID" + } + }, + "/conversations/{cnv_domain}/{cnv}/access": { + "put": { + "description": " [internal route ID: \"update-conversation-access\"]\n\n", + "operationId": "update-conversation-access", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationAccessData_MjMxMTI5ODc3" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "Access updated" + }, + "204": { + "description": "Access unchanged" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-op", + "message": "Invalid target access" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-op", + "access-denied", + "action-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid target access (label: `invalid-op`)\n\nInvalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)\n\nInsufficient authorization (missing modify_conversation_access) (label: `action-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Update access modes for a conversation" + } + }, + "/conversations/{cnv_domain}/{cnv}/add-permission": { + "put": { + "description": " [internal route ID: \"update-channel-add-permission\"]\n\n", + "operationId": "update-channel-add-permission", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/AddPermissionUpdate_LTU3MzEwOTY4" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "Add permissions updated" + }, + "204": { + "description": "Add permissions unchanged" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-op", + "message": "Invalid target access" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-op", + "not-connected", + "operation-denied", + "no-team-member", + "access-denied", + "action-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid target access (label: `invalid-op`)\n\nUsers are not connected (label: `not-connected`)\n\nInsufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nConversation access denied (label: `access-denied`)\n\nInvalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing modify_add_permissions) (label: `action-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team", + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` not found\n\nTeam not found (label: `no-team`)\n\nConversation not found (label: `no-conversation`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "non_federating_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "non_federating_backends" + ], + "type": "object" + } + } + }, + "description": "Adding members to the conversation is not possible because the backends involved do not form a fully connected graph" + }, + "533": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "unreachable_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "unreachable_backends" + ], + "type": "object" + } + } + }, + "description": "Some domains are unreachable" + } + }, + "summary": "Update the permissions for adding members to a channel" + } + }, + "/conversations/{cnv_domain}/{cnv}/groupinfo": { + "get": { + "description": " [internal route ID: \"get-group-info\"]\n\n", + "operationId": "get-group-info", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "message/mls": { + "schema": { + "$ref": "#/components/schemas/GroupInfoData" + } + } + }, + "description": "The group information" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-not-enabled", + "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-not-enabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "mls-missing-group-info", + "message": "The conversation has no group information" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-missing-group-info", + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` not found\n\nThe conversation has no group information (label: `mls-missing-group-info`)\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Get MLS group information" + } + }, + "/conversations/{cnv_domain}/{cnv}/history": { + "put": { + "description": " [internal route ID: \"update-conversation-history\"]\n\n", + "operationId": "update-conversation-history", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationHistoryUpdate_LTg5MDQ5Nzgx" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "History updated" + }, + "204": { + "description": "History unchanged" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "history-not-supported", + "message": "Shared history is not supported on this conversation" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "history-not-supported" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nShared history is not supported on this conversation (label: `history-not-supported`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "action-denied", + "message": "Insufficient authorization (missing modify_conversation_access)" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "action-denied", + "invalid-op", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Insufficient authorization (missing modify_conversation_access) (label: `action-denied`)\n\nInvalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Update history settings of a conversation" + } + }, + "/conversations/{cnv_domain}/{cnv}/members": { + "post": { + "description": " [internal route ID: \"add-members-to-conversation\"]\n\n", + "operationId": "add-members-to-conversation", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/InviteQualified_ODYyODIyNjYz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "Conversation updated" + }, + "204": { + "description": "Conversation unchanged" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-group-id-not-supported", + "message": "The group ID version of the conversation is not supported by one of the federated backends" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-group-id-not-supported" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nThe group ID version of the conversation is not supported by one of the federated backends (label: `mls-group-id-not-supported`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "missing-legalhold-consent", + "message": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "missing-legalhold-consent", + "not-connected", + "no-team-member", + "access-denied", + "too-many-members", + "invalid-op", + "action-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nUsers are not connected (label: `not-connected`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nConversation access denied (label: `access-denied`)\n\nMaximum number of members per conversation reached (label: `too-many-members`)\n\nInvalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing leave_conversation) (label: `action-denied`)\n\nInsufficient authorization (missing add_conversation_member) (label: `action-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "non_federating_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "non_federating_backends" + ], + "type": "object" + } + } + }, + "description": "Adding members to the conversation is not possible because the backends involved do not form a fully connected graph" + }, + "533": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "unreachable_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "unreachable_backends" + ], + "type": "object" + } + } + }, + "description": "Some domains are unreachable" + } + }, + "summary": "Add qualified members to an existing conversation." + }, + "put": { + "description": " [internal route ID: \"replace-members-in-conversation\"]\n\nThis will add any members not already in the conversation, and remove any members not in the provided list except users that are associated via a user group. The given role in the request body will be applied to all added members. The roles of already existing members will not be changed even if these members are included in the request body and their role differs from the role provided in this request.", + "operationId": "replace-members-in-conversation", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/InviteQualified_ODYyODIyNjYz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Conversation members replaced" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-group-id-not-supported", + "message": "The group ID version of the conversation is not supported by one of the federated backends" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-group-id-not-supported" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nThe group ID version of the conversation is not supported by one of the federated backends (label: `mls-group-id-not-supported`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "missing-legalhold-consent", + "message": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "missing-legalhold-consent", + "not-connected", + "no-team-member", + "access-denied", + "too-many-members", + "invalid-op", + "action-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nUsers are not connected (label: `not-connected`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nConversation access denied (label: `access-denied`)\n\nMaximum number of members per conversation reached (label: `too-many-members`)\n\nInvalid operation (label: `invalid-op`)\n\nThe conversation would be left without an admin\n\nInsufficient authorization (missing leave_conversation) (label: `action-denied`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)\n\nInsufficient authorization (missing add_conversation_member) (label: `action-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "non_federating_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "non_federating_backends" + ], + "type": "object" + } + } + }, + "description": "Adding members to the conversation is not possible because the backends involved do not form a fully connected graph" + }, + "533": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "unreachable_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "unreachable_backends" + ], + "type": "object" + } + } + }, + "description": "Some domains are unreachable" + } + }, + "summary": "Replace the members of a conversation." + } + }, + "/conversations/{cnv_domain}/{cnv}/members/{usr_domain}/{usr}": { + "delete": { + "description": " [internal route ID: \"remove-member\"]\n\n", + "operationId": "remove-member", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "usr_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Target User ID", + "in": "path", + "name": "usr", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "Member removed" + }, + "204": { + "description": "No change" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "eligible_members": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "type": "array" + } + }, + "required": [ + "eligible_members" + ], + "type": "object" + } + } + }, + "description": "The conversation would be left without an admin\n\nInvalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` or `usr_domain` or `usr` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Remove a member from a conversation" + }, + "put": { + "description": " [internal route ID: \"update-other-member\"]\n\n**Note**: at least one field has to be provided.", + "operationId": "update-other-member", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "usr_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Target User ID", + "in": "path", + "name": "usr", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/OtherMemberUpdate_LTM1MjYzOTU0" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Membership updated" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-op", + "message": "Invalid operation" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-op", + "action-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid operation (label: `invalid-op`)\n\nInvalid target (label: `invalid-op`)\n\nInsufficient authorization (missing modify_other_conversation_member) (label: `action-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation-member", + "message": "Conversation member not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation-member", + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` or `usr_domain` or `usr` not found\n\nConversation member not found (label: `no-conversation-member`)\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Update membership of the specified user" + } + }, + "/conversations/{cnv_domain}/{cnv}/message-timer": { + "put": { + "description": " [internal route ID: \"update-conversation-message-timer\"]\n\n", + "operationId": "update-conversation-message-timer", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationMessageTimerUpdate_LTcxMjUwNzQ4" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "Message timer updated" + }, + "204": { + "description": "Message timer unchanged" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-op", + "message": "Invalid operation" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-op", + "access-denied", + "action-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)\n\nInsufficient authorization (missing modify_conversation_message_timer) (label: `action-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Update the message timer for a conversation" + } + }, + "/conversations/{cnv_domain}/{cnv}/name": { + "put": { + "description": " [internal route ID: \"update-conversation-name\"]\n\n\nOAuth scope: `write:conversations_name`", + "operationId": "update-conversation-name", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationRename_ODkwODg1MzQ0" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "Name unchanged" + }, + "204": { + "description": "Name updated" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-op", + "message": "Invalid operation" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-op", + "action-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing modify_conversation_name) (label: `action-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Update conversation name" + } + }, + "/conversations/{cnv_domain}/{cnv}/proteus/messages": { + "post": { + "description": " [internal route ID: \"post-proteus-message\"]\n\nThis endpoint ensures that the list of clients is correct and only sends the message if the list is correct.\nTo override this, the endpoint accepts `client_mismatch_strategy` in the body. It can have these values:\n- `report_all`: When set, the message is not sent if any clients are missing. The missing clients are reported in the response.\n- `ignore_all`: When set, no checks about missing clients are carried out.\n- `report_only`: Takes a list of qualified UserIDs. If any clients of the listed users are missing, the message is not sent. The missing clients are reported in the response.\n- `ignore_only`: Takes a list of qualified UserIDs. If any clients of the non-listed users are missing, the message is not sent. The missing clients are reported in the response.\n\nThe sending of messages in a federated conversation could theoretically fail partially. To make this case unlikely, the backend first gets a list of clients from all the involved backends and then tries to send a message. So, if any backend is down, the message is not propagated to anyone. But the actual message fan out to multiple backends could still fail partially. This type of failure is reported as a 201, the clients for which the message sending failed are part of the response body.\n\nThis endpoint can lead to OtrMessageAdd event being sent to the recipients.\n\n**NOTE:** The protobuf definitions of the request body can be found at https://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto.", + "operationId": "post-proteus-message", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/x-protobuf": { + "schema": { + "$ref": "#/components/schemas/QualifiedNewOtrMessage" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageSendingStatus_ODg0NDgyNDk4" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MessageSendingStatus_ODg0NDgyNDk4" + } + } + }, + "description": "Message sent" + }, + "403": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unknown Client (label: `unknown-client`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` or Conversation not found (label: `no-conversation`)" + }, + "412": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageSendingStatus_ODg0NDgyNDk4" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MessageSendingStatus_ODg0NDgyNDk4" + } + } + }, + "description": "Missing clients" + } + }, + "summary": "Post an encrypted message to a conversation (accepts only Protobuf)" + } + }, + "/conversations/{cnv_domain}/{cnv}/protocol": { + "put": { + "description": " [internal route ID: \"update-conversation-protocol\"]\n\n**Note**: Only proteus->mixed upgrade is supported.", + "operationId": "update-conversation-protocol", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ProtocolUpdate_NzY1ODgxNDQy" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "Conversation updated" + }, + "204": { + "description": "Conversation unchanged" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-migration-criteria-not-satisfied", + "message": "The migration criteria for mixed to MLS protocol transition are not satisfied for this conversation" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-migration-criteria-not-satisfied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nThe migration criteria for mixed to MLS protocol transition are not satisfied for this conversation (label: `mls-migration-criteria-not-satisfied`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "operation-denied", + "message": "Insufficient permissions" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "operation-denied", + "no-team-member", + "invalid-op", + "action-denied", + "invalid-protocol-transition" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInvalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing leave_conversation) (label: `action-denied`)\n\nProtocol transition is invalid (label: `invalid-protocol-transition`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team", + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` not found\n\nTeam not found (label: `no-team`)\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Update the protocol of the conversation" + } + }, + "/conversations/{cnv_domain}/{cnv}/receipt-mode": { + "put": { + "description": " [internal route ID: \"update-conversation-receipt-mode\"]\n\n", + "operationId": "update-conversation-receipt-mode", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationReceiptModeUpdate_NDE4MzUzNTU3" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "Receipt mode updated" + }, + "204": { + "description": "Receipt mode unchanged" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "mls-receipts-not-allowed", + "message": "Read receipts on MLS conversations are not allowed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-receipts-not-allowed", + "invalid-op", + "access-denied", + "action-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Read receipts on MLS conversations are not allowed (label: `mls-receipts-not-allowed`)\n\nInvalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)\n\nInsufficient authorization (missing modify_conversation_receipt_mode) (label: `action-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Update receipt mode for a conversation" + } + }, + "/conversations/{cnv_domain}/{cnv}/self": { + "get": { + "description": " [internal route ID: \"get-conversation-self\"]\n\n", + "operationId": "get-conversation-self", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Member_OTA5OTgyNzcw" + } + } + }, + "description": "" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Get self membership properties" + }, + "put": { + "description": " [internal route ID: \"update-conversation-self\"]\n\n**Note**: at least one field has to be provided.", + "operationId": "update-conversation-self", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MemberUpdate_LTg4NTQ0OTYz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Update successful" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Update self membership properties" + } + }, + "/conversations/{cnv_domain}/{cnv}/subconversations/{subconv}": { + "delete": { + "description": " [internal route ID: \"delete-subconversation\"]\n\n", + "operationId": "delete-subconversation", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "subconv", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MLSReset_NzgwODA3ODc4" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + } + }, + "description": "Deletion successful" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-not-enabled", + "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-not-enabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Conversation access denied" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation access denied (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` or `subconv` not found\n\nConversation not found (label: `no-conversation`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "mls-stale-message", + "message": "The conversation epoch in a message is too old" + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-stale-message" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The conversation epoch in a message is too old (label: `mls-stale-message`)" + } + }, + "summary": "Delete an MLS subconversation" + }, + "get": { + "description": " [internal route ID: \"get-subconversation\"]\n\n", + "operationId": "get-subconversation", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "subconv", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicSubConversation_MjI2NTIxMzU4" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PublicSubConversation_MjI2NTIxMzU4" + } + } + }, + "description": "Subconversation" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "mls-subconv-unsupported-convtype", + "message": "MLS subconversations are only supported for regular conversations" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-subconv-unsupported-convtype", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "MLS subconversations are only supported for regular conversations (label: `mls-subconv-unsupported-convtype`)\n\nConversation access denied (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` or `subconv` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Get information about an MLS subconversation" + } + }, + "/conversations/{cnv_domain}/{cnv}/subconversations/{subconv}/groupinfo": { + "get": { + "description": " [internal route ID: \"get-subconversation-group-info\"]\n\n", + "operationId": "get-subconversation-group-info", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "subconv", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "message/mls": { + "schema": { + "$ref": "#/components/schemas/GroupInfoData" + } + } + }, + "description": "The group information" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-not-enabled", + "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-not-enabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "mls-missing-group-info", + "message": "The conversation has no group information" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-missing-group-info", + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` or `subconv` not found\n\nThe conversation has no group information (label: `mls-missing-group-info`)\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Get MLS group information of subconversation" + } + }, + "/conversations/{cnv_domain}/{cnv}/subconversations/{subconv}/self": { + "delete": { + "description": " [internal route ID: \"leave-subconversation\"]\n\n", + "operationId": "leave-subconversation", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "subconv", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-not-enabled", + "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-not-enabled", + "mls-protocol-error" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)\n\nMLS protocol error (label: `mls-protocol-error`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Conversation access denied" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation access denied (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` or `subconv` not found\n\nConversation not found (label: `no-conversation`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "mls-stale-message", + "message": "The conversation epoch in a message is too old" + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-stale-message" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The conversation epoch in a message is too old (label: `mls-stale-message`)" + } + }, + "summary": "Leave an MLS subconversation" + } + }, + "/conversations/{cnv_domain}/{cnv}/typing": { + "post": { + "description": " [internal route ID: \"member-typing-qualified\"]\n\n", + "operationId": "member-typing-qualified", + "parameters": [ + { + "in": "path", + "name": "cnv_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/TypingStatus_LTg5MzcyNDMy" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Notification sent" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv_domain` or `cnv` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Sending typing notifications" + } + }, + "/conversations/{cnv}/code": { + "delete": { + "description": " [internal route ID: \"remove-code-unqualified\"]\n\n", + "operationId": "remove-code-unqualified", + "parameters": [ + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "Conversation code deleted." + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Conversation access denied" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation access denied (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Delete conversation code" + }, + "get": { + "description": " [internal route ID: \"get-code\"]\n\n\nOAuth scope: `write:conversations_code`", + "operationId": "get-code", + "parameters": [ + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConversationCodeInfo_LTc5MzgzNjg3" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationCodeInfo_LTc5MzgzNjg3" + } + } + }, + "description": "Conversation Code" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Conversation access denied" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation access denied (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation", + "no-conversation-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)\n\nConversation code not found (label: `no-conversation-code`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "guest-links-disabled", + "message": "The guest link feature is disabled and all guest links have been revoked" + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "guest-links-disabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The guest link feature is disabled and all guest links have been revoked (label: `guest-links-disabled`)" + } + }, + "summary": "Get existing conversation code" + }, + "post": { + "description": " [internal route ID: \"create-conversation-code-unqualified\"]\n\n\nOAuth scope: `write:conversations_code`", + "operationId": "create-conversation-code-unqualified", + "parameters": [ + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CreateConversationCodeRequest_NTYzMTA1NDYz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConversationCodeInfo_LTc5MzgzNjg3" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationCodeInfo_LTc5MzgzNjg3" + } + } + }, + "description": "Conversation code already exists." + }, + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Event_LTMwMTMyODM5" + } + } + }, + "description": "Conversation code created." + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Conversation access denied" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation access denied (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "create-conv-code-conflict", + "message": "Conversation code already exists with a different password setting than the requested one." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "create-conv-code-conflict", + "guest-links-disabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation code already exists with a different password setting than the requested one. (label: `create-conv-code-conflict`)\n\nThe guest link feature is disabled and all guest links have been revoked (label: `guest-links-disabled`)" + } + }, + "summary": "Create or recreate a conversation code" + } + }, + "/conversations/{cnv}/features/conversationGuestLinks": { + "get": { + "description": " [internal route ID: \"get-conversation-guest-links-status\"]\n\n", + "operationId": "get-conversation-guest-links-status", + "parameters": [ + { + "description": "Conversation ID", + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_GuestLinksConfig_LTcwNjU0NDMw" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Conversation access denied" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation access denied (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Get the status of the guest links feature for a conversation that potentially has been created by someone from another team." + } + }, + "/conversations/{cnv}/otr/messages": { + "post": { + "description": " [internal route ID: \"post-otr-message-unqualified\"]\n\nThis endpoint ensures that the list of clients is correct and only sends the message if the list is correct.\nTo override this, the endpoint accepts two query params:\n- `ignore_missing`: Can be 'true' 'false' or a comma separated list of user IDs.\n - When 'true' all missing clients are ignored.\n - When 'false' all missing clients are reported.\n - When comma separated list of user-ids, only clients for listed users are ignored.\n- `report_missing`: Can be 'true' 'false' or a comma separated list of user IDs.\n - When 'true' all missing clients are reported.\n - When 'false' all missing clients are ignored.\n - When comma separated list of user-ids, only clients for listed users are reported.\n\nApart from these, the request body also accepts `report_missing` which can only be a list of user ids and behaves the same way as the query parameter.\n\nAll three of these should be considered mutually exclusive. The server however does not error if more than one is specified, it reads them in this order of precedence:\n- `report_missing` in the request body has highest precedence.\n- `ignore_missing` in the query param is the next.\n- `report_missing` in the query param has the lowest precedence.\n\nThis endpoint can lead to OtrMessageAdd event being sent to the recipients.\n\n**NOTE:** The protobuf definitions of the request body can be found at https://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto.", + "operationId": "post-otr-message-unqualified", + "parameters": [ + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "query", + "name": "ignore_missing", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "report_missing", + "required": false, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewOtrMessage_LTUyMTE5MTMw" + } + }, + "application/x-protobuf": { + "schema": { + "$ref": "#/components/schemas/NewOtrMessage_LTUyMTE5MTMw" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + } + }, + "description": "Message sent" + }, + "403": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "unknown-client", + "message": "Unknown Client" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unknown-client", + "missing-legalhold-consent-old-clients", + "missing-legalhold-consent" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unknown Client (label: `unknown-client`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has old clients that do not support legalhold's UI requirements (label: `missing-legalhold-consent-old-clients`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv` or Conversation not found (label: `no-conversation`)" + }, + "412": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ClientMismatch_ODUyODM0MDQ0" + } + } + }, + "description": "Missing clients" + } + }, + "summary": "Post an encrypted message to a conversation (accepts JSON or Protobuf)" + } + }, + "/conversations/{cnv}/roles": { + "get": { + "description": " [internal route ID: \"get-conversation-roles\"]\n\n", + "operationId": "get-conversation-roles", + "parameters": [ + { + "in": "path", + "name": "cnv", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationRolesList" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Conversation access denied" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation access denied (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`cnv` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Get existing roles available for the given conversation" + } + }, + "/cookies": { + "get": { + "description": " [internal route ID: \"list-cookies\"]\n\n", + "operationId": "list-cookies", + "parameters": [ + { + "description": "Filter by label (comma-separated list)", + "in": "query", + "name": "labels", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CookieList_LTM4MzYwNzAz" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CookieList_LTM4MzYwNzAz" + } + } + }, + "description": "List of cookies" + } + }, + "summary": "Retrieve the list of cookies currently stored for the user" + } + }, + "/cookies/remove": { + "post": { + "description": " [internal route ID: \"remove-cookies\"]\n\n", + "operationId": "remove-cookies", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/RemoveCookies_OTYwMTI0NDMy" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Cookies revoked" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Authentication failed (label: `invalid-credentials`)" + } + }, + "summary": "Revoke stored cookies" + } + }, + "/custom-backend/by-domain/{domain}": { + "get": { + "description": " [internal route ID: \"get-custom-backend-by-domain\"]\n\n", + "operationId": "get-custom-backend-by-domain", + "parameters": [ + { + "description": "URL-encoded email domain", + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CustomBackend_LTQxODI0MjQ0" + } + } + }, + "description": "" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "custom-backend-not-found", + "message": "Custom backend not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "custom-backend-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`domain` not found\n\nCustom backend not found (label: `custom-backend-not-found`)" + } + }, + "summary": "Shows information about custom backends related to a given email domain" + } + }, + "/delete": { + "post": { + "description": " [internal route ID: \"verify-delete\"]\n\n", + "operationId": "verify-delete", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/VerifyDeleteUser_Njc1NDQ1MDIy" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Deletion is initiated." + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-code", + "message": "Invalid verification code" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid verification code (label: `invalid-code`)" + } + }, + "summary": "Verify account deletion with a code." + } + }, + "/domain-verification/{domain}/authorize-team": { + "post": { + "description": " [internal route ID: \"domain-verification-authorize-team\"]\n\n", + "operationId": "domain-verification-authorize-team", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DomainOwnershipToken_NTU0ODc1NDE5" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Authorized" + }, + "401": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 401, + "label": "domain-registration-update-auth-failure", + "message": "Domain registration updated auth failure" + }, + "properties": { + "code": { + "enum": [ + 401 + ], + "type": "integer" + }, + "label": { + "enum": [ + "domain-registration-update-auth-failure" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Domain registration updated auth failure (label: `domain-registration-update-auth-failure`)" + }, + "402": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 402, + "label": "domain-registration-update-payment-required", + "message": "Domain registration updated payment required" + }, + "properties": { + "code": { + "enum": [ + 402 + ], + "type": "integer" + }, + "label": { + "enum": [ + "domain-registration-update-payment-required" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Domain registration updated payment required (label: `domain-registration-update-payment-required`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "operation-forbidden-for-domain-registration-state", + "message": "Invalid domain registration state update" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "operation-forbidden-for-domain-registration-state" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid domain registration state update (label: `operation-forbidden-for-domain-registration-state`)" + } + }, + "summary": "Authorize a team to operate on a verified domain" + } + }, + "/domain-verification/{domain}/backend": { + "post": { + "description": " [internal route ID: \"update-domain-redirect\"]\n\n", + "operationId": "update-domain-redirect", + "parameters": [ + { + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DomainRedirectConfig_NTI5NDE5MDQy" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Updated" + }, + "401": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 401, + "label": "domain-registration-update-auth-failure", + "message": "Domain registration updated auth failure" + }, + "properties": { + "code": { + "enum": [ + 401 + ], + "type": "integer" + }, + "label": { + "enum": [ + "domain-registration-update-auth-failure" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Domain registration updated auth failure (label: `domain-registration-update-auth-failure`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "operation-forbidden-for-domain-registration-state", + "message": "Invalid domain registration state update" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "operation-forbidden-for-domain-registration-state" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid domain registration state update (label: `operation-forbidden-for-domain-registration-state`)" + } + }, + "summary": "Update the domain redirect configuration" + } + }, + "/domain-verification/{domain}/challenges": { + "post": { + "description": " [internal route ID: \"domain-verification-challenge\"]\n\n", + "operationId": "domain-verification-challenge", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DomainVerificationChallenge_NjIwMzA1MjE5" + } + } + }, + "description": "" + } + }, + "summary": "Get a DNS verification challenge" + } + }, + "/domain-verification/{domain}/challenges/{challengeId}": { + "post": { + "description": " [internal route ID: \"verify-challenge\"]\n\n", + "operationId": "verify-challenge", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "challengeId", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ChallengeToken_Mzk3NTcwOTM3" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DomainOwnershipToken_NTU0ODc1NDE5" + } + } + }, + "description": "" + }, + "401": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 401, + "label": "domain-registration-update-auth-failure", + "message": "Domain registration updated auth failure" + }, + "properties": { + "code": { + "enum": [ + 401 + ], + "type": "integer" + }, + "label": { + "enum": [ + "domain-registration-update-auth-failure" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Domain registration updated auth failure (label: `domain-registration-update-auth-failure`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "domain-verification-failed", + "message": "Domain verification failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "domain-verification-failed" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Domain verification failed (label: `domain-verification-failed`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "challenge-not-found", + "message": "Challenge not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "challenge-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`domain` or `challengeId` not found\n\nChallenge not found (label: `challenge-not-found`)" + } + }, + "summary": "Verify a DNS verification challenge" + } + }, + "/domain-verification/{domain}/team": { + "post": { + "description": " [internal route ID: \"update-team-invite\"]\n\n", + "operationId": "update-team-invite", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/TeamInviteConfig_MTg4Nzk4NzMz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Updated" + }, + "402": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 402, + "label": "domain-registration-update-payment-required", + "message": "Domain registration updated payment required" + }, + "properties": { + "code": { + "enum": [ + 402 + ], + "type": "integer" + }, + "label": { + "enum": [ + "domain-registration-update-payment-required" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Domain registration updated payment required (label: `domain-registration-update-payment-required`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "operation-forbidden-for-domain-registration-state", + "message": "Invalid domain registration state update" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "operation-forbidden-for-domain-registration-state" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid domain registration state update (label: `operation-forbidden-for-domain-registration-state`)" + } + }, + "summary": "Update the team-invite configuration" + } + }, + "/domain-verification/{domain}/team/challenges/{challengeId}": { + "post": { + "description": " [internal route ID: \"verify-challenge-team\"]\n\n", + "operationId": "verify-challenge-team", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "challengeId", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ChallengeToken_Mzk3NTcwOTM3" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DomainOwnershipToken_NTU0ODc1NDE5" + } + } + }, + "description": "" + }, + "401": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 401, + "label": "domain-registration-update-auth-failure", + "message": "Domain registration updated auth failure" + }, + "properties": { + "code": { + "enum": [ + 401 + ], + "type": "integer" + }, + "label": { + "enum": [ + "domain-registration-update-auth-failure" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Domain registration updated auth failure (label: `domain-registration-update-auth-failure`)" + }, + "402": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 402, + "label": "domain-registration-update-payment-required", + "message": "Domain registration updated payment required" + }, + "properties": { + "code": { + "enum": [ + 402 + ], + "type": "integer" + }, + "label": { + "enum": [ + "domain-registration-update-payment-required" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Domain registration updated payment required (label: `domain-registration-update-payment-required`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "operation-forbidden-for-domain-registration-state", + "message": "Invalid domain registration state update" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "operation-forbidden-for-domain-registration-state" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid domain registration state update (label: `operation-forbidden-for-domain-registration-state`)" + } + }, + "summary": "Verify a DNS verification challenge for a team" + } + }, + "/events": { + "get": { + "description": " [internal route ID: \"consume-events\"]\n\nThis is the rabbitMQ-based variant of \"await-notifications\"", + "externalDocs": { + "description": "RFC 6455", + "url": "https://datatracker.ietf.org/doc/html/rfc6455" + }, + "operationId": "consume-events", + "parameters": [ + { + "description": "Client ID", + "in": "query", + "name": "client", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Synchronization marker ID", + "in": "query", + "name": "sync_marker", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "101": { + "description": "Connection upgraded." + }, + "426": { + "description": "Upgrade required." + } + }, + "summary": "Consume events over a websocket connection" + } + }, + "/feature-configs": { + "get": { + "description": " [internal route ID: \"get-all-feature-configs-for-user\"]\n\nGets feature configs for a user. If the user is a member of a team and has the required permissions, this will return the team's feature configs.If the user is not a member of a team, this will return the personal feature configs (the server defaults).\nOAuth scope: `read:feature_configs`", + "operationId": "get-all-feature-configs-for-user", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NP_LockableFtur_ghdCnfiSOVsyAvIRqExmDpB_MGwUT2Q_LTM1Mzc0ODgy" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "operation-denied", + "message": "Insufficient permissions" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "operation-denied", + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Team not found (label: `no-team`)" + } + }, + "summary": "Gets feature configs for a user" + } + }, + "/get-domain-registration": { + "post": { + "description": " [internal route ID: \"get-domain-registration\"]\n\n- `due_to_existing_account`: boolean (optional, only present if `domain_redirect` is `no-registration`)\n- `backend`: object (optional, must be present if `domain_redirect` is `backend`)\n - `config_url`: string (required)\n - `webapp_url`: string (optional)\n- `sso_code`: string (optional, must be present if `domain_redirect` is `sso`)", + "operationId": "get-domain-registration", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/GetDomainRegistrationRequest_LTg4NTM1MzM2" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DomainRedirectResponse_V10_LTEyMjI4NTM0" + } + } + }, + "description": "" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-domain", + "message": "Invalid domain" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-domain" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid domain (label: `invalid-domain`)" + } + }, + "summary": "Get domain registration configuration by email" + } + }, + "/handles": { + "post": { + "description": " [internal route ID: \"check-user-handles\"]\n\n", + "operationId": "check-user-handles", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CheckHandles_LTc0OTkxMzAx" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/Handle" + }, + "type": "array" + } + }, + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/Handle" + }, + "type": "array" + } + } + }, + "description": "List of free handles" + } + }, + "summary": "Check availability of user handles" + } + }, + "/handles/{handle}": { + "head": { + "description": " [internal route ID: \"check-user-handle\"]\n\n", + "operationId": "check-user-handle", + "parameters": [ + { + "in": "path", + "name": "handle", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + } + }, + "description": "Handle is taken" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-handle", + "message": "The given handle is invalid (less than 2 or more than 256 characters; chars not in \"a-z0-9_.-\"; or on the blocklist)" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-handle" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The given handle is invalid (less than 2 or more than 256 characters; chars not in \"a-z0-9_.-\"; or on the blocklist) (label: `invalid-handle`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Handle not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`handle` not found\n\nHandle not found (label: `not-found`)" + } + }, + "summary": "Check whether a user handle can be taken" + } + }, + "/identity-providers": { + "get": { + "description": " [internal route ID: \"idp-get-all\"]\n\n", + "operationId": "idp-get-all", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/IdPList" + } + } + }, + "description": "" + } + } + }, + "post": { + "description": " [internal route ID: \"idp-create\"]\n\nCreate a new identity provider.\n\nThe `api_version` parameter controls the uniqueness constraint for IdP issuers:\n- `v1`: IdP issuers must be globally unique across the entire backend (all teams)\n- `v2` (default): IdP issuers must be unique per team (can be reused across different teams)\n\nThese constraints apply to both, multi-ingress and standard backends.", + "operationId": "idp-create", + "parameters": [ + { + "in": "query", + "name": "replaces", + "required": false, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "query", + "name": "api_version", + "required": false, + "schema": { + "default": "v2", + "enum": [ + "v1", + "v2" + ], + "type": "string" + } + }, + { + "in": "query", + "name": "handle", + "required": false, + "schema": { + "maxLength": 32, + "minLength": 1, + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/IdPMetadataInfo" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/IdPMetadataInfo" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/IdPConfig_WireIdP_NDA5MTE4Mjk0" + } + } + }, + "description": "" + } + } + } + }, + "/identity-providers/{id}": { + "delete": { + "description": " [internal route ID: \"idp-delete\"]\n\n", + "operationId": "idp-delete", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "query", + "name": "purge", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "204": { + "description": "" + } + } + }, + "get": { + "description": " [internal route ID: \"idp-get\"]\n\n", + "operationId": "idp-get", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/IdPConfig_WireIdP_NDA5MTE4Mjk0" + } + } + }, + "description": "" + } + } + }, + "put": { + "description": " [internal route ID: \"idp-update\"]\n\n", + "operationId": "idp-update", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "query", + "name": "handle", + "required": false, + "schema": { + "maxLength": 32, + "minLength": 1, + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/IdPMetadataInfo" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/IdPMetadataInfo" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/IdPConfig_WireIdP_NDA5MTE4Mjk0" + } + } + }, + "description": "" + } + } + } + }, + "/identity-providers/{id}/raw": { + "get": { + "description": " [internal route ID: \"idp-get-raw\"]\n\n", + "operationId": "idp-get-raw", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/xml": { + "schema": { + "type": "string" + } + } + }, + "description": "" + } + } + } + }, + "/list-connections": { + "post": { + "description": " [internal route ID: \"list-connections\"]\n\nThe IDs returned by this endpoint are paginated. To get the first page, make a call with the `paging_state` field set to `null` (or omitted). Whenever the `has_more` field of the response is set to `true`, more results are available, and they can be obtained by calling the endpoint again, but this time passing the value of `paging_state` returned by the previous call. One can continue in this fashion until all results are returned, which is indicated by `has_more` being `false`. Note that `paging_state` should be considered an opaque token. It should not be inspected, or stored, or reused across multiple unrelated invocations of the endpoint.", + "operationId": "list-connections", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/GetMuliTabPgRqs_ConcLOrm501_LTIwMjA4NzYw" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MultiTabePg_ConcsLOrRmU_MTgwMzU4OTU5" + } + } + }, + "description": "" + } + }, + "summary": "List the connections to other users, including remote users" + } + }, + "/list-users": { + "post": { + "description": " [internal route ID: \"list-users-by-ids-or-handles\"]\n\nThe 'qualified_ids' and 'qualified_handles' parameters are mutually exclusive.", + "operationId": "list-users-by-ids-or-handles", + "parameters": [ + { + "description": "Include whether each local user can currently be contacted", + "in": "query", + "name": "include-contact-status", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ListUsersQuery" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ListUsersById_LTQ5MTE3NDc0" + } + } + }, + "description": "" + } + }, + "summary": "List users" + } + }, + "/login": { + "post": { + "description": " [internal route ID: \"login\"]\n\nLogins are throttled at the server's discretion", + "operationId": "login", + "parameters": [ + { + "description": "Request a persistent cookie instead of a session cookie", + "in": "query", + "name": "persist", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Login_LTgyNTIzMTM1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccessToken_ODIyMTczMjMw" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/AccessToken_ODIyMTczMjMw" + } + } + }, + "description": "OK", + "headers": { + "Set-Cookie": { + "schema": { + "type": "string" + } + } + } + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "code-authentication-required", + "message": "Code authentication is required" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "code-authentication-required", + "code-authentication-failed", + "pending-activation", + "suspended", + "invalid-credentials" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Code authentication is required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nAccount pending activation (label: `pending-activation`)\n\nAccount suspended (label: `suspended`)\n\nAuthentication failed (label: `invalid-credentials`)" + } + }, + "summary": "Authenticate a user to obtain a cookie and first access token" + } + }, + "/meetings": { + "post": { + "description": " [internal route ID: \"create-meeting\"]\n\n\nOAuth scope: `write:meetings`", + "operationId": "create-meeting", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewMeeting_LTI1NTMzOTU5" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MeetingWithConversation_LTMyNzA4NzU0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MeetingWithConversation_LTMyNzA4NzU0" + } + } + }, + "description": "Meeting created" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-op", + "message": "Invalid meeting times, empty update, or meetings feature disabled" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-op" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid meeting times, empty update, or meetings feature disabled (label: `invalid-op`)" + }, + "533": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "unreachable_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "unreachable_backends" + ], + "type": "object" + } + } + }, + "description": "Some domains are unreachable" + } + }, + "summary": "Create a new meeting" + } + }, + "/meetings/list": { + "get": { + "description": " [internal route ID: \"list-meetings\"]\n\n", + "operationId": "list-meetings", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/Meeting_ODU0OTMzMTgw" + }, + "type": "array" + } + } + }, + "description": "" + } + }, + "summary": "List all meetings for the authenticated user" + } + }, + "/meetings/{domain}/{id}": { + "delete": { + "description": " [internal route ID: \"delete-meeting\"]\n\n", + "operationId": "delete-meeting", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Meeting deleted" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-op", + "message": "Invalid meeting times, empty update, or meetings feature disabled" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-op", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid meeting times, empty update, or meetings feature disabled (label: `invalid-op`)\n\nYou do not have permission to access this resource (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "meeting-not-found", + "message": "Meeting not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "meeting-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`domain` or `id` or Meeting not found (label: `meeting-not-found`)" + } + }, + "summary": "Delete a meeting" + }, + "get": { + "description": " [internal route ID: \"get-meeting\"]\n\n", + "operationId": "get-meeting", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Meeting_ODU0OTMzMTgw" + } + } + }, + "description": "" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "meeting-not-found", + "message": "Meeting not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "meeting-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`domain` or `id` or Meeting not found (label: `meeting-not-found`)" + } + }, + "summary": "Get a single meeting by ID" + }, + "put": { + "description": " [internal route ID: \"update-meeting\"]\n\n", + "operationId": "update-meeting", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UpdateMeeting_NTExNzYxMTcz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MeetingWithConversation_LTMyNzA4NzU0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MeetingWithConversation_LTMyNzA4NzU0" + } + } + }, + "description": "Meeting updated" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-op", + "message": "Invalid meeting times, empty update, or meetings feature disabled" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-op", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid meeting times, empty update, or meetings feature disabled (label: `invalid-op`)\n\nYou do not have permission to access this resource (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "meeting-not-found", + "message": "Meeting not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "meeting-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`domain` or `id` or Meeting not found (label: `meeting-not-found`)" + } + }, + "summary": "Update an existing meeting" + } + }, + "/meetings/{domain}/{id}/invitations": { + "post": { + "description": " [internal route ID: \"add-meeting-invitation\"]\n\n", + "operationId": "add-meeting-invitation", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MeetingEmailsInvitation_NzgyNzUzMzcz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Invitation added" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-op", + "message": "Invalid meeting times, empty update, or meetings feature disabled" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-op", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid meeting times, empty update, or meetings feature disabled (label: `invalid-op`)\n\nYou do not have permission to access this resource (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "meeting-not-found", + "message": "Meeting not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "meeting-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`domain` or `id` or Meeting not found (label: `meeting-not-found`)" + } + }, + "summary": "Add an email to the invited emails" + }, + "put": { + "description": " [internal route ID: \"replace-meeting-invitation\"]\n\n", + "operationId": "replace-meeting-invitation", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MeetingEmailsInvitation_NzgyNzUzMzcz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Invitations replaced" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-op", + "message": "Invalid meeting times, empty update, or meetings feature disabled" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-op", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid meeting times, empty update, or meetings feature disabled (label: `invalid-op`)\n\nYou do not have permission to access this resource (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "meeting-not-found", + "message": "Meeting not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "meeting-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`domain` or `id` or Meeting not found (label: `meeting-not-found`)" + } + }, + "summary": "Replace the invited emails" + } + }, + "/meetings/{domain}/{id}/invitations/delete": { + "post": { + "description": " [internal route ID: \"remove-meeting-invitation\"]\n\n", + "operationId": "remove-meeting-invitation", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MeetingEmailsInvitation_NzgyNzUzMzcz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Invitations removed" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-op", + "message": "Invalid meeting times, empty update, or meetings feature disabled" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-op", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid meeting times, empty update, or meetings feature disabled (label: `invalid-op`)\n\nYou do not have permission to access this resource (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "meeting-not-found", + "message": "Meeting not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "meeting-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`domain` or `id` or Meeting not found (label: `meeting-not-found`)" + } + }, + "summary": "Remove emails from the invited emails" + } + }, + "/mls/commit-bundles": { + "post": { + "description": " [internal route ID: \"mls-commit-bundle\"]\n\n\n\n**Note**: this endpoint can execute proposals, and therefore return all possible errors associated with adding or removing members to a conversation, in addition to the ones listed below. See the documentation of [POST /conversations/{cnv}/members/v2](#/default/post_conversations__cnv__members_v2) and [POST /conversations/{cnv_domain}/{cnv}/members/{usr_domain}/{usr}](#/default/delete_conversations__cnv_domain___cnv__members__usr_domain___usr_) for more details on the possible error responses of each type of proposal.", + "operationId": "mls-commit-bundle", + "requestBody": { + "content": { + "message/mls": { + "schema": { + "$ref": "#/components/schemas/CommitBundle" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MLSMessageSendingStatus_NjA1NDA0MTE4" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MLSMessageSendingStatus_NjA1NDA0MTE4" + } + } + }, + "description": "Commit accepted and forwarded" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-invalid-leaf-node-signature", + "message": "Invalid leaf node signature" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-invalid-leaf-node-signature", + "mls-group-id-not-supported", + "mls-welcome-mismatch", + "mls-self-removal-not-allowed", + "mls-protocol-error", + "mls-not-enabled", + "mls-invalid-leaf-node-index", + "mls-group-conversation-mismatch", + "mls-commit-missing-references", + "mls-client-sender-user-mismatch" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid leaf node signature (label: `mls-invalid-leaf-node-signature`)\n\nThe group ID version of the conversation is not supported by one of the federated backends (label: `mls-group-id-not-supported`)\n\nSubmitted group info is inconsistent with the backend group state (label `inconsistent-group-state`)\n\nThe list of targets of a welcome message does not match the list of new clients in a group (label: `mls-welcome-mismatch`)\n\nSelf removal from group is not allowed (label: `mls-self-removal-not-allowed`)\n\nMLS protocol error (label: `mls-protocol-error`)\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)\n\nA referenced leaf node index points to a blank or non-existing node (label: `mls-invalid-leaf-node-index`)\n\nConversation ID resolved from Group ID does not match submitted Conversation ID (label: `mls-group-conversation-mismatch`)\n\nThe commit is not referencing all pending proposals (label: `mls-commit-missing-references`)\n\nUser ID resolved from Client ID does not match message's sender user ID (label: `mls-client-sender-user-mismatch`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "mls-identity-mismatch", + "message": "Leaf node signature key does not match the client's key" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-identity-mismatch", + "mls-subconv-join-parent-missing", + "missing-legalhold-consent", + "legalhold-not-enabled", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Leaf node signature key does not match the client's key (label: `mls-identity-mismatch`)\n\nMLS client cannot join the subconversation because it is not member of the parent conversation (label: `mls-subconv-join-parent-missing`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nlegal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nConversation access denied (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "mls-proposal-not-found", + "message": "A proposal referenced in a commit message could not be found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-proposal-not-found", + "no-conversation", + "no-conversation-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "A proposal referenced in a commit message could not be found (label: `mls-proposal-not-found`)\n\nConversation not found (label: `no-conversation`)\n\nConversation member not found (label: `no-conversation-member`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "missing_users": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "type": "array" + } + }, + "required": [ + "missing_users" + ], + "type": "object" + } + } + }, + "description": "Group is out of sync\n\nAdding members to the conversation is not possible because the backends involved do not form a fully connected graph\n\nA user who is under legal-hold may not participate in MLS conversations (label: `mls-legal-hold-not-allowed`)\n\nThe conversation epoch in a message is too old (label: `mls-stale-message`)\n\nA proposal of type Add or Remove does not apply to the full list of clients for a user (label: `mls-client-mismatch`)" + }, + "422": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 422, + "label": "mls-unsupported-proposal", + "message": "Unsupported proposal type" + }, + "properties": { + "code": { + "enum": [ + 422 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-unsupported-proposal", + "mls-unsupported-message" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unsupported proposal type (label: `mls-unsupported-proposal`)\n\nAttempted to send a message with an unsupported combination of content type and wire format (label: `mls-unsupported-message`)" + }, + "533": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "unreachable_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "unreachable_backends" + ], + "type": "object" + } + } + }, + "description": "Some domains are unreachable" + } + }, + "summary": "Post a MLS CommitBundle" + } + }, + "/mls/key-packages/claim/{user_domain}/{user}": { + "post": { + "description": " [internal route ID: \"mls-key-packages-claim\"]\n\nOnly key packages for the specified ciphersuite are claimed.", + "operationId": "mls-key-packages-claim", + "parameters": [ + { + "in": "path", + "name": "user_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User Id", + "in": "path", + "name": "user", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "description": "Ciphersuite in hex format (e.g. 0x0002)", + "in": "query", + "name": "ciphersuite", + "required": true, + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyPackageBundle_MjU2MjY0MDU2" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/KeyPackageBundle_MjU2MjY0MDU2" + } + } + }, + "description": "Claimed key packages" + } + }, + "summary": "Claim one key package for each client of the given user" + } + }, + "/mls/key-packages/self/{client}": { + "delete": { + "description": " [internal route ID: \"mls-key-packages-delete\"]\n\n", + "operationId": "mls-key-packages-delete", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Ciphersuite in hex format (e.g. 0x0002)", + "in": "query", + "name": "ciphersuite", + "required": true, + "schema": { + "type": "number" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DeleteKeyPackages_LTQxNTcxNjY3" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "OK" + } + }, + "summary": "Delete all key packages for a given ciphersuite and client" + }, + "post": { + "description": " [internal route ID: \"mls-key-packages-upload\"]\n\nThe request body should be a json object containing a list of base64-encoded key packages.", + "operationId": "mls-key-packages-upload", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/KeyPackageUpload_NTQ2Mjk2NzEx" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Key packages uploaded" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-protocol-error", + "message": "MLS protocol error" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-protocol-error" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nMLS protocol error (label: `mls-protocol-error`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "mls-identity-mismatch", + "message": "Key package credential does not match qualified client ID" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-identity-mismatch" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Key package credential does not match qualified client ID (label: `mls-identity-mismatch`)" + } + }, + "summary": "Upload a fresh batch of key packages" + }, + "put": { + "description": " [internal route ID: \"mls-key-packages-replace\"]\n\nThe request body should be a json object containing a list of base64-encoded key packages. Use this sparingly.", + "operationId": "mls-key-packages-replace", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Comma-separated list of ciphersuites in hex format (e.g. 0x0002)", + "in": "query", + "name": "ciphersuites", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/KeyPackageUpload_NTQ2Mjk2NzEx" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Key packages replaced" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-protocol-error", + "message": "MLS protocol error" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-protocol-error" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body` or `ciphersuites`\n\nMLS protocol error (label: `mls-protocol-error`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "mls-identity-mismatch", + "message": "Key package credential does not match qualified client ID" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-identity-mismatch" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Key package credential does not match qualified client ID (label: `mls-identity-mismatch`)" + } + }, + "summary": "Upload a fresh batch of key packages and replace the old ones" + } + }, + "/mls/key-packages/self/{client}/count": { + "get": { + "description": " [internal route ID: \"mls-key-packages-count\"]\n\n", + "operationId": "mls-key-packages-count", + "parameters": [ + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Ciphersuite in hex format (e.g. 0x0002)", + "in": "query", + "name": "ciphersuite", + "required": true, + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyPackageCount_LTYwNDg5MDcz" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/KeyPackageCount_LTYwNDg5MDcz" + } + } + }, + "description": "Number of key packages" + } + }, + "summary": "Return the number of unclaimed key packages for a given ciphersuite and client" + } + }, + "/mls/messages": { + "post": { + "description": " [internal route ID: \"mls-message\"]\n\n\n\n**Note**: this endpoint can execute proposals, and therefore return all possible errors associated with adding or removing members to a conversation, in addition to the ones listed below. See the documentation of [POST /conversations/{cnv}/members/v2](#/default/post_conversations__cnv__members_v2) and [POST /conversations/{cnv_domain}/{cnv}/members/{usr_domain}/{usr}](#/default/delete_conversations__cnv_domain___cnv__members__usr_domain___usr_) for more details on the possible error responses of each type of proposal.", + "operationId": "mls-message", + "requestBody": { + "content": { + "message/mls": { + "schema": { + "$ref": "#/components/schemas/MLSMessage" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MLSMessageSendingStatus_NjA1NDA0MTE4" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MLSMessageSendingStatus_NjA1NDA0MTE4" + } + } + }, + "description": "Message sent" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-invalid-leaf-node-signature", + "message": "Invalid leaf node signature" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-invalid-leaf-node-signature", + "mls-self-removal-not-allowed", + "mls-protocol-error", + "mls-not-enabled", + "mls-invalid-leaf-node-index", + "mls-group-conversation-mismatch", + "mls-commit-missing-references", + "mls-client-sender-user-mismatch" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid leaf node signature (label: `mls-invalid-leaf-node-signature`)\n\nSubmitted group info is inconsistent with the backend group state (label `inconsistent-group-state`)\n\nSelf removal from group is not allowed (label: `mls-self-removal-not-allowed`)\n\nMLS protocol error (label: `mls-protocol-error`)\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)\n\nA referenced leaf node index points to a blank or non-existing node (label: `mls-invalid-leaf-node-index`)\n\nConversation ID resolved from Group ID does not match submitted Conversation ID (label: `mls-group-conversation-mismatch`)\n\nThe commit is not referencing all pending proposals (label: `mls-commit-missing-references`)\n\nUser ID resolved from Client ID does not match message's sender user ID (label: `mls-client-sender-user-mismatch`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "mls-subconv-join-parent-missing", + "message": "MLS client cannot join the subconversation because it is not member of the parent conversation" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-subconv-join-parent-missing", + "missing-legalhold-consent", + "legalhold-not-enabled", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "MLS client cannot join the subconversation because it is not member of the parent conversation (label: `mls-subconv-join-parent-missing`)\n\nFailed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nlegal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nConversation access denied (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "mls-proposal-not-found", + "message": "A proposal referenced in a commit message could not be found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-proposal-not-found", + "no-conversation", + "no-conversation-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "A proposal referenced in a commit message could not be found (label: `mls-proposal-not-found`)\n\nConversation not found (label: `no-conversation`)\n\nConversation member not found (label: `no-conversation-member`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "missing_users": { + "items": { + "$ref": "#/components/schemas/Qualified_Id_IdTag_User_LTQ1NTIwNDM1" + }, + "type": "array" + } + }, + "required": [ + "missing_users" + ], + "type": "object" + } + } + }, + "description": "Group is out of sync\n\nAdding members to the conversation is not possible because the backends involved do not form a fully connected graph\n\nThe conversation epoch in a message is too old (label: `mls-stale-message`)\n\nA proposal of type Add or Remove does not apply to the full list of clients for a user (label: `mls-client-mismatch`)" + }, + "422": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 422, + "label": "mls-unsupported-proposal", + "message": "Unsupported proposal type" + }, + "properties": { + "code": { + "enum": [ + 422 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-unsupported-proposal", + "mls-unsupported-message" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unsupported proposal type (label: `mls-unsupported-proposal`)\n\nAttempted to send a message with an unsupported combination of content type and wire format (label: `mls-unsupported-message`)" + }, + "533": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "unreachable_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "unreachable_backends" + ], + "type": "object" + } + } + }, + "description": "Some domains are unreachable" + } + }, + "summary": "Post an MLS message" + } + }, + "/mls/public-keys": { + "get": { + "description": " [internal route ID: \"mls-public-keys\"]\n\nThe format of the returned key is determined by the `format` query parameter:\n - raw (default): base64-encoded raw public keys\n - jwk: keys are nested objects in JWK format.", + "operationId": "mls-public-keys", + "parameters": [ + { + "in": "query", + "name": "format", + "required": false, + "schema": { + "enum": [ + "raw", + "jwk" + ], + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MLSKeysByPurpose_MLSKeys_SomeKey_NjkxMjk0MTAx" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MLSKeysByPurpose_MLSKeys_SomeKey_NjkxMjk0MTAx" + } + } + }, + "description": "Public keys" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-not-enabled", + "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-not-enabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `format`\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" + } + }, + "summary": "Get public keys used by the backend to sign external proposals" + } + }, + "/mls/reset-conversation": { + "post": { + "description": " [internal route ID: \"mls-reset-conversation\"]\n\n", + "operationId": "mls-reset-conversation", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MLSReset_NzgwODA3ODc4" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Conversation reset" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-protocol-error", + "message": "MLS protocol error" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-protocol-error", + "mls-group-id-not-supported", + "mls-federated-reset-not-supported", + "mls-not-enabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "MLS protocol error (label: `mls-protocol-error`)\n\nThe group ID version of the conversation is not supported by one of the federated backends (label: `mls-group-id-not-supported`)\n\nReset is not supported by the owning backend of the conversation (label: `mls-federated-reset-not-supported`)\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`) or `body`" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "action-denied", + "message": "Insufficient authorization (missing leave_conversation)" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "action-denied", + "invalid-op", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Insufficient authorization (missing leave_conversation) (label: `action-denied`)\n\nInvalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Conversation not found (label: `no-conversation`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "mls-stale-message", + "message": "The conversation epoch in a message is too old" + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-stale-message" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The conversation epoch in a message is too old (label: `mls-stale-message`)" + } + }, + "summary": "Reset an MLS conversation to epoch 0" + } + }, + "/notifications": { + "get": { + "description": " [internal route ID: \"get-notifications\"]\n\nSee also: GET /teams/notifications", + "operationId": "get-notifications", + "parameters": [ + { + "description": "Only return notifications more recent than this", + "in": "query", + "name": "since", + "required": false, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "description": "Only return notifications targeted at the given client", + "in": "query", + "name": "client", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum number of notifications to return", + "in": "query", + "name": "size", + "required": false, + "schema": { + "format": "int32", + "maximum": 10000, + "minimum": 100, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueuedNotificationList_MTU0ODEyNTQ2" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/QueuedNotificationList_MTU0ODEyNTQ2" + } + } + }, + "description": "Notification list" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Some notifications not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Some notifications not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Some notifications not found (label: `not-found`)" + } + }, + "summary": "Fetch notifications" + } + }, + "/notifications/last": { + "get": { + "description": " [internal route ID: \"get-last-notification\"]\n\n", + "operationId": "get-last-notification", + "parameters": [ + { + "description": "Only return notifications targeted at the given client", + "in": "query", + "name": "client", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueuedNotification_NTY2NzY2MTU2" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/QueuedNotification_NTY2NzY2MTU2" + } + } + }, + "description": "Notification found" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Some notifications not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Some notifications not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Some notifications not found (label: `not-found`)" + } + }, + "summary": "Fetch the last notification" + } + }, + "/notifications/{id}": { + "get": { + "description": " [internal route ID: \"get-notification-by-id\"]\n\n", + "operationId": "get-notification-by-id", + "parameters": [ + { + "description": "Notification ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "description": "Only return notifications targeted at the given client", + "in": "query", + "name": "client", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueuedNotification_NTY2NzY2MTU2" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/QueuedNotification_NTY2NzY2MTU2" + } + } + }, + "description": "Notification found" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Some notifications not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Some notifications not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`id` or Some notifications not found (label: `not-found`)" + } + }, + "summary": "Fetch a notification by ID" + } + }, + "/oauth/applications": { + "get": { + "description": " [internal route ID: \"get-oauth-applications\"]\n\nGet all OAuth applications with active account access for a user.", + "operationId": "get-oauth-applications", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/OAuthApplication_Mjk5NTUxNjA1" + }, + "type": "array" + } + }, + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/OAuthApplication_Mjk5NTUxNjA1" + }, + "type": "array" + } + } + }, + "description": "OAuth applications found" + } + }, + "summary": "Get OAuth applications with account access" + } + }, + "/oauth/applications/{OAuthClientId}/sessions": { + "delete": { + "description": " [internal route ID: \"revoke-oauth-account-access\"]\n\n", + "operationId": "revoke-oauth-account-access", + "parameters": [ + { + "description": "The ID of the OAuth client", + "in": "path", + "name": "OAuthClientId", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PasswordReqBody_LTcxMzE3ODE3" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "OAuth application access revoked" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + } + }, + "summary": "Revoke account access from an OAuth application" + } + }, + "/oauth/applications/{OAuthClientId}/sessions/{RefreshTokenId}": { + "delete": { + "description": " [internal route ID: \"delete-oauth-refresh-token\"]\n\nRevoke an active OAuth session by providing the refresh token ID.", + "operationId": "delete-oauth-refresh-token", + "parameters": [ + { + "description": "The ID of the OAuth client", + "in": "path", + "name": "OAuthClientId", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "description": "The ID of the refresh token", + "in": "path", + "name": "RefreshTokenId", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PasswordReqBody_LTcxMzE3ODE3" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "OAuth client not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`OAuthClientId` or `RefreshTokenId` not found\n\nOAuth client not found (label: `not-found`)" + } + }, + "summary": "Revoke an active OAuth session" + } + }, + "/oauth/authorization/codes": { + "post": { + "description": " [internal route ID: \"create-oauth-auth-code\"]\n\nCurrently only supports the 'code' response type, which corresponds to the authorization code flow.", + "operationId": "create-oauth-auth-code", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CreateOAuthAuthorizationCodeRequest_LTQ3NzI1Mjkz" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "headers": { + "Location": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 400, + "label": "redirect-url-miss-match", + "message": "The redirect URL does not match the one registered with the client" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "redirect-url-miss-match" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "redirect-url-miss-match", + "message": "The redirect URL does not match the one registered with the client" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "redirect-url-miss-match" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Bad Request\n\nThe redirect URL does not match the one registered with the client (label: `redirect-url-miss-match`) or `body`", + "headers": { + "Location": { + "schema": { + "type": "string" + } + } + } + }, + "403": { + "description": "Forbidden", + "headers": { + "Location": { + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "Not Found", + "headers": { + "Location": { + "schema": { + "type": "string" + } + } + } + } + }, + "summary": "Create an OAuth authorization code" + } + }, + "/oauth/clients/{OAuthClientId}": { + "get": { + "description": " [internal route ID: \"get-oauth-client\"]\n\n", + "operationId": "get-oauth-client", + "parameters": [ + { + "description": "The ID of the OAuth client", + "in": "path", + "name": "OAuthClientId", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OAuthClient_NzExMTI5NTIy" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/OAuthClient_NzExMTI5NTIy" + } + } + }, + "description": "OAuth client found" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "forbidden", + "message": "OAuth is disabled" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "forbidden" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "OAuth is disabled (label: `forbidden`)" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "OAuth client not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "OAuth client not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`OAuthClientId` or OAuth client not found (label: `not-found`)\n\nOAuth client not found (label: `not-found`)" + } + }, + "summary": "Get OAuth client information" + } + }, + "/oauth/revoke": { + "post": { + "description": " [internal route ID: \"revoke-oauth-refresh-token\"]\n\nRevoke an access token.", + "operationId": "revoke-oauth-refresh-token", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/OAuthRevokeRefreshTokenRequest_MjA1MDg4MzQ4" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "forbidden", + "message": "Invalid refresh token" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "forbidden" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid refresh token (label: `forbidden`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "OAuth client not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "OAuth client not found (label: `not-found`)" + }, + "500": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 500, + "label": "jwt-error", + "message": "Internal error while handling JWT token" + }, + "properties": { + "code": { + "enum": [ + 500 + ], + "type": "integer" + }, + "label": { + "enum": [ + "jwt-error" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Internal error while handling JWT token (label: `jwt-error`)" + } + }, + "summary": "Revoke an OAuth refresh token" + } + }, + "/oauth/token": { + "post": { + "description": " [internal route ID: \"create-oauth-access-token\"]\n\nObtain a new access token from an authorization code or a refresh token.", + "operationId": "create-oauth-access-token", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Either_OAuthAccessTokenRequest_OAuthRefreshAccessTokenRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/OAuthAccessTokenResponse_NzEwOTI4NjQ0" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid_grant", + "message": "Invalid grant" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid_grant", + "forbidden" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid grant (label: `invalid_grant`)\n\nInvalid client credentials (label: `forbidden`)\n\nInvalid grant type (label: `forbidden`)\n\nInvalid refresh token (label: `forbidden`)\n\nOAuth is disabled (label: `forbidden`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "OAuth client not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "OAuth client not found (label: `not-found`)\n\nOAuth authorization code not found (label: `not-found`)" + }, + "500": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 500, + "label": "jwt-error", + "message": "Internal error while handling JWT token" + }, + "properties": { + "code": { + "enum": [ + 500 + ], + "type": "integer" + }, + "label": { + "enum": [ + "jwt-error" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Internal error while handling JWT token (label: `jwt-error`)" + } + }, + "summary": "Create an OAuth access token" + } + }, + "/one2one-conversations": { + "post": { + "description": " [internal route ID: \"create-one-to-one-conversation\"]\n\n", + "operationId": "create-one-to-one-conversation", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewOne2OneConv_LTI3OTc4NDAz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/v3_OwnConversation_GroupConvType_LTU2MzYxNTg0V3" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/v3_OwnConversation_GroupConvType_LTU2MzYxNTg0V3" + } + } + }, + "description": "Conversation existed", + "headers": { + "Location": { + "description": "Conversation ID", + "schema": { + "format": "uuid", + "type": "string" + } + } + } + }, + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/v3_OwnConversation_GroupConvType_LTU2MzYxNTg0V3" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/v3_OwnConversation_GroupConvType_LTU2MzYxNTg0V3" + } + } + }, + "description": "Conversation created", + "headers": { + "Location": { + "description": "Conversation ID", + "schema": { + "format": "uuid", + "type": "string" + } + } + } + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "missing-legalhold-consent", + "message": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "missing-legalhold-consent", + "operation-denied", + "not-connected", + "no-team-member", + "non-binding-team-members", + "invalid-op", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Failed to connect to a user or to invite a user to a group because somebody is under legalhold and somebody else has not granted consent (label: `missing-legalhold-consent`)\n\nInsufficient permissions (label: `operation-denied`)\n\nUsers are not connected (label: `not-connected`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nBoth users must be members of the same binding team (label: `non-binding-team-members`)\n\nInvalid operation (label: `invalid-op`)\n\nConversation access denied (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team", + "non-binding-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Team not found (label: `no-team`)\n\nNot a member of a binding team (label: `non-binding-team`)" + }, + "533": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "unreachable_backends": { + "items": { + "$ref": "#/components/schemas/Domain" + }, + "type": "array" + } + }, + "required": [ + "unreachable_backends" + ], + "type": "object" + } + } + }, + "description": "Some domains are unreachable" + } + }, + "summary": "Create a 1:1 conversation" + } + }, + "/one2one-conversations/{usr_domain}/{usr}": { + "get": { + "description": " [internal route ID: \"get-one-to-one-mls-conversation\"]\n\n", + "operationId": "get-one-to-one-mls-conversation", + "parameters": [ + { + "in": "path", + "name": "usr_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "usr", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "query", + "name": "format", + "required": false, + "schema": { + "enum": [ + "raw", + "jwk" + ], + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MLSOne2OneConversation_SomeKey_GroupConvType_LTg2MTcwMjY3" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/MLSOne2OneConversation_SomeKey_GroupConvType_LTg2MTcwMjY3" + } + } + }, + "description": "MLS 1-1 conversation" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "mls-not-enabled", + "message": "MLS is not configured on this backend. See docs.wire.com for instructions on how to enable it" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-not-enabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `format`\n\nMLS is not configured on this backend. See docs.wire.com for instructions on how to enable it (label: `mls-not-enabled`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "not-connected", + "message": "Users are not connected" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-connected" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Users are not connected (label: `not-connected`)" + } + }, + "summary": "Get an MLS 1:1 conversation" + } + }, + "/password-reset": { + "post": { + "description": " [internal route ID: \"post-password-reset\"]\n\n", + "operationId": "post-password-reset", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewPasswordReset_LTEyNzAxMTcy" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Password reset code created and sent by email." + } + }, + "summary": "Initiate a password reset." + } + }, + "/password-reset/complete": { + "post": { + "description": " [internal route ID: \"post-password-reset-complete\"]\n\n", + "operationId": "post-password-reset-complete", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CompletePasswordReset_NDcyMjY5OTc4" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Password reset successful." + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-code", + "message": "Invalid password reset code." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid password reset code. (label: `invalid-code`)" + } + }, + "summary": "Complete a password reset." + } + }, + "/properties": { + "delete": { + "description": " [internal route ID: \"clear-properties\"]\n\n", + "operationId": "clear-properties", + "responses": { + "200": { + "description": "Properties cleared" + } + }, + "summary": "Clear all properties" + }, + "get": { + "description": " [internal route ID: \"list-property-keys\"]\n\n", + "operationId": "list-property-keys", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ASCII" + }, + "type": "array" + } + }, + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/ASCII" + }, + "type": "array" + } + } + }, + "description": "List of property keys" + } + }, + "summary": "List all property keys" + } + }, + "/properties-values": { + "get": { + "description": " [internal route ID: \"list-properties\"]\n\n", + "operationId": "list-properties", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PropertyKeysAndValues" + } + } + }, + "description": "" + } + }, + "summary": "List all properties with key and value" + } + }, + "/properties/{key}": { + "delete": { + "description": " [internal route ID: \"delete-property\"]\n\n", + "operationId": "delete-property", + "parameters": [ + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "format": "printable", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Property deleted" + } + }, + "summary": "Delete a property" + }, + "get": { + "description": " [internal route ID: \"get-property\"]\n\n", + "operationId": "get-property", + "parameters": [ + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "format": "printable", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PropertyValue" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PropertyValue" + } + } + }, + "description": "The property value" + }, + "404": { + "description": "`key` or Property not found(**Note**: This error has an empty body for legacy reasons)" + } + }, + "summary": "Get a property value" + }, + "put": { + "description": " [internal route ID: \"set-property\"]\n\n", + "operationId": "set-property", + "parameters": [ + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "format": "printable", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PropertyValue" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Property set" + } + }, + "summary": "Set a user property" + } + }, + "/provider": { + "delete": { + "description": " [internal route ID: \"provider-delete\"]\n\n", + "operationId": "provider-delete", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DeleteProvider_MzYxMzM3Mjg2" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials", + "invalid-provider", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Authentication failed (label: `invalid-credentials`)\n\nThe provider does not exist. (label: `invalid-provider`)\n\nAccess denied. (label: `access-denied`)" + } + }, + "summary": "Delete a provider" + }, + "get": { + "description": " [internal route ID: \"provider-get-account\"]\n\n", + "operationId": "provider-get-account", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Provider_NDIyMzQ3ODIy" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Provider_NDIyMzQ3ODIy" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Provider not found." + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Provider not found." + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Provider not found. (label: `not-found`)\n\nProvider not found. (label: `not-found`)" + } + }, + "summary": "Get account" + }, + "put": { + "description": " [internal route ID: \"provider-update\"]\n\n", + "operationId": "provider-update", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UpdateProvider_LTQwMjY4MDgy" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-provider", + "message": "The provider does not exist." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-provider", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The provider does not exist. (label: `invalid-provider`)\n\nAccess denied. (label: `access-denied`)" + } + }, + "summary": "Update a provider" + } + }, + "/provider/activate": { + "get": { + "description": " [internal route ID: \"provider-activate\"]\n\n", + "operationId": "provider-activate", + "parameters": [ + { + "in": "query", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "code", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderActivationResponse_LTgzNTU3MzA5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ProviderActivationResponse_LTgzNTU3MzA5" + } + } + }, + "description": "" + }, + "204": { + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-code", + "message": "Invalid verification code" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-code", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid verification code (label: `invalid-code`)\n\nAccess denied. (label: `access-denied`)" + } + }, + "summary": "Activate a provider" + } + }, + "/provider/assets": { + "post": { + "description": " [internal route ID: (\"assets-upload-v3\", provider)]\n\n

Construct the request as multipart/mixed; set header Content-Type: multipart/mixed; boundary=<boundary>.

Use exactly two parts in this order:

  1. application/json metadata (AssetSettings)
  2. application/octet-stream asset bytes

Each part must include Content-Type and Content-Length; the second part may include Content-MD5. Use CRLF between headers and bodies.

When asset audit logging is enabled, the JSON metadata must include:

  • convId: object { id: UUID, domain: String } (qualified conversation ID)
  • filename: String
  • filetype: String MIME type (e.g. image/png, application/pdf)

Optional metadata: public (Bool, default false), retention (one of eternal, persistent, volatile, eternal-infrequent_access, expiring).

For profile pictures or team icons without a conversation, set convId.id to 00000000-0000-0000-0000-000000000000 and convId.domain to the tenant’s domain; use any reasonable filename.

Note: the server treats the asset bytes as application/octet-stream; filetype is used for auditing only.

Example body (boundary=frontier):

Content-Type: multipart/mixed; boundary=frontier

--frontier
Content-Type: application/json
Content-Length: 191

{\"public\":false,\"retention\":\"volatile\",\"convId\":{\"id\":\"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\",\"domain\":\"example.com\"},\"filename\":\"report.pdf\",\"filetype\":\"application/pdf\"}
--frontier
Content-Type: application/octet-stream
Content-Length: 11

Hello Audit
--frontier--
", + "operationId": "assets-upload-v3_provider", + "requestBody": { + "content": { + "multipart/mixed": { + "schema": { + "$ref": "#/components/schemas/AssetSource" + } + } + }, + "description": "A body with content type `multipart/mixed body`. The first section's content type should be `application/json`. The second section's content type should be always be `application/octet-stream`. Other content types will be ignored by the server." + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Asset_Qualified_AssetKey_MzU1MjMxNTA5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Asset_Qualified_AssetKey_MzU1MjMxNTA5" + } + } + }, + "description": "Asset posted", + "headers": { + "Location": { + "description": "Asset location", + "schema": { + "format": "url", + "type": "string" + } + } + } + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "incomplete-body", + "message": "HTTP content-length header does not match body size" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "incomplete-body", + "invalid-length" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nHTTP content-length header does not match body size (label: `incomplete-body`)\n\nInvalid content length (label: `invalid-length`)" + }, + "413": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 413, + "label": "client-error", + "message": "Asset too large" + }, + "properties": { + "code": { + "enum": [ + 413 + ], + "type": "integer" + }, + "label": { + "enum": [ + "client-error" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Asset too large (label: `client-error`)" + } + }, + "summary": "Upload an asset" + } + }, + "/provider/assets/{key}": { + "delete": { + "description": " [internal route ID: (\"assets-delete-v3\", provider)]\n\n", + "operationId": "assets-delete-v3_provider", + "parameters": [ + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Asset deleted" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "unauthorised", + "message": "Unauthorised operation" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unauthorised" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unauthorised operation (label: `unauthorised`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Asset not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`key` not found\n\nAsset not found (label: `not-found`)" + } + }, + "summary": "Delete an asset" + }, + "get": { + "description": " [internal route ID: (\"assets-download-v3\", provider)]\n\n", + "operationId": "assets-download-v3_provider", + "parameters": [ + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "header", + "name": "Asset-Token", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "asset_token", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "302": { + "description": "Asset found", + "headers": { + "Location": { + "description": "Asset location", + "schema": { + "format": "url", + "type": "string" + } + } + } + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Asset not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Asset not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`key` or Asset not found (label: `not-found`)" + } + }, + "summary": "Download an asset" + } + }, + "/provider/email": { + "put": { + "description": " [internal route ID: \"provider-update-email\"]\n\n", + "operationId": "provider-update-email", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/EmailUpdate_LTYwODE0ODQ5" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-email", + "message": "Invalid e-mail address." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-email" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid e-mail address. (label: `invalid-email`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-provider", + "message": "The provider does not exist." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-provider", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The provider does not exist. (label: `invalid-provider`)\n\nAccess denied. (label: `access-denied`)" + }, + "429": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 429, + "label": "too-many-requests", + "message": "Too many request to generate a verification code." + }, + "properties": { + "code": { + "enum": [ + 429 + ], + "type": "integer" + }, + "label": { + "enum": [ + "too-many-requests" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Too many request to generate a verification code. (label: `too-many-requests`)" + } + }, + "summary": "Update a provider email" + } + }, + "/provider/login": { + "post": { + "description": " [internal route ID: \"provider-login\"]\n\n", + "operationId": "provider-login", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ProviderLogin_LTE2MTk2NTM5" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "headers": { + "Set-Cookie": { + "schema": { + "type": "string" + } + } + } + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Authentication failed (label: `invalid-credentials`)\n\nAccess denied. (label: `access-denied`)" + } + }, + "summary": "Login as a provider" + } + }, + "/provider/password": { + "put": { + "description": " [internal route ID: \"provider-update-password\"]\n\n", + "operationId": "provider-update-password", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PasswordChange_NDI0ODgwNDU0" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Authentication failed (label: `invalid-credentials`)\n\nAccess denied. (label: `access-denied`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "password-must-differ", + "message": "For password reset, new and old password must be different." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "password-must-differ" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "For password reset, new and old password must be different. (label: `password-must-differ`)" + } + }, + "summary": "Update a provider password" + } + }, + "/provider/password-reset": { + "post": { + "description": " [internal route ID: \"provider-password-reset\"]\n\n", + "operationId": "provider-password-reset", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PasswordReset_LTYzNDYxNTQ3" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-code", + "message": "Invalid password reset code." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-code", + "invalid-key" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid password reset code. (label: `invalid-code`)\n\nInvalid email or mobile number for password reset. (label: `invalid-key`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Authentication failed (label: `invalid-credentials`)\n\nAccess denied. (label: `access-denied`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "password-must-differ", + "message": "For password reset, new and old password must be different." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "password-must-differ", + "code-exists" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "For password reset, new and old password must be different. (label: `password-must-differ`)\n\nA password reset is already in progress. (label: `code-exists`)\n\nA password reset is already in progress. (label: `code-exists`)" + }, + "429": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 429, + "label": "too-many-requests", + "message": "Too many request to generate a verification code." + }, + "properties": { + "code": { + "enum": [ + 429 + ], + "type": "integer" + }, + "label": { + "enum": [ + "too-many-requests" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Too many request to generate a verification code. (label: `too-many-requests`)" + } + }, + "summary": "Begin a password reset" + } + }, + "/provider/password-reset/complete": { + "post": { + "description": " [internal route ID: \"provider-password-reset-complete\"]\n\n", + "operationId": "provider-password-reset-complete", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CompletePasswordReset_LTYzMDAxNDA1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-code", + "message": "Invalid password reset code." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid password reset code. (label: `invalid-code`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials", + "invalid-code", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Authentication failed (label: `invalid-credentials`)\n\nInvalid verification code (label: `invalid-code`)\n\nAccess denied. (label: `access-denied`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "password-must-differ", + "message": "For password reset, new and old password must be different." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "password-must-differ" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "For password reset, new and old password must be different. (label: `password-must-differ`)" + } + }, + "summary": "Complete a password reset" + } + }, + "/provider/register": { + "post": { + "description": " [internal route ID: \"provider-register\"]\n\n", + "operationId": "provider-register", + "parameters": [ + { + "in": "header", + "name": "X-Forwarded-For", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewProvider_LTEyMTY5MjYy" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewProviderResponse_OTE0ODI2NjU0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewProviderResponse_OTE0ODI2NjU0" + } + } + }, + "description": "" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-email", + "message": "Invalid e-mail address." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-email" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body` or `X-Forwarded-For`\n\nInvalid e-mail address. (label: `invalid-email`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + }, + "429": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 429, + "label": "too-many-requests", + "message": "Too many request to generate a verification code." + }, + "properties": { + "code": { + "enum": [ + 429 + ], + "type": "integer" + }, + "label": { + "enum": [ + "too-many-requests" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Too many request to generate a verification code. (label: `too-many-requests`)" + } + }, + "summary": "Register a new provider" + } + }, + "/provider/services": { + "get": { + "description": " [internal route ID: \"get-provider-services\"]\n\n", + "operationId": "get-provider-services", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/Service_MjcyOTA5NjQx" + }, + "type": "array" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + } + }, + "summary": "List provider services" + }, + "post": { + "description": " [internal route ID: \"post-provider-services\"]\n\n", + "operationId": "post-provider-services", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewService_LTYwOTU1MDQ3" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewServiceResponse_LTExMzcwMjg5" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewServiceResponse_LTExMzcwMjg5" + } + } + }, + "description": "" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-service-key", + "message": "Invalid service key." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-service-key" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid service key. (label: `invalid-service-key`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + } + }, + "summary": "Create a new service" + } + }, + "/provider/services/{service-id}": { + "delete": { + "description": " [internal route ID: \"delete-provider-services-by-service-id\"]\n\n", + "operationId": "delete-provider-services-by-service-id", + "parameters": [ + { + "in": "path", + "name": "service-id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DeleteService_LTY2NzY5NzMz" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Authentication failed (label: `invalid-credentials`)\n\nAccess denied. (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Service not found." + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`service-id` not found\n\nService not found. (label: `not-found`)" + } + }, + "summary": "Delete service" + }, + "get": { + "description": " [internal route ID: \"get-provider-services-by-service-id\"]\n\n", + "operationId": "get-provider-services-by-service-id", + "parameters": [ + { + "in": "path", + "name": "service-id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Service_MjcyOTA5NjQx" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Service not found." + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`service-id` not found\n\nService not found. (label: `not-found`)" + } + }, + "summary": "Get provider service by service id" + }, + "put": { + "description": " [internal route ID: \"put-provider-services-by-service-id\"]\n\n", + "operationId": "put-provider-services-by-service-id", + "parameters": [ + { + "in": "path", + "name": "service-id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UpdateService_MjAxNzQ2Njkz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Provider service updated" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Provider not found." + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`service-id` not found\n\nProvider not found. (label: `not-found`)\n\nService not found. (label: `not-found`)" + } + }, + "summary": "Update provider service" + } + }, + "/provider/services/{service-id}/connection": { + "put": { + "description": " [internal route ID: \"put-provider-services-connection-by-service-id\"]\n\n", + "operationId": "put-provider-services-connection-by-service-id", + "parameters": [ + { + "in": "path", + "name": "service-id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UpdateServiceConn_LTQ1OTYwNjIz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Provider service connection updated" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-service-key", + "message": "Invalid service key." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-service-key" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid service key. (label: `invalid-service-key`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Authentication failed (label: `invalid-credentials`)\n\nAccess denied. (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Service not found." + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`service-id` not found\n\nService not found. (label: `not-found`)" + } + }, + "summary": "Update provider service connection" + } + }, + "/providers/{pid}": { + "get": { + "description": " [internal route ID: \"provider-get-profile\"]\n\n", + "operationId": "provider-get-profile", + "parameters": [ + { + "in": "path", + "name": "pid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Provider_NDIyMzQ3ODIy" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Provider_NDIyMzQ3ODIy" + } + } + }, + "description": "" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Provider not found." + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Provider not found." + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`pid` or Provider not found. (label: `not-found`)" + } + }, + "summary": "Get profile" + } + }, + "/providers/{provider-id}/services": { + "get": { + "description": " [internal route ID: \"get-provider-services-by-provider-id\"]\n\n", + "operationId": "get-provider-services-by-provider-id", + "parameters": [ + { + "in": "path", + "name": "provider-id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/ServiceProfile_LTc2MDQzNTk3" + }, + "type": "array" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + } + }, + "summary": "Get provider services by provider id" + } + }, + "/providers/{provider-id}/services/{service-id}": { + "get": { + "description": " [internal route ID: \"get-provider-services-by-provider-id-and-service-id\"]\n\n", + "operationId": "get-provider-services-by-provider-id-and-service-id", + "parameters": [ + { + "in": "path", + "name": "provider-id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "service-id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ServiceProfile_LTc2MDQzNTk3" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Service not found." + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`provider-id` or `service-id` not found\n\nService not found. (label: `not-found`)" + } + }, + "summary": "Get provider service by provider id and service id" + } + }, + "/proxy/giphy/v1/gifs": {}, + "/proxy/googlemaps/api/staticmap": {}, + "/proxy/googlemaps/maps/api/geocode": {}, + "/proxy/soundcloud/resolve": {}, + "/proxy/soundcloud/stream": {}, + "/proxy/spotify/api/token": {}, + "/proxy/youtube/v3": {}, + "/push/tokens": { + "get": { + "description": " [internal route ID: \"get-push-tokens\"]\n\n", + "operationId": "get-push-tokens", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PushTokenList_NDI0Mjc3MzY3" + } + } + }, + "description": "" + } + }, + "summary": "List the user's registered push tokens" + }, + "post": { + "description": " [internal route ID: \"register-push-token\"]\n\n", + "operationId": "register-push-token", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PushToken_ODYzMDYzOTA4" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PushToken_ODYzMDYzOTA4" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PushToken_ODYzMDYzOTA4" + } + } + }, + "description": "Push token registered", + "headers": { + "Location": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 400, + "label": "apns-voip-not-supported", + "message": "Adding APNS_VOIP tokens is not supported" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "apns-voip-not-supported" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "apns-voip-not-supported", + "message": "Adding APNS_VOIP tokens is not supported" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "apns-voip-not-supported" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Adding APNS_VOIP tokens is not supported (label: `apns-voip-not-supported`) or `body`" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "app-not-found", + "message": "App does not exist" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "app-not-found", + "invalid-token" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "app-not-found", + "message": "App does not exist" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "app-not-found", + "invalid-token" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "App does not exist (label: `app-not-found`)\n\nInvalid push token (label: `invalid-token`)" + }, + "413": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 413, + "label": "sns-thread-budget-reached", + "message": "Too many concurrent calls to SNS; is SNS down?" + }, + "properties": { + "code": { + "enum": [ + 413 + ], + "type": "integer" + }, + "label": { + "enum": [ + "sns-thread-budget-reached", + "token-too-long", + "metadata-too-long" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 413, + "label": "sns-thread-budget-reached", + "message": "Too many concurrent calls to SNS; is SNS down?" + }, + "properties": { + "code": { + "enum": [ + 413 + ], + "type": "integer" + }, + "label": { + "enum": [ + "sns-thread-budget-reached", + "token-too-long", + "metadata-too-long" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Too many concurrent calls to SNS; is SNS down? (label: `sns-thread-budget-reached`)\n\nPush token length must be < 8192 for GCM or 400 for APNS (label: `token-too-long`)\n\nTried to add token to endpoint resulting in metadata length > 2048 (label: `metadata-too-long`)" + } + }, + "summary": "Register a native push token" + } + }, + "/push/tokens/{pid}": { + "delete": { + "description": " [internal route ID: \"delete-push-token\"]\n\n", + "operationId": "delete-push-token", + "parameters": [ + { + "description": "The push token to delete", + "in": "path", + "name": "pid", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Push token unregistered" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Push token not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Push token not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`pid` or Push token not found (label: `not-found`)" + } + }, + "summary": "Unregister a native push token" + } + }, + "/register": { + "post": { + "description": " [internal route ID: \"register\"]\n\nIf the environment where the registration takes place is private and a registered email address is not whitelisted, a 403 error is returned.", + "operationId": "register", + "parameters": [ + { + "in": "header", + "name": "X-Forwarded-For", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewUser_PlainTextPassword_8_LTI4MzI5NzQx" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User_NjA4OTQwMTQ4" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/User_NjA4OTQwMTQ4" + } + } + }, + "description": "User created and pending activation", + "headers": { + "Location": { + "description": "UserId", + "schema": { + "format": "uuid", + "type": "string" + } + }, + "Set-Cookie": { + "description": "Cookie", + "schema": { + "type": "string" + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 400, + "label": "invalid-invitation-code", + "message": "Invalid invitation code." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-invitation-code", + "invalid-email", + "invalid-phone" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-invitation-code", + "message": "Invalid invitation code." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-invitation-code", + "invalid-email", + "invalid-phone" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid invitation code. (label: `invalid-invitation-code`)\n\nInvalid e-mail address. (label: `invalid-email`)\n\nInvalid mobile phone number (label: `invalid-phone`) or `body` or `X-Forwarded-For`" + }, + "403": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 403, + "label": "unauthorized", + "message": "Unauthorized e-mail address" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unauthorized", + "missing-identity", + "blacklisted-email", + "too-many-team-members", + "user-creation-restricted", + "ephemeral-user-creation-disabled", + "managed-by-scim" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "unauthorized", + "message": "Unauthorized e-mail address" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "unauthorized", + "missing-identity", + "blacklisted-email", + "too-many-team-members", + "user-creation-restricted", + "ephemeral-user-creation-disabled", + "managed-by-scim" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Unauthorized e-mail address (label: `unauthorized`)\n\nUsing an invitation code requires registering the given email. (label: `missing-identity`)\n\nThe given e-mail address has been blacklisted due to a permanent bounce or a complaint. (label: `blacklisted-email`)\n\nToo many members in this team. (label: `too-many-team-members`)\n\nThis instance does not allow creation of personal users or teams. (label: `user-creation-restricted`)\n\nEphemeral user creation is disabled on this instance. (label: `ephemeral-user-creation-disabled`)\n\nUpdating name is not allowed, because it is managed by SCIM, or E2EId is enabled (label: `managed-by-scim`)" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "invalid-code", + "message": "User does not exist" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "invalid-code", + "message": "User does not exist" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "User does not exist (label: `invalid-code`)\n\nInvalid activation code (label: `invalid-code`)" + }, + "409": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 409, + "label": "key-exists", + "message": "The given e-mail address is in use." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "key-exists" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "key-exists", + "message": "The given e-mail address is in use." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "key-exists" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The given e-mail address is in use. (label: `key-exists`)" + } + }, + "summary": "Register a new user." + } + }, + "/scim/auth-tokens": { + "delete": { + "description": " [internal route ID: \"auth-tokens-delete\"]\n\n", + "operationId": "auth-tokens-delete", + "parameters": [ + { + "in": "query", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "code-authentication-required", + "message": "Code authentication is required" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "code-authentication-required", + "code-authentication-failed" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Code authentication is required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)" + } + } + }, + "get": { + "description": " [internal route ID: \"auth-tokens-list\"]\n\n", + "operationId": "auth-tokens-list", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ScimTokenList_NjQwNTYxOTAw" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "code-authentication-required", + "message": "Code authentication is required" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "code-authentication-required", + "code-authentication-failed" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Code authentication is required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)" + } + } + }, + "post": { + "description": " [internal route ID: \"auth-tokens-create\"]\n\n", + "operationId": "auth-tokens-create", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CreateScimToken_OTY0NjYxMDQ2" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CreateScimTokenResponse_LTIzOTU2NDU4" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "code-authentication-required", + "message": "Code authentication is required" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "code-authentication-required", + "code-authentication-failed" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Code authentication is required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)" + } + } + } + }, + "/scim/auth-tokens/{id}": { + "put": { + "description": " [internal route ID: \"auth-tokens-put-name\"]\n\n", + "operationId": "auth-tokens-put-name", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ScimTokenName_LTgzOTM2OTI4" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "code-authentication-required", + "message": "Code authentication is required" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "code-authentication-required", + "code-authentication-failed" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Code authentication is required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)" + } + } + } + }, + "/search/contacts": { + "get": { + "description": " [internal route ID: \"search-contacts\"]\n\n", + "operationId": "search-contacts", + "parameters": [ + { + "description": "Search query

The search query is normalized: lower-cased and diacritics are removed ('Björn' becomes 'bjorn'). The normalized search query matches accounts that, in this order of priority:

  • are equal to the normalized full handle;
  • are equal to the normalized full user display name;
  • prefix-match the normalized handle;
  • prefix-match the normalized user display name.

NB: '@' Does NOT do anything special, ignoring user display names.

See also: [authoritative ElasticSearch query](https://github.com/wireapp/wire-server/blob/83c25cca6a5e9d2205c102410b452eb78fc50a00/libs/wire-subsystems/src/Wire/IndexedUserStore/ElasticSearch.hs#L251-L288)

", + "in": "query", + "name": "q", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Searched domain. Note: This is optional only for backwards compatibility, future versions will mandate this.", + "in": "query", + "name": "domain", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Number of results to return (min: 1, max: 500, default 15)", + "in": "query", + "name": "size", + "required": false, + "schema": { + "format": "int32", + "maximum": 500, + "minimum": 1, + "type": "integer" + } + }, + { + "description": "Only user types. Omitted or empty (type=) means no filtering.", + "in": "query", + "name": "type", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/SearchResult_Contact_OTExNzg4MTE0" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "insufficient-permissions", + "message": "Insufficient permissions" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "insufficient-permissions" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Insufficient permissions (label: `insufficient-permissions`)" + } + }, + "summary": "Search for users" + } + }, + "/self": { + "delete": { + "description": " [internal route ID: \"delete-self\"]\n\nif the account has a verified identity, a verification code is sent and needs to be confirmed to authorise the deletion. if the account has no verified identity but a password, it must be provided. if password is correct, or if neither a verified identity nor a password exists, account deletion is scheduled immediately.", + "operationId": "delete-self", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DeleteUser_NjE0MjE2Mjkz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Deletion is initiated." + }, + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeletionCodeTimeout_LTU1MTk0NDI3" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DeletionCodeTimeout_LTU1MTk0NDI3" + } + } + }, + "description": "Deletion is pending verification with a code." + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-user", + "message": "Invalid user" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-user" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid user (label: `invalid-user`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-self-delete-for-team-owner", + "message": "Team owners are not allowed to delete themselves; ask a fellow owner" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-self-delete-for-team-owner", + "pending-delete", + "missing-auth", + "invalid-credentials", + "invalid-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Team owners are not allowed to delete themselves; ask a fellow owner (label: `no-self-delete-for-team-owner`)\n\nA verification code for account deletion is still pending (label: `pending-delete`)\n\nRe-authentication via password required (label: `missing-auth`)\n\nAuthentication failed (label: `invalid-credentials`)\n\nInvalid verification code (label: `invalid-code`)" + } + }, + "summary": "Initiate account deletion." + }, + "get": { + "description": " [internal route ID: \"get-self\"]\n\n\nOAuth scope: `read:self`", + "operationId": "get-self", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/User_NjA4OTQwMTQ4" + } + } + }, + "description": "" + } + }, + "summary": "Get your own profile" + }, + "put": { + "description": " [internal route ID: \"put-self\"]\n\n", + "operationId": "put-self", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserUpdate_MjQ4NTEwOTQz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User updated" + } + }, + "summary": "Update your profile." + } + }, + "/self/email": { + "delete": { + "description": " [internal route ID: \"remove-email\"]\n\nYour email address can only be removed if you also have a phone number.", + "operationId": "remove-email", + "responses": { + "200": { + "description": "Identity Removed" + }, + "403": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 403, + "label": "last-identity", + "message": "The last user identity cannot be removed." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "last-identity", + "no-identity" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "last-identity", + "message": "The last user identity cannot be removed." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "last-identity", + "no-identity" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The last user identity cannot be removed. (label: `last-identity`)\n\nThe user has no verified email (label: `no-identity`)" + } + }, + "summary": "Remove your email address." + } + }, + "/self/handle": { + "put": { + "description": " [internal route ID: \"change-handle\"]\n\n", + "operationId": "change-handle", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/HandleUpdate_NTI4NDk1OTAx" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Handle Changed" + } + }, + "summary": "Change your handle." + } + }, + "/self/locale": { + "put": { + "description": " [internal route ID: \"change-locale\"]\n\n", + "operationId": "change-locale", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LocaleUpdate_LTgzNjgyOTEw" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Local Changed" + } + }, + "summary": "Change your locale." + } + }, + "/self/password": { + "head": { + "description": " [internal route ID: \"check-password-exists\"]\n\n", + "operationId": "check-password-exists", + "responses": { + "200": { + "description": "Password is set" + }, + "404": { + "description": "Password is not set" + } + }, + "summary": "Check that your password is set." + }, + "put": { + "description": " [internal route ID: \"change-password\"]\n\n", + "operationId": "change-password", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PasswordChange_MTgzMDM2NTY2" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Password Changed" + }, + "403": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials", + "no-identity" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-credentials", + "message": "Authentication failed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-credentials", + "no-identity" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Authentication failed (label: `invalid-credentials`)\n\nThe user has no verified email (label: `no-identity`)" + }, + "409": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 409, + "label": "password-must-differ", + "message": "For password change, new and old password must be different." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "password-must-differ" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "password-must-differ", + "message": "For password change, new and old password must be different." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "password-must-differ" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "For password change, new and old password must be different. (label: `password-must-differ`)" + } + }, + "summary": "Change your password." + } + }, + "/self/supported-protocols": { + "put": { + "description": " [internal route ID: \"change-supported-protocols\"]\n\n", + "operationId": "change-supported-protocols", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/SupportedProtocolUpdate_LTE3Njk3MDM4" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Supported protocols changed" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "mls-protocol-error", + "message": "MLS protocol cannot be removed" + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-protocol-error" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "MLS protocol cannot be removed (label: `mls-protocol-error`)" + } + }, + "summary": "Change your supported protocols" + } + }, + "/services": { + "get": { + "description": " [internal route ID: \"get-services\"]\n\n", + "operationId": "get-services", + "parameters": [ + { + "in": "query", + "name": "tags", + "required": false, + "schema": { + "enum": [ + "audio", + "books", + "business", + "design", + "education", + "entertainment", + "finance", + "fitness", + "food-drink", + "games", + "graphics", + "health", + "integration", + "lifestyle", + "media", + "medical", + "movies", + "music", + "news", + "photography", + "poll", + "productivity", + "quiz", + "rating", + "shopping", + "social", + "sports", + "travel", + "tutorial", + "video", + "weather" + ], + "type": "string" + } + }, + { + "in": "query", + "name": "start", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "size", + "required": false, + "schema": { + "format": "int32", + "maximum": 100, + "minimum": 10, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ServiceProfilePage_Njg1NDQ5Njc4" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + } + }, + "summary": "List services" + } + }, + "/services/tags": { + "get": { + "description": " [internal route ID: \"get-services-tags\"]\n\n", + "operationId": "get-services-tags", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ServiceTagList" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "Access denied." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Access denied. (label: `access-denied`)" + } + }, + "summary": "Get services tags" + } + }, + "/sso/finalize-login": { + "post": { + "deprecated": true, + "description": " [internal route ID: \"auth-resp-legacy\"]\n\nDEPRECATED! use /sso/metadata/:tid instead! Details: https://docs.wire.com/understand/single-sign-on/trouble-shooting.html#can-i-use-the-same-sso-login-code-for-multiple-teams", + "operationId": "auth-resp-legacy", + "responses": { + "200": { + "content": { + "text/plain;charset=utf-8": { + "schema": { + "type": "string" + } + } + }, + "description": "" + } + } + } + }, + "/sso/finalize-login/{team}": { + "post": { + "description": " [internal route ID: \"auth-resp\"]\n\n", + "operationId": "auth-resp", + "parameters": [ + { + "in": "path", + "name": "team", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "text/plain;charset=utf-8": { + "schema": { + "type": "string" + } + } + }, + "description": "" + } + } + } + }, + "/sso/get-by-email": { + "post": { + "description": " [internal route ID: \"sso-get-by-email\"]\n\n", + "operationId": "sso-get-by-email", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/GetByEmailReq_LTY4MzE3Njgy" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetByEmailResp_LTMxNTY3MjA0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/GetByEmailResp_LTMxNTY3MjA0" + } + } + }, + "description": "SSO code found" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetByEmailResp_LTMxNTY3MjA0" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/GetByEmailResp_LTMxNTY3MjA0" + } + } + }, + "description": "SSO code not found or feature disabled" + } + } + } + }, + "/sso/initiate-login/{idp}": { + "get": { + "description": " [internal route ID: \"auth-req\"]\n\n", + "operationId": "auth-req", + "parameters": [ + { + "in": "query", + "name": "success_redirect", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "error_redirect", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "label", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "idp", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "text/html": { + "schema": { + "$ref": "#/components/schemas/FormRedirect" + } + } + }, + "description": "" + } + } + }, + "head": { + "description": " [internal route ID: \"auth-req-precheck\"]\n\n", + "operationId": "auth-req-precheck", + "parameters": [ + { + "in": "query", + "name": "success_redirect", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "error_redirect", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "label", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "idp", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "text/plain;charset=utf-8": {} + }, + "description": "" + } + } + } + }, + "/sso/metadata": { + "get": { + "deprecated": true, + "description": " [internal route ID: \"sso-metadata\"]\n\nDEPRECATED! use /sso/metadata/:tid instead! Details: https://docs.wire.com/understand/single-sign-on/trouble-shooting.html#can-i-use-the-same-sso-login-code-for-multiple-teams", + "operationId": "sso-metadata", + "responses": { + "200": { + "content": { + "application/xml": { + "schema": { + "type": "string" + } + } + }, + "description": "" + } + } + } + }, + "/sso/metadata/{team}": { + "get": { + "description": " [internal route ID: \"sso-team-metadata\"]\n\n", + "operationId": "sso-team-metadata", + "parameters": [ + { + "in": "path", + "name": "team", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/xml": { + "schema": { + "type": "string" + } + } + }, + "description": "" + } + } + } + }, + "/sso/settings": { + "get": { + "description": " [internal route ID: \"sso-settings\"]\n\n", + "operationId": "sso-settings", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/SsoSettings" + } + } + }, + "description": "" + } + } + } + }, + "/system/settings": { + "get": { + "description": " [internal route ID: \"get-system-settings\"]\n\n", + "operationId": "get-system-settings", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/SystemSettings_ODU3MDk5MTA3" + } + } + }, + "description": "" + } + }, + "summary": "Returns a curated set of system configuration settings for authorized users." + } + }, + "/system/settings/unauthorized": { + "get": { + "description": " [internal route ID: \"get-system-settings-unauthorized\"]\n\n", + "operationId": "get-system-settings-unauthorized", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/SystemSettingsPublic_LTgwNTMxNjU2" + } + } + }, + "description": "" + } + }, + "summary": "Returns a curated set of system configuration settings." + } + }, + "/teams/invitations/accept": { + "post": { + "description": " [internal route ID: \"accept-team-invitation\"]\n\n", + "operationId": "accept-team-invitation", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/AcceptTeamInvitation_Nzg5NzI3MjA2" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Team invitation accepted." + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "missing-auth", + "message": "Re-authentication via password required" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "missing-auth", + "invalid-credentials", + "missing-identity", + "too-many-team-members" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Re-authentication via password required (label: `missing-auth`)\n\nAuthentication failed (label: `invalid-credentials`)\n\nUsing an invitation code requires registering the given email. (label: `missing-identity`)\n\nToo many members in this team. (label: `too-many-team-members`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "invalid-code", + "message": "Invalid activation code" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-code", + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid activation code (label: `invalid-code`)\n\nUser does not exist (label: `invalid-code`)\n\nNo pending invitations exists. (label: `not-found`)" + } + }, + "summary": "Accept a team invitation, changing a personal account into a team member account." + } + }, + "/teams/invitations/by-email": { + "head": { + "description": " [internal route ID: \"head-team-invitations\"]\n\n", + "operationId": "head-team-invitations", + "parameters": [ + { + "description": "Email address", + "in": "query", + "name": "email", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Pending invitation exists." + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "No pending invitations exists." + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "No pending invitations exists." + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "No pending invitations exists. (label: `not-found`)" + }, + "409": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 409, + "label": "conflicting-invitations", + "message": "Multiple conflicting invitations to different teams exists." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "conflicting-invitations" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "conflicting-invitations", + "message": "Multiple conflicting invitations to different teams exists." + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "conflicting-invitations" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Multiple conflicting invitations to different teams exists. (label: `conflicting-invitations`)" + } + }, + "summary": "Check if there is an invitation pending given an email address." + } + }, + "/teams/invitations/info": { + "get": { + "description": " [internal route ID: \"get-team-invitation-info\"]\n\n", + "operationId": "get-team-invitation-info", + "parameters": [ + { + "description": "Invitation code", + "in": "query", + "name": "code", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvitationUserView_LTUyMTE3Nzkz" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/InvitationUserView_LTUyMTE3Nzkz" + } + } + }, + "description": "Invitation info" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-invitation-code", + "message": "Invalid invitation code." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-invitation-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `code`\n\nInvalid invitation code. (label: `invalid-invitation-code`)" + } + }, + "summary": "Get invitation info given a code." + } + }, + "/teams/notifications": { + "get": { + "description": " [internal route ID: \"get-team-notifications\"]\n\n

This is a work-around for scalability issues with gundeck user event fan-out. It does not track all team-wide events, but only `member-join`.

Note that `/teams/notifications` behaves differently from `/notifications`:

  • If there is a gap between the notification id requested with `since` and the available data, team queues respond with 200 and the data that could be found. They do NOT respond with status 404, but valid data in the body.\n
  • The notification with the id given via `since` is included in the response if it exists. You should remove this and only use it to decide whether there was a gap between your last request and this one.\n
  • If the notification id does *not* exist, you get the more recent events from the queue (instead of all of them). This can be done because a notification id is a UUIDv1, which is essentially a time stamp.\n
  • There is no corresponding `/last` end-point to get only the most recent event. That end-point was only useful to avoid having to pull the entire queue. In team queues, if you have never requested the queue before and have no prior notification id, just pull with timestamp 'now'.

See also: GET /notifications

", + "operationId": "get-team-notifications", + "parameters": [ + { + "description": "Notification id to start with in the response (UUIDv1)", + "in": "query", + "name": "since", + "required": false, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "description": "Maximum number of events to return (1..10000; default: 1000)", + "in": "query", + "name": "size", + "required": false, + "schema": { + "format": "int32", + "maximum": 10000, + "minimum": 1, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/QueuedNotificationList_MTU0ODEyNTQ2" + } + } + }, + "description": "" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-notification-id", + "message": "Could not parse notification id (must be UUIDv1)." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-notification-id" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `size` or `since`\n\nCould not parse notification id (must be UUIDv1). (label: `invalid-notification-id`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Team not found (label: `no-team`)" + } + }, + "summary": "Read recently added team members from team queue" + } + }, + "/teams/{team-id}/services/whitelist": { + "post": { + "description": " [internal route ID: \"post-team-whitelist-by-team-id\"]\n\n", + "operationId": "post-team-whitelist-by-team-id", + "parameters": [ + { + "in": "path", + "name": "team-id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UpdateServiceWhitelist_LTU5MDAwMTIw" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "UpdateServiceWhitelistRespChanged" + }, + "204": { + "description": "UpdateServiceWhitelistRespUnchanged" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "mls-services-not-allowed", + "message": "Services not allowed in MLS" + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-services-not-allowed" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Services not allowed in MLS (label: `mls-services-not-allowed`)" + } + }, + "summary": "Update service whitelist" + } + }, + "/teams/{team-id}/services/whitelisted": { + "get": { + "description": " [internal route ID: \"get-whitelisted-services-by-team-id\"]\n\n", + "operationId": "get-whitelisted-services-by-team-id", + "parameters": [ + { + "in": "path", + "name": "team-id", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "query", + "name": "prefix", + "required": false, + "schema": { + "maxLength": 128, + "minLength": 1, + "type": "string" + } + }, + { + "in": "query", + "name": "filter_disabled", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "in": "query", + "name": "size", + "required": false, + "schema": { + "format": "int32", + "maximum": 100, + "minimum": 10, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ServiceProfilePage_Njg1NDQ5Njc4" + } + } + }, + "description": "" + } + }, + "summary": "Get whitelisted services by team id" + } + }, + "/teams/{teamId}/registered-domains": { + "get": { + "description": " [internal route ID: \"get-all-registered-domains\"]\n\n", + "operationId": "get-all-registered-domains", + "parameters": [ + { + "in": "path", + "name": "teamId", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/RegisteredDomains_V10_NDYwNzYyMTMy" + } + } + }, + "description": "" + } + }, + "summary": "Get all registered domains" + } + }, + "/teams/{teamId}/registered-domains/{domain}": { + "delete": { + "description": " [internal route ID: \"delete-registered-domain\"]\n\n", + "operationId": "delete-registered-domain", + "parameters": [ + { + "in": "path", + "name": "teamId", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Deleted" + }, + "402": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 402, + "label": "domain-registration-update-payment-required", + "message": "Domain registration updated payment required" + }, + "properties": { + "code": { + "enum": [ + 402 + ], + "type": "integer" + }, + "label": { + "enum": [ + "domain-registration-update-payment-required" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Domain registration updated payment required (label: `domain-registration-update-payment-required`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "operation-forbidden-for-domain-registration-state", + "message": "Invalid domain registration state update" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "operation-forbidden-for-domain-registration-state" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid domain registration state update (label: `operation-forbidden-for-domain-registration-state`)" + } + }, + "summary": "Delete a registered domain" + } + }, + "/teams/{tid}": { + "delete": { + "description": " [internal route ID: \"delete-team\"]\n\n", + "operationId": "delete-team", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/TeamDeleteData_ODI5NTU0ODE5" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Team is scheduled for removal" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "code-authentication-required", + "message": "Verification code required" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "code-authentication-required", + "code-authentication-failed", + "access-denied", + "operation-denied", + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Verification code required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nThis operation requires reauthentication (label: `access-denied`)\n\nInsufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (missing DeleteTeam) (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + }, + "429": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 429, + "label": "too-many-requests", + "message": "Please try again later." + }, + "properties": { + "code": { + "enum": [ + 429 + ], + "type": "integer" + }, + "label": { + "enum": [ + "too-many-requests" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Please try again later. (label: `too-many-requests`)" + }, + "503": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 503, + "label": "queue-full", + "message": "The delete queue is full; no further delete requests can be processed at the moment" + }, + "properties": { + "code": { + "enum": [ + 503 + ], + "type": "integer" + }, + "label": { + "enum": [ + "queue-full" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "The delete queue is full; no further delete requests can be processed at the moment (label: `queue-full`)" + } + }, + "summary": "Delete a team" + }, + "get": { + "description": " [internal route ID: \"get-team\"]\n\n", + "operationId": "get-team", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Team_NDg4MjQwOTIw" + } + } + }, + "description": "" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get a team by ID" + }, + "put": { + "description": " [internal route ID: \"update-team\"]\n\n", + "operationId": "update-team", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/TeamUpdateData_LTE0NTM2NTU5" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Team updated" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "operation-denied", + "message": "Insufficient permissions (missing SetTeamData)" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "operation-denied", + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Insufficient permissions (missing SetTeamData) (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" + } + }, + "summary": "Update team properties" + } + }, + "/teams/{tid}/apps": { + "get": { + "description": " [internal route ID: \"get-apps\"]\n\n", + "operationId": "get-apps", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/UserProfile_LTQzMTQxMTE1" + }, + "type": "array" + } + } + }, + "description": "" + } + }, + "summary": "Get all apps owned by the given team (not including collaborators)" + }, + "post": { + "description": " [internal route ID: \"create-app\"]\n\n", + "operationId": "create-app", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewApp_LTQwODMwMzQ4" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CreatedApp_LTM3NjUxOTY1" + } + } + }, + "description": "" + } + }, + "summary": "Create a new app" + } + }, + "/teams/{tid}/apps/{app}": { + "put": { + "description": " [internal route ID: \"put-app\"]\n\n", + "operationId": "put-app", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "app", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PutApp_LTE4MDc1OTM4" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + } + }, + "description": "" + } + }, + "summary": "Update metadata of an existing app" + } + }, + "/teams/{tid}/apps/{app}/cookies": { + "post": { + "description": " [internal route ID: \"refresh-app-cookie\"]\n\n", + "operationId": "refresh-app-cookie", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "app", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/RefreshAppCookieRequest_MjEyMDMyMTk5" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/RefreshAppCookieResponse_LTQ0MjU1NTIw" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "missing-auth", + "message": "Re-authentication via password required" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "missing-auth" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Re-authentication via password required (label: `missing-auth`)" + } + }, + "summary": "Get a new app authentication token" + } + }, + "/teams/{tid}/channels/search": { + "get": { + "description": " [internal route ID: \"search-channels\"]\n\n", + "operationId": "search-channels", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "description": "Search string", + "in": "query", + "name": "q", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "sort_order", + "required": false, + "schema": { + "enum": [ + "asc", + "desc" + ], + "type": "string" + } + }, + { + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "description": "integer from [1..500]", + "type": "number" + } + }, + { + "description": "`name` of the last seen channel of the current page, used to get the next page.", + "in": "query", + "name": "last_seen_name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "`id` of the last seen channel, used to get the next page, used as a tie breaker. **Must** be sent to get the next page.", + "in": "query", + "name": "last_seen_id", + "required": false, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "allowEmptyValue": true, + "in": "query", + "name": "discoverable", + "schema": { + "default": false, + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationPage_LTIwMDU2NDI3" + } + } + }, + "description": "" + } + }, + "summary": "Search channels" + } + }, + "/teams/{tid}/collaborators": { + "get": { + "description": " [internal route ID: \"get-team-collaborators\"]\n\n", + "operationId": "get-team-collaborators", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/TeamCollaborator_LTI3MzM1MTYz" + }, + "type": "array" + } + }, + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/TeamCollaborator_LTI3MzM1MTYz" + }, + "type": "array" + } + } + }, + "description": "Return collaborators" + } + }, + "summary": "Get all collaborators of the team." + }, + "post": { + "description": " [internal route ID: \"add-team-collaborator\"]\n\n", + "operationId": "add-team-collaborator", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewTeamCollaborator_LTIxNjEzMTYw" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "" + } + }, + "summary": "Add a collaborator to the team." + } + }, + "/teams/{tid}/collaborators/{uid}": { + "delete": { + "description": " [internal route ID: \"remove-team-collaborator\"]\n\n", + "operationId": "remove-team-collaborator", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + } + }, + "summary": "Remove a collaborator from the team." + }, + "put": { + "description": " [internal route ID: \"update-team-collaborator\"]\n\n", + "operationId": "update-team-collaborator", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/CollaboratorPermission_NDg5NTg2ODgy" + }, + "type": "array", + "uniqueItems": true + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "" + } + }, + "summary": "Update a collaborator permissions from the team." + } + }, + "/teams/{tid}/conversations": { + "get": { + "description": " [internal route ID: \"get-team-conversations\"]\n\n", + "operationId": "get-team-conversations", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/TeamConversationList_OTI3MzY3NzY0" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + } + }, + "summary": "Get team conversations" + } + }, + "/teams/{tid}/conversations/roles": { + "get": { + "description": " [internal route ID: \"get-team-conversation-roles\"]\n\n", + "operationId": "get-team-conversation-roles", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ConversationRolesList" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)" + } + }, + "summary": "Get existing roles available for the given team" + } + }, + "/teams/{tid}/conversations/{cid}": { + "delete": { + "description": " [internal route ID: \"delete-team-conversation\"]\n\n", + "operationId": "delete-team-conversation", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "cid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Conversation deleted" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "invalid-op", + "action-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInvalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing delete_conversation) (label: `action-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` or `cid` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Remove a team conversation" + }, + "get": { + "description": " [internal route ID: \"get-team-conversation\"]\n\n", + "operationId": "get-team-conversation", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "cid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/TeamConversation_LTIwNzgyNTEz" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-conversation", + "message": "Conversation not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-conversation" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` or `cid` not found\n\nConversation not found (label: `no-conversation`)" + } + }, + "summary": "Get one team conversation" + } + }, + "/teams/{tid}/features": { + "get": { + "description": " [internal route ID: \"get-all-feature-configs-for-team\"]\n\nGets feature configs for a team. User must be a member of the team and have permission to view team features.", + "operationId": "get-all-feature-configs-for-team", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NP_LockableFtur_ghdCnfiSOVsyAvIRqExmDpB_MGwUT2Q_LTM1Mzc0ODgy" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "operation-denied", + "message": "Insufficient permissions" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "operation-denied", + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Gets feature configs for a team" + } + }, + "/teams/{tid}/features/allowedGlobalOperations": { + "get": { + "description": " [internal route ID: (\"get\", AllowedGlobalOperationsConfig)]\n\n", + "operationId": "get_AllowedGlobalOperationsConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_AllowedGlobalOperationsConfig_NjQ1MjA5MDYw" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for allowedGlobalOperations" + } + }, + "/teams/{tid}/features/appLock": { + "get": { + "description": " [internal route ID: (\"get\", AppLockConfigB)]\n\n", + "operationId": "get_AppLockConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_AppLockConfigB_Bare_Identity_ODgzNDI0OTU5" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for appLock" + }, + "put": { + "description": " [internal route ID: (\"put\", AppLockConfigB)]\n\n", + "operationId": "put_AppLockConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_AppLockConfigB_Bare_Identity_MTAzMjI5NDYy" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_AppLockConfigB_Bare_Identity_ODgzNDI0OTU5" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for appLock" + } + }, + "/teams/{tid}/features/apps": { + "get": { + "description": " [internal route ID: (\"get\", AppsConfig)]\n\n", + "operationId": "get_AppsConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_AppsConfig_MzQyNTMxNTk5" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for apps" + } + }, + "/teams/{tid}/features/assetAuditLog": { + "get": { + "description": " [internal route ID: (\"get\", AssetAuditLogConfig)]\n\n", + "operationId": "get_AssetAuditLogConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_AssetAuditLogConfig_NDQ3MzcyMzk2" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for assetAuditLog" + } + }, + "/teams/{tid}/features/cells": { + "get": { + "description": " [internal route ID: (\"get\", CellsConfigB)]\n\n", + "operationId": "get_CellsConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_CellsConfigB_Bare_Identity_LTgzMDA1NjI3" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for cells" + }, + "put": { + "description": " [internal route ID: (\"put\", CellsConfigB)]\n\n", + "operationId": "put_CellsConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_CellsConfigB_Bare_Identity_NzU2NjgxNzEw" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_CellsConfigB_Bare_Identity_LTgzMDA1NjI3" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for cells" + } + }, + "/teams/{tid}/features/cellsInternal": { + "get": { + "description": " [internal route ID: (\"get\", CellsInternalConfigB)]\n\n", + "operationId": "get_CellsInternalConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_CsInfigBdy_LTQ3MTU3Mjg0" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for cellsInternal" + } + }, + "/teams/{tid}/features/channels": { + "get": { + "description": " [internal route ID: (\"get\", ChannelsConfigB)]\n\n", + "operationId": "get_ChannelsConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_ChannelsConfigB_Bare_Identity_NzA2NDEyMDEw" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for channels" + }, + "put": { + "description": " [internal route ID: (\"put\", ChannelsConfigB)]\n\n", + "operationId": "put_ChannelsConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_ChannelsConfigB_Bare_Identity_LTU4NTE4MTgx" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_ChannelsConfigB_Bare_Identity_NzA2NDEyMDEw" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for channels" + } + }, + "/teams/{tid}/features/chatBubbles": { + "get": { + "description": " [internal route ID: (\"get\", ChatBubblesConfig)]\n\n", + "operationId": "get_ChatBubblesConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_ChatBubblesConfig_NDgwMTQzNjI2" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for chatBubbles" + } + }, + "/teams/{tid}/features/classifiedDomains": { + "get": { + "description": " [internal route ID: (\"get\", ClassifiedDomainsConfig)]\n\n", + "operationId": "get_ClassifiedDomainsConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_ClassifiedDomainsConfig_LTY1ODQwODg1" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for classifiedDomains" + } + }, + "/teams/{tid}/features/conferenceCalling": { + "get": { + "description": " [internal route ID: (\"get\", ConferenceCallingConfigB)]\n\n", + "operationId": "get_ConferenceCallingConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_CnfigBIdy_NzY1NDU5MDAy" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for conferenceCalling" + }, + "put": { + "description": " [internal route ID: (\"put\", ConferenceCallingConfigB)]\n\n", + "operationId": "put_ConferenceCallingConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_ConferenceCallingConfigB_Bare_Identity_Njc2NTcxNTI3" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_CnfigBIdy_NzY1NDU5MDAy" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for conferenceCalling" + } + }, + "/teams/{tid}/features/consumableNotifications": { + "get": { + "description": " [internal route ID: (\"get\", ConsumableNotificationsConfig)]\n\n", + "operationId": "get_ConsumableNotificationsConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_ConsumableNotificationsConfig_MjUxMjczMjM0" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for consumableNotifications" + } + }, + "/teams/{tid}/features/conversationGuestLinks": { + "get": { + "description": " [internal route ID: (\"get\", GuestLinksConfig)]\n\n", + "operationId": "get_GuestLinksConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_GuestLinksConfig_LTcwNjU0NDMw" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for conversationGuestLinks" + }, + "put": { + "description": " [internal route ID: (\"put\", GuestLinksConfig)]\n\n", + "operationId": "put_GuestLinksConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_GuestLinksConfig_NjQyMDMxNjg3" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_GuestLinksConfig_LTcwNjU0NDMw" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for conversationGuestLinks" + } + }, + "/teams/{tid}/features/digitalSignatures": { + "get": { + "description": " [internal route ID: (\"get\", DigitalSignaturesConfig)]\n\n", + "operationId": "get_DigitalSignaturesConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_DigitalSignaturesConfig_ODM2MDA2NDU4" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for digitalSignatures" + } + }, + "/teams/{tid}/features/domainRegistration": { + "get": { + "description": " [internal route ID: (\"get\", DomainRegistrationConfig)]\n\n", + "operationId": "get_DomainRegistrationConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_DomainRegistrationConfig_NzU0NjczNTE0" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for domainRegistration" + } + }, + "/teams/{tid}/features/enforceFileDownloadLocation": { + "get": { + "description": " [internal route ID: (\"get\", EnforceFileDownloadLocationConfigB)]\n\n

Custom feature: only supported on some dedicated on-prem systems.

", + "operationId": "get_EnforceFileDownloadLocationConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_EnfiDwdCgBIy_ODA5OTA5MTQ4" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for enforceFileDownloadLocation" + }, + "put": { + "description": " [internal route ID: (\"put\", EnforceFileDownloadLocationConfigB)]\n\n

Custom feature: only supported on some dedicated on-prem systems.

", + "operationId": "put_EnforceFileDownloadLocationConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Featur_EnfocilDwdLCgBIy_MjcxMzc1NDA5" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_EnfiDwdCgBIy_ODA5OTA5MTQ4" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for enforceFileDownloadLocation" + } + }, + "/teams/{tid}/features/exposeInvitationURLsToTeamAdmin": { + "get": { + "description": " [internal route ID: (\"get\", ExposeInvitationURLsToTeamAdminConfig)]\n\n", + "operationId": "get_ExposeInvitationURLsToTeamAdminConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_ExpsInviURTmAdCfg_LTQzMzU2OTY1" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for exposeInvitationURLsToTeamAdmin" + }, + "put": { + "description": " [internal route ID: (\"put\", ExposeInvitationURLsToTeamAdminConfig)]\n\n", + "operationId": "put_ExposeInvitationURLsToTeamAdminConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_ExposeInvitationURLsToTeamAdminConfig_LTY5NzY2Mzg5" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_ExpsInviURTmAdCfg_LTQzMzU2OTY1" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for exposeInvitationURLsToTeamAdmin" + } + }, + "/teams/{tid}/features/fileSharing": { + "get": { + "description": " [internal route ID: (\"get\", FileSharingConfig)]\n\n", + "operationId": "get_FileSharingConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_FileSharingConfig_MjgwNjIzODEz" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for fileSharing" + }, + "put": { + "description": " [internal route ID: (\"put\", FileSharingConfig)]\n\n", + "operationId": "put_FileSharingConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_FileSharingConfig_LTUyNjkxMzM4" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_FileSharingConfig_MjgwNjIzODEz" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for fileSharing" + } + }, + "/teams/{tid}/features/legalhold": { + "get": { + "description": " [internal route ID: (\"get\", LegalholdConfig)]\n\n", + "operationId": "get_LegalholdConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_LegalholdConfig_LTc5MTk5OTIw" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for legalhold" + }, + "put": { + "description": " [internal route ID: (\"put\", LegalholdConfig)]\n\n", + "operationId": "put_LegalholdConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_LegalholdConfig_NjM3MTkxNjYw" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_LegalholdConfig_LTc5MTk5OTIw" + } + } + }, + "description": "" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "legalhold-not-registered", + "message": "legal hold service has not been registered for this team" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-not-registered" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nlegal hold service has not been registered for this team (label: `legalhold-not-registered`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "legalhold-disable-unimplemented", + "message": "legal hold cannot be disabled for whitelisted teams" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-disable-unimplemented", + "legalhold-not-enabled", + "too-large-team-for-legalhold", + "action-denied", + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "legal hold cannot be disabled for whitelisted teams (label: `legalhold-disable-unimplemented`)\n\nlegal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nCannot enable legalhold on large teams (reason: for removing LH from team, we need to iterate over all members, which is only supported for teams with less than 2k members) (label: `too-large-team-for-legalhold`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + }, + "500": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 500, + "label": "legalhold-internal", + "message": "legal hold service: could not block connections when resolving policy conflicts." + }, + "properties": { + "code": { + "enum": [ + 500 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-internal", + "legalhold-illegal-op" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "legal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)\n\ninternal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)" + } + }, + "summary": "Put config for legalhold" + } + }, + "/teams/{tid}/features/limitedEventFanout": { + "get": { + "description": " [internal route ID: (\"get\", LimitedEventFanoutConfig)]\n\n", + "operationId": "get_LimitedEventFanoutConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_LimitedEventFanoutConfig_MTg3ODM0NzU0" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for limitedEventFanout" + } + }, + "/teams/{tid}/features/meetings": { + "get": { + "description": " [internal route ID: (\"get\", MeetingsConfig)]\n\n", + "operationId": "get_MeetingsConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_MeetingsConfig_LTE0OTQ5Nzcw" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for meetings" + }, + "put": { + "description": " [internal route ID: (\"put\", MeetingsConfig)]\n\n", + "operationId": "put_MeetingsConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_MeetingsConfig_NDc2MzM0MDE1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_MeetingsConfig_LTE0OTQ5Nzcw" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for meetings" + } + }, + "/teams/{tid}/features/mls": { + "get": { + "description": " [internal route ID: (\"get\", MLSConfigB)]\n\n", + "operationId": "get_MLSConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_MLSConfigB_Bare_Identity_MTg1MTc0NTEw" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for mls" + }, + "put": { + "description": " [internal route ID: (\"put\", MLSConfigB)]\n\n", + "operationId": "put_MLSConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_MLSConfigB_Bare_Identity_LTI5MjA3MDYy" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_MLSConfigB_Bare_Identity_MTg1MTc0NTEw" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for mls" + } + }, + "/teams/{tid}/features/mlsE2EId": { + "get": { + "description": " [internal route ID: (\"get\", MlsE2EIdConfigB)]\n\n", + "operationId": "get_MlsE2EIdConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_MlsE2EIdConfigB_Bare_Identity_MTU2ODkyMDc4" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for mlsE2EId" + }, + "put": { + "description": " [internal route ID: (\"put\", MlsE2EIdConfigB)]\n\n", + "operationId": "put_MlsE2EIdConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_MlsE2EIdConfigB_Bare_Identity_LTUxODYzODEx" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_MlsE2EIdConfigB_Bare_Identity_MTU2ODkyMDc4" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for mlsE2EId" + } + }, + "/teams/{tid}/features/mlsMigration": { + "get": { + "description": " [internal route ID: (\"get\", MlsMigrationConfigB)]\n\n", + "operationId": "get_MlsMigrationConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_MsignCfBIdy_LTE1NjAxNjU2" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for mlsMigration" + }, + "put": { + "description": " [internal route ID: (\"put\", MlsMigrationConfigB)]\n\n", + "operationId": "put_MlsMigrationConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_MlsMigrationConfigB_Bare_Identity_LTQyMDAxMTkz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_MsignCfBIdy_LTE1NjAxNjU2" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for mlsMigration" + } + }, + "/teams/{tid}/features/outlookCalIntegration": { + "get": { + "description": " [internal route ID: (\"get\", OutlookCalIntegrationConfig)]\n\n", + "operationId": "get_OutlookCalIntegrationConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_OutlookCalIntegrationConfig_NjQ0MzMyMzY0" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for outlookCalIntegration" + }, + "put": { + "description": " [internal route ID: (\"put\", OutlookCalIntegrationConfig)]\n\n", + "operationId": "put_OutlookCalIntegrationConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_OutlookCalIntegrationConfig_LTg0MjIxNTMx" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_OutlookCalIntegrationConfig_NjQ0MzMyMzY0" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for outlookCalIntegration" + } + }, + "/teams/{tid}/features/preventAdminlessGroups": { + "get": { + "description": " [internal route ID: (\"get\", PreventAdminlessGroupsConfigB)]\n\n", + "operationId": "get_PreventAdminlessGroupsConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_PvnAdmisGpCfgBIy_MTQxOTU4Mzgw" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for preventAdminlessGroups" + }, + "put": { + "description": " [internal route ID: \"put-PreventAdminlessGroupsConfig@v18\"]\n\n

For API version 18, use duration strings for the timeout fields. The request body must have the following shape:

{\n  "config": {\n    "deletionTimeoutDuration": "7d",\n    "promotionStrategy": "alphabetical",\n    "reminderTimeoutDurations": [\n      "2d",\n      "4d",\n      "6d"\n    ]\n  },\n  "status": "enabled"\n}

Older API versions use the legacy numeric fields deletionTimeout and reminderTimeouts.

", + "operationId": "put-PreventAdminlessGroupsConfig@v18", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Featur_Vsiond_18PvAmlGpCfgBIy_MjUwNjk2MjQwV18" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_PvnAdmisGpCfgBIy_MTQxOTU4Mzgw" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for preventAdminlessGroups" + } + }, + "/teams/{tid}/features/searchVisibility": { + "get": { + "description": " [internal route ID: (\"get\", SearchVisibilityAvailableConfig)]\n\n", + "operationId": "get_SearchVisibilityAvailableConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_SearchVisibilityAvailableConfig_LTkxMTA5ODk5" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for searchVisibility" + }, + "put": { + "description": " [internal route ID: (\"put\", SearchVisibilityAvailableConfig)]\n\n", + "operationId": "put_SearchVisibilityAvailableConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_SearchVisibilityAvailableConfig_LTMzNTkxODI1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_SearchVisibilityAvailableConfig_LTkxMTA5ODk5" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for searchVisibility" + } + }, + "/teams/{tid}/features/searchVisibilityInbound": { + "get": { + "description": " [internal route ID: (\"get\", SearchVisibilityInboundConfig)]\n\n", + "operationId": "get_SearchVisibilityInboundConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_SearchVisibilityInboundConfig_NzA5NzczNTgy" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for searchVisibilityInbound" + }, + "put": { + "description": " [internal route ID: (\"put\", SearchVisibilityInboundConfig)]\n\n", + "operationId": "put_SearchVisibilityInboundConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_SearchVisibilityInboundConfig_MTI1NzQxODY2" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_SearchVisibilityInboundConfig_NzA5NzczNTgy" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for searchVisibilityInbound" + } + }, + "/teams/{tid}/features/selfDeletingMessages": { + "get": { + "description": " [internal route ID: (\"get\", SelfDeletingMessagesConfigB)]\n\n", + "operationId": "get_SelfDeletingMessagesConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_SfDingMsCBIdy_LTg5MTEwNTA2" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for selfDeletingMessages" + }, + "put": { + "description": " [internal route ID: (\"put\", SelfDeletingMessagesConfigB)]\n\n", + "operationId": "put_SelfDeletingMessagesConfigB", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Featur_SlfDingMsCoBIdy_LTg2MzYzNjc2" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_SfDingMsCBIdy_LTg5MTEwNTA2" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for selfDeletingMessages" + } + }, + "/teams/{tid}/features/simplifiedUserConnectionRequestQRCode": { + "get": { + "description": " [internal route ID: (\"get\", SimplifiedUserConnectionRequestQRCodeConfig)]\n\n", + "operationId": "get_SimplifiedUserConnectionRequestQRCodeConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_SimpfdUsCnRqQg_Njk5NjU4OTgy" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for simplifiedUserConnectionRequestQRCode" + } + }, + "/teams/{tid}/features/sndFactorPasswordChallenge": { + "get": { + "description": " [internal route ID: (\"get\", SndFactorPasswordChallengeConfig)]\n\n", + "operationId": "get_SndFactorPasswordChallengeConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_SndFactorPasswordChallengeConfig_MjQ3NzQ2ODgx" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for sndFactorPasswordChallenge" + }, + "put": { + "description": " [internal route ID: (\"put\", SndFactorPasswordChallengeConfig)]\n\n", + "operationId": "put_SndFactorPasswordChallengeConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Feature_SndFactorPasswordChallengeConfig_NDc0MzUyMzQz" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_SndFactorPasswordChallengeConfig_MjQ3NzQ2ODgx" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Put config for sndFactorPasswordChallenge" + } + }, + "/teams/{tid}/features/sso": { + "get": { + "description": " [internal route ID: (\"get\", SSOConfig)]\n\n", + "operationId": "get_SSOConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_SSOConfig_NjcyMjU4MDY2" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for sso" + } + }, + "/teams/{tid}/features/stealthUsers": { + "get": { + "description": " [internal route ID: (\"get\", StealthUsersConfig)]\n\n", + "operationId": "get_StealthUsersConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFeature_StealthUsersConfig_LTE1MTk2NzIz" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for stealthUsers" + } + }, + "/teams/{tid}/features/validateSAMLemails": { + "get": { + "description": " [internal route ID: (\"get\", RequireExternalEmailVerificationConfig)]\n\n

Controls whether externally managed email addresses (from SAML or SCIM) must be verified by the user, or are auto-activated.

The external feature name is kept as validateSAMLemails for backward compatibility. That name is misleading because the feature also applies to SCIM-managed users, and it controls email ownership verification rather than generic email validation.

", + "operationId": "get_RequireExternalEmailVerificationConfig", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LockableFtur_RqiExnmVfCg_NjUyMzgzNzY5" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "operation-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Get config for validateSAMLemails" + } + }, + "/teams/{tid}/get-members-by-ids-using-post": { + "post": { + "description": " [internal route ID: \"get-team-members-by-ids\"]\n\nThe `has_more` field in the response body is always `false`.", + "operationId": "get-team-members-by-ids", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "description": "Maximum results to be returned", + "in": "query", + "name": "maxResults", + "required": false, + "schema": { + "format": "int32", + "maximum": 2000, + "minimum": 1, + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserIdList_MzA1MTI1Njgx" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/TeamMemberList_Optional_LTM1ODE2MzM0" + } + } + }, + "description": "" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "too-many-uids", + "message": "Can only process 2000 user ids per request." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "too-many-uids" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body` or `maxResults`\n\nCan only process 2000 user ids per request. (label: `too-many-uids`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)" + } + }, + "summary": "Get team members by user id list" + } + }, + "/teams/{tid}/invitations": { + "get": { + "description": " [internal route ID: \"get-team-invitations\"]\n\n", + "operationId": "get-team-invitations", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "description": "Invitation id to start from (ascending).", + "in": "query", + "name": "start", + "required": false, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "description": "Number of results to return (default 100, max 500).", + "in": "query", + "name": "size", + "required": false, + "schema": { + "format": "int32", + "maximum": 500, + "minimum": 1, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvitationList_ODk4NTQxODc3" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/InvitationList_ODk4NTQxODc3" + } + } + }, + "description": "List of sent invitations" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "insufficient-permissions", + "message": "Insufficient team permissions" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "insufficient-permissions" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Insufficient team permissions (label: `insufficient-permissions`)" + } + }, + "summary": "List the sent team invitations" + }, + "post": { + "description": " [internal route ID: \"send-team-invitation\"]\n\nInvitations are sent by email. The maximum allowed number of pending team invitations is equal to the team size.", + "operationId": "send-team-invitation", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/InvitationRequest_LTcyMDIzNDc0" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Invitation_NTkzMDYwODc1" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Invitation_NTkzMDYwODc1" + } + } + }, + "description": "Invitation was created and sent.", + "headers": { + "Location": { + "schema": { + "format": "url", + "type": "string" + } + } + } + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-invitation-code", + "message": "Invalid invitation code." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-invitation-code", + "invalid-email" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nInvalid invitation code. (label: `invalid-invitation-code`)\n\nInvalid e-mail address. (label: `invalid-email`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "insufficient-permissions", + "message": "Insufficient team permissions" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "insufficient-permissions", + "too-many-team-invitations", + "blacklisted-email", + "no-identity", + "no-email" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Insufficient team permissions (label: `insufficient-permissions`)\n\nToo many team invitations for this team (label: `too-many-team-invitations`)\n\nThe given e-mail address has been blacklisted due to a permanent bounce or a complaint. (label: `blacklisted-email`)\n\nThe user has no verified email (label: `no-identity`)\n\nThis operation requires the user to have a verified email address. (label: `no-email`)" + } + }, + "summary": "Create and send a new team invitation." + } + }, + "/teams/{tid}/invitations/{iid}": { + "delete": { + "description": " [internal route ID: \"delete-team-invitation\"]\n\n", + "operationId": "delete-team-invitation", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "iid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Invitation deleted" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "insufficient-permissions", + "message": "Insufficient team permissions" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "insufficient-permissions" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Insufficient team permissions (label: `insufficient-permissions`)" + } + }, + "summary": "Delete a pending team invitation by ID." + }, + "get": { + "description": " [internal route ID: \"get-team-invitation\"]\n\n", + "operationId": "get-team-invitation", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "iid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Invitation_NTkzMDYwODc1" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/Invitation_NTkzMDYwODc1" + } + } + }, + "description": "Invitation" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "insufficient-permissions", + "message": "Insufficient team permissions" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "insufficient-permissions" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Insufficient team permissions (label: `insufficient-permissions`)" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Notification not found." + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "Notification not found." + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` or `iid` or Notification not found. (label: `not-found`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "duplicate-entry", + "message": "Entry already exists" + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "duplicate-entry" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Entry already exists (label: `duplicate-entry`)" + } + }, + "summary": "Get a pending team invitation by ID." + } + }, + "/teams/{tid}/legalhold/consent": { + "post": { + "description": " [internal route ID: \"consent-to-legal-hold\"]\n\n", + "operationId": "consent-to-legal-hold", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "201": { + "description": "Grant consent successful" + }, + "204": { + "description": "Consent already granted" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "invalid-op", + "message": "Invalid operation" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-op", + "action-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team-member", + "message": "Team member not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam member not found (label: `no-team-member`)" + }, + "500": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 500, + "label": "legalhold-internal", + "message": "legal hold service: could not block connections when resolving policy conflicts." + }, + "properties": { + "code": { + "enum": [ + 500 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-internal", + "legalhold-illegal-op" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "legal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)\n\ninternal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)" + } + }, + "summary": "Consent to legal hold" + } + }, + "/teams/{tid}/legalhold/settings": { + "delete": { + "description": " [internal route ID: \"delete-legal-hold-settings\"]\n\nThis endpoint can lead to the following events being sent:\n- ClientRemoved event to members with a legalhold client (via brig)\n- UserLegalHoldDisabled event to contacts of members with a legalhold client (via brig)", + "operationId": "delete-legal-hold-settings", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/RemoveLegalHoldSettingsRequest_NzMzMzMyMDAz" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Legal hold service settings deleted" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "legalhold-not-registered", + "message": "legal hold service has not been registered for this team" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-not-registered" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nlegal hold service has not been registered for this team (label: `legalhold-not-registered`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "legalhold-disable-unimplemented", + "message": "legal hold cannot be disabled for whitelisted teams" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-disable-unimplemented", + "legalhold-not-enabled", + "invalid-op", + "action-denied", + "no-team-member", + "operation-denied", + "code-authentication-required", + "code-authentication-failed", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "legal hold cannot be disabled for whitelisted teams (label: `legalhold-disable-unimplemented`)\n\nlegal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nInvalid operation (label: `invalid-op`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient permissions (label: `operation-denied`)\n\nVerification code required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nThis operation requires reauthentication (label: `access-denied`)" + }, + "429": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 429, + "label": "too-many-requests", + "message": "Please try again later." + }, + "properties": { + "code": { + "enum": [ + 429 + ], + "type": "integer" + }, + "label": { + "enum": [ + "too-many-requests" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Please try again later. (label: `too-many-requests`)" + }, + "500": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 500, + "label": "legalhold-internal", + "message": "legal hold service: could not block connections when resolving policy conflicts." + }, + "properties": { + "code": { + "enum": [ + 500 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-internal", + "legalhold-illegal-op" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "legal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)\n\ninternal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)" + } + }, + "summary": "Delete legal hold service settings" + }, + "get": { + "description": " [internal route ID: \"get-legal-hold-settings\"]\n\n", + "operationId": "get-legal-hold-settings", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ViewLegalHoldService_LTE3MzQzNDkw" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "operation-denied", + "message": "Insufficient permissions" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "operation-denied", + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" + } + }, + "summary": "Get legal hold service settings" + }, + "post": { + "description": " [internal route ID: \"create-legal-hold-settings\"]\n\n", + "operationId": "create-legal-hold-settings", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewLegalHoldService_Mzg0ODQ5NDU1" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ViewLegalHoldService_LTE3MzQzNDkw" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ViewLegalHoldService_LTE3MzQzNDkw" + } + } + }, + "description": "Legal hold service settings created" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "legalhold-status-bad", + "message": "legal hold service: invalid response" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-status-bad", + "legalhold-invalid-key" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nlegal hold service: invalid response (label: `legalhold-status-bad`)\n\nlegal hold service pubkey is invalid (label: `legalhold-invalid-key`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "legalhold-not-enabled", + "message": "legal hold is not enabled for this team" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-not-enabled", + "operation-denied", + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "legal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nInsufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" + } + }, + "summary": "Create legal hold service settings" + } + }, + "/teams/{tid}/legalhold/{uid}": { + "delete": { + "description": " [internal route ID: \"disable-legal-hold-for-user\"]\n\nThis endpoint can lead to the following events being sent:\n- ClientRemoved event to the user owning the client (via brig)\n- UserLegalHoldDisabled event to contacts of the user owning the client (via brig)", + "operationId": "disable-legal-hold-for-user", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/DisableLegalHoldForUserRequest_LTYyMDYxOTEy" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Disable legal hold successful" + }, + "204": { + "description": "Legal hold was not enabled" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "legalhold-not-registered", + "message": "legal hold service has not been registered for this team" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-not-registered" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nlegal hold service has not been registered for this team (label: `legalhold-not-registered`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "operation-denied", + "message": "Insufficient permissions" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "operation-denied", + "no-team-member", + "action-denied", + "code-authentication-required", + "code-authentication-failed", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)\n\nVerification code required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nThis operation requires reauthentication (label: `access-denied`)" + }, + "429": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 429, + "label": "too-many-requests", + "message": "Please try again later." + }, + "properties": { + "code": { + "enum": [ + 429 + ], + "type": "integer" + }, + "label": { + "enum": [ + "too-many-requests" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Please try again later. (label: `too-many-requests`)" + }, + "500": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 500, + "label": "legalhold-internal", + "message": "legal hold service: could not block connections when resolving policy conflicts." + }, + "properties": { + "code": { + "enum": [ + 500 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-internal", + "legalhold-illegal-op" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "legal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)\n\ninternal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)" + } + }, + "summary": "Disable legal hold for user" + }, + "get": { + "description": " [internal route ID: \"get-legal-hold\"]\n\n", + "operationId": "get-legal-hold", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserLegalHoldStatusResponse_LTQ1MzUxMTE3" + } + } + }, + "description": "" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team-member", + "message": "Team member not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` or `uid` not found\n\nTeam member not found (label: `no-team-member`)" + } + }, + "summary": "Get legal hold status" + }, + "post": { + "description": " [internal route ID: \"request-legal-hold-device\"]\n\nThis endpoint can lead to the following events being sent:\n- LegalHoldClientRequested event to contacts of the user the device is requested for, if they didn't already have a legalhold client (via brig)", + "operationId": "request-legal-hold-device", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "201": { + "description": "Request device successful" + }, + "204": { + "description": "Request device already pending" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "legalhold-not-registered", + "message": "legal hold service has not been registered for this team" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-not-registered", + "legalhold-status-bad" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "legal hold service has not been registered for this team (label: `legalhold-not-registered`)\n\nlegal hold service: invalid response (label: `legalhold-status-bad`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "legalhold-not-enabled", + "message": "legal hold is not enabled for this team" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-not-enabled", + "operation-denied", + "no-team-member", + "action-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "legal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nInsufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team-member", + "message": "Team member not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` or `uid` not found\n\nTeam member not found (label: `no-team-member`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "mls-legal-hold-not-allowed", + "message": "A user who is under legal-hold may not participate in MLS conversations" + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "mls-legal-hold-not-allowed", + "legalhold-no-consent", + "legalhold-already-enabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "A user who is under legal-hold may not participate in MLS conversations (label: `mls-legal-hold-not-allowed`)\n\nuser has not given consent to using legal hold (label: `legalhold-no-consent`)\n\nlegal hold is already enabled for this user (label: `legalhold-already-enabled`)" + }, + "500": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 500, + "label": "legalhold-illegal-op", + "message": "internal server error: inconsistent change of user's legalhold state" + }, + "properties": { + "code": { + "enum": [ + 500 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-illegal-op", + "legalhold-internal" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "internal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)\n\nlegal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)" + } + }, + "summary": "Request legal hold device" + } + }, + "/teams/{tid}/legalhold/{uid}/approve": { + "put": { + "description": " [internal route ID: \"approve-legal-hold-device\"]\n\nThis endpoint can lead to the following events being sent:\n- ClientAdded event to the user owning the client (via brig)\n- UserLegalHoldEnabled event to contacts of the user owning the client (via brig)\n- ClientRemoved event to the user, if removing old client due to max number (via brig)", + "operationId": "approve-legal-hold-device", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ApproveLegalHoldForUserRequest_NjEyNzYyMTIx" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Legal hold approved" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "legalhold-not-registered", + "message": "legal hold service has not been registered for this team" + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-not-registered" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nlegal hold service has not been registered for this team (label: `legalhold-not-registered`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "legalhold-not-enabled", + "message": "legal hold is not enabled for this team" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-not-enabled", + "no-team-member", + "action-denied", + "access-denied", + "code-authentication-required", + "code-authentication-failed" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "legal hold is not enabled for this team (label: `legalhold-not-enabled`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nInsufficient authorization (missing remove_conversation_member) (label: `action-denied`)\n\nYou do not have permission to access this resource (label: `access-denied`)\n\nVerification code required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nThis operation requires reauthentication (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "legalhold-no-device-allocated", + "message": "no legal hold device is registered for this user. POST /teams/:tid/legalhold/:uid/ to start the flow." + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-no-device-allocated" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` or `uid` not found\n\nno legal hold device is registered for this user. POST /teams/:tid/legalhold/:uid/ to start the flow. (label: `legalhold-no-device-allocated`)" + }, + "409": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 409, + "label": "legalhold-already-enabled", + "message": "legal hold is already enabled for this user" + }, + "properties": { + "code": { + "enum": [ + 409 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-already-enabled" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "legal hold is already enabled for this user (label: `legalhold-already-enabled`)" + }, + "412": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 412, + "label": "legalhold-not-pending", + "message": "legal hold cannot be approved without being in a pending state" + }, + "properties": { + "code": { + "enum": [ + 412 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-not-pending" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "legal hold cannot be approved without being in a pending state (label: `legalhold-not-pending`)" + }, + "429": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 429, + "label": "too-many-requests", + "message": "Please try again later." + }, + "properties": { + "code": { + "enum": [ + 429 + ], + "type": "integer" + }, + "label": { + "enum": [ + "too-many-requests" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Please try again later. (label: `too-many-requests`)" + }, + "500": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 500, + "label": "legalhold-internal", + "message": "legal hold service: could not block connections when resolving policy conflicts." + }, + "properties": { + "code": { + "enum": [ + 500 + ], + "type": "integer" + }, + "label": { + "enum": [ + "legalhold-internal", + "legalhold-illegal-op" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "legal hold service: could not block connections when resolving policy conflicts. (label: `legalhold-internal`)\n\ninternal server error: inconsistent change of user's legalhold state (label: `legalhold-illegal-op`)" + } + }, + "summary": "Approve legal hold device" + } + }, + "/teams/{tid}/members": { + "get": { + "description": " [internal route ID: \"get-team-members\"]\n\n", + "operationId": "get-team-members", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "description": "Maximum results to be returned", + "in": "query", + "name": "maxResults", + "required": false, + "schema": { + "format": "int32", + "maximum": 2000, + "minimum": 1, + "type": "integer" + } + }, + { + "description": "Optional, when not specified, the first page will be returned.Every returned page contains a `pagingState`, this should be supplied to retrieve the next page.", + "in": "query", + "name": "pagingState", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/TeamMembersPage_NzYwNDIxODgx" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)" + } + }, + "summary": "Get team members" + }, + "put": { + "description": " [internal route ID: \"update-team-member\"]\n\n", + "operationId": "update-team-member", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewTeamMember_Required_LTg2NjU5OTI2" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "operation-denied", + "message": "Insufficient permissions" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "operation-denied", + "no-team-member", + "too-many-team-admins", + "invalid-permissions", + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nMaximum number of admins per team reached (label: `too-many-team-admins`)\n\nThe specified permissions are invalid (label: `invalid-permissions`)\n\nYou do not have permission to access this resource (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team-member", + "message": "Team member not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member", + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam member not found (label: `no-team-member`)\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Update an existing team member" + } + }, + "/teams/{tid}/members/csv": { + "get": { + "description": " [internal route ID: \"get-team-members-csv\"]\n\nThe endpoint returns data in chunked transfer encoding. Internal server errors might result in a failed transfer instead of a 500 response.", + "operationId": "get-team-members-csv", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "text/csv": {} + }, + "description": "CSV of team members" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "access-denied", + "message": "You do not have permission to access this resource" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "access-denied" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "You do not have permission to access this resource (label: `access-denied`)" + } + }, + "summary": "Get all members of the team as a CSV file" + } + }, + "/teams/{tid}/members/{uid}": { + "delete": { + "description": " [internal route ID: \"delete-team-member\"]\n\n", + "operationId": "delete-team-member", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/TeamMemberDeleteData_LTg2OTEyOTI4" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "" + }, + "202": { + "description": "Team member scheduled for deletion" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "operation-denied", + "message": "Insufficient permissions" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "operation-denied", + "no-team-member", + "access-denied", + "code-authentication-required", + "code-authentication-failed" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)\n\nYou do not have permission to access this resource (label: `access-denied`)\n\nVerification code required (label: `code-authentication-required`)\n\nCode authentication failed (label: `code-authentication-failed`)\n\nThis operation requires reauthentication (label: `access-denied`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team", + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` or `uid` not found\n\nTeam not found (label: `no-team`)\n\nTeam member not found (label: `no-team-member`)" + }, + "429": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 429, + "label": "too-many-requests", + "message": "Please try again later." + }, + "properties": { + "code": { + "enum": [ + 429 + ], + "type": "integer" + }, + "label": { + "enum": [ + "too-many-requests" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Please try again later. (label: `too-many-requests`)" + } + }, + "summary": "Remove an existing team member" + }, + "get": { + "description": " [internal route ID: \"get-team-member\"]\n\n", + "operationId": "get-team-member", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/TeamMember_Optional_NTU0MDcyNzI1" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "no-team-member", + "message": "Requesting user is not a team member" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Requesting user is not a team member (label: `no-team-member`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team-member", + "message": "Team member not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` or `uid` not found\n\nTeam member not found (label: `no-team-member`)" + } + }, + "summary": "Get single team member" + } + }, + "/teams/{tid}/search": { + "get": { + "description": " [internal route ID: \"browse-team\"]\n\n", + "operationId": "browse-team", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "description": "Search expression", + "in": "query", + "name": "q", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Role filter, eg. `member,partner`. Empty list means do not filter.", + "in": "query", + "name": "frole", + "required": false, + "schema": { + "items": { + "enum": [ + "owner", + "admin", + "member", + "partner" + ], + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Can be one of name, handle, email, saml_idp, managed_by, role, created_at.", + "in": "query", + "name": "sortby", + "required": false, + "schema": { + "enum": [ + "name", + "handle", + "email", + "saml_idp", + "managed_by", + "role", + "created_at" + ], + "type": "string" + } + }, + { + "description": "Can be one of asc, desc.", + "in": "query", + "name": "sortorder", + "required": false, + "schema": { + "enum": [ + "asc", + "desc" + ], + "type": "string" + } + }, + { + "description": "Number of results to return (min: 1, max: 500, default: 15)", + "in": "query", + "name": "size", + "required": false, + "schema": { + "maximum": 500, + "minimum": 1, + "type": "integer" + } + }, + { + "description": "Optional, when not specified, the first page will be returned. Every returned page contains a `paging_state`, this should be supplied to retrieve the next page.", + "in": "query", + "name": "pagingState", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter for (un-)verified email", + "in": "query", + "name": "email", + "required": false, + "schema": { + "enum": [ + "unverified", + "verified" + ], + "type": "string" + } + }, + { + "description": "Optional, return only non-searchable members when false.", + "in": "query", + "name": "searchable", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SearchResult_TeamContact_LTE0NjQ0NzMw" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/SearchResult_TeamContact_LTE0NjQ0NzMw" + } + } + }, + "description": "Search results" + } + }, + "summary": "Browse team for members (requires add-user permission)" + } + }, + "/teams/{tid}/search-visibility": { + "get": { + "description": " [internal route ID: \"get-search-visibility\"]\n\n", + "operationId": "get-search-visibility", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/TeamSearchVisibilityView_Mzg3MzMzMTk3" + } + } + }, + "description": "" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "operation-denied", + "message": "Insufficient permissions" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "operation-denied", + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Insufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" + } + }, + "summary": "Shows the value for search visibility" + }, + "put": { + "description": " [internal route ID: \"set-search-visibility\"]\n\n", + "operationId": "set-search-visibility", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/TeamSearchVisibilityView_Mzg3MzMzMTk3" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Search visibility set" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "team-search-visibility-not-enabled", + "message": "Custom search is not available for this team" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "team-search-visibility-not-enabled", + "operation-denied", + "no-team-member" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Custom search is not available for this team (label: `team-search-visibility-not-enabled`)\n\nInsufficient permissions (label: `operation-denied`)\n\nRequesting user is not a team member (label: `no-team-member`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "no-team", + "message": "Team not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "no-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`tid` not found\n\nTeam not found (label: `no-team`)" + } + }, + "summary": "Sets the search visibility for the whole team" + } + }, + "/teams/{tid}/size": { + "get": { + "description": " [internal route ID: \"get-team-size\"]\n\nCan be out of sync by roughly the `refresh_interval` of the ES index.", + "operationId": "get-team-size", + "parameters": [ + { + "in": "path", + "name": "tid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamSize_LTMzMzk2MTk1" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/TeamSize_LTMzMzk2MTk1" + } + } + }, + "description": "Number of team members" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "invalid-invitation-code", + "message": "Invalid invitation code." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "invalid-invitation-code" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid invitation code. (label: `invalid-invitation-code`)" + } + }, + "summary": "Get the number of team members as an integer" + } + }, + "/time": { + "get": { + "description": " [internal route ID: \"get-server-time\"]\n\nReturns the current server time in UTC with seconds precision.", + "operationId": "get-server-time", + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ServerTime_LTM4NTI3MzIx" + } + } + }, + "description": "" + } + }, + "summary": "Get the current server time" + } + }, + "/upgrade-personal-to-team": { + "post": { + "description": " [internal route ID: \"upgrade-personal-to-team\"]\n\n", + "operationId": "upgrade-personal-to-team", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/BindingNewTeamUser_LTY0MDQxMDEw" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateUserTeam_MzI4NDQ1Mzkw" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CreateUserTeam_MzI4NDQ1Mzkw" + } + } + }, + "description": "Team created" + }, + "403": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 403, + "label": "user-already-in-a-team", + "message": "Switching teams is not allowed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-already-in-a-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "user-already-in-a-team", + "message": "Switching teams is not allowed" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-already-in-a-team" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Switching teams is not allowed (label: `user-already-in-a-team`)" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "User not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "User not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "User not found (label: `not-found`)" + } + }, + "summary": "Upgrade personal user to team owner" + } + }, + "/user-groups": { + "get": { + "description": " [internal route ID: \"get-user-groups\"]\n\n", + "operationId": "get-user-groups", + "parameters": [ + { + "description": "Search string", + "in": "query", + "name": "q", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "sort_by", + "required": false, + "schema": { + "enum": [ + "name", + "created_at" + ], + "type": "string" + } + }, + { + "in": "query", + "name": "sort_order", + "required": false, + "schema": { + "enum": [ + "asc", + "desc" + ], + "type": "string" + } + }, + { + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "description": "integer from [1..500]", + "type": "number" + } + }, + { + "description": "`name` of the last seen user group, used to get the next page when sorting by name.", + "in": "query", + "name": "last_seen_name", + "required": false, + "schema": { + "maxLength": 4000, + "minLength": 1, + "type": "string" + } + }, + { + "description": "`created_at` field of the last seen user group, used to get the next page when sorting by created_at.", + "in": "query", + "name": "last_seen_created_at", + "required": false, + "schema": { + "format": "yyyy-mm-ddThh:MM:ssZ", + "type": "string" + } + }, + { + "description": "`id` of the last seen group, used to get the next page. **Must** be sent to get the next page.", + "in": "query", + "name": "last_seen_id", + "required": false, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "allowEmptyValue": true, + "in": "query", + "name": "include_channels", + "schema": { + "default": false, + "type": "boolean" + } + }, + { + "allowEmptyValue": true, + "in": "query", + "name": "include_member_count", + "schema": { + "default": false, + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserGroupPage_UserGroup_Const_LTMxNDg5MDAy" + } + } + }, + "description": "" + } + }, + "summary": "Fetch groups accessible to the logged-in user" + }, + "post": { + "description": " [internal route ID: \"create-user-group\"]\n\n", + "operationId": "create-user-group", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/NewUserGroup_MzYxODU0OTU1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserGroup_Identity_NTg4MTY1MjEx" + } + } + }, + "description": "" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "user-group-invalid", + "message": "Only team members of the same team can be added to a user group." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-invalid" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nOnly team members of the same team can be added to a user group. (label: `user-group-invalid`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "user-group-write-forbidden", + "message": "Only team admins can create, update, or delete user groups." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-write-forbidden" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Only team admins can create, update, or delete user groups. (label: `user-group-write-forbidden`)" + } + } + } + }, + "/user-groups/check-name": { + "post": { + "description": " [internal route ID: \"check-user-group-name-available\"]\n\n", + "operationId": "check-user-group-name-available", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/CheckUserGroupName_LTg0ODU1OTk1" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserGroupNameAvailability_LTYzMDE1NTk4" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserGroupNameAvailability_LTYzMDE1NTk4" + } + } + }, + "description": "OK" + } + }, + "summary": "[STUB] Check if a user group name is available" + } + }, + "/user-groups/{gid}": { + "delete": { + "description": " [internal route ID: \"delete-user-group\"]\n\n", + "operationId": "delete-user-group", + "parameters": [ + { + "in": "path", + "name": "gid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "User group deleted" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "user-group-write-forbidden", + "message": "Only team admins can create, update, or delete user groups." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-write-forbidden" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Only team admins can create, update, or delete user groups. (label: `user-group-write-forbidden`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "user-group-not-found", + "message": "User group not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`gid` not found\n\nUser group not found (label: `user-group-not-found`)" + } + } + }, + "get": { + "description": " [internal route ID: \"get-user-group\"]\n\n", + "operationId": "get-user-group", + "parameters": [ + { + "in": "path", + "name": "gid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "allowEmptyValue": true, + "in": "query", + "name": "include_channels", + "schema": { + "default": false, + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserGroup_Identity_NTg4MTY1MjEx" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserGroup_Identity_NTg4MTY1MjEx" + } + } + }, + "description": "User Group Found" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "user-group-not-found", + "message": "User group not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "user-group-not-found", + "message": "User group not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`gid` or User group not found (label: `user-group-not-found`)\n\nUser group not found (label: `user-group-not-found`)" + } + }, + "summary": "Fetch a group accessible to the logged-in user" + }, + "put": { + "description": " [internal route ID: \"update-user-group\"]\n\n", + "operationId": "update-user-group", + "parameters": [ + { + "in": "path", + "name": "gid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserGroupUpdate_MjUyNTA3Mjgy" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User added updated" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "user-group-write-forbidden", + "message": "Only team admins can create, update, or delete user groups." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-write-forbidden" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Only team admins can create, update, or delete user groups. (label: `user-group-write-forbidden`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "user-group-not-found", + "message": "User group not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`gid` not found\n\nUser group not found (label: `user-group-not-found`)" + } + } + } + }, + "/user-groups/{gid}/channels": { + "put": { + "description": " [internal route ID: \"update-user-group-channels\"]\n\n", + "operationId": "update-user-group-channels", + "parameters": [ + { + "in": "path", + "name": "gid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "allowEmptyValue": true, + "in": "query", + "name": "append_only", + "schema": { + "default": false, + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UpdateUserGroupChannels_LTIyMjcwMTMx" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User group channels updated" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "user-group-write-forbidden", + "message": "Only team admins can create, update, or delete user groups." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-write-forbidden" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Only team admins can create, update, or delete user groups. (label: `user-group-write-forbidden`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "user-group-not-found", + "message": "User group not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`gid` not found\n\nUser group not found (label: `user-group-not-found`)" + } + }, + "summary": "Replaces the channels with the given list." + } + }, + "/user-groups/{gid}/users": { + "post": { + "description": " [internal route ID: \"add-users-to-group-bulk\"]\n\n", + "operationId": "add-users-to-group-bulk", + "parameters": [ + { + "in": "path", + "name": "gid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserGroupAddUsers_LTgzOTYzNzk0" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Users added to group" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "user-group-invalid", + "message": "Only team members of the same team can be added to a user group." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-invalid" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Invalid `body`\n\nOnly team members of the same team can be added to a user group. (label: `user-group-invalid`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "user-group-write-forbidden", + "message": "Only team admins can create, update, or delete user groups." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-write-forbidden" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Only team admins can create, update, or delete user groups. (label: `user-group-write-forbidden`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "user-group-not-found", + "message": "User group not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`gid` not found\n\nUser group not found (label: `user-group-not-found`)" + } + } + }, + "put": { + "description": " [internal route ID: \"update-user-group-members\"]\n\n", + "operationId": "update-user-group-members", + "parameters": [ + { + "in": "path", + "name": "gid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UpdateUserGroupMembers_LTg1MzQ2NDY3" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User group members updated" + } + }, + "summary": "[STUB] Update user group members. Replaces the users with the given list." + } + }, + "/user-groups/{gid}/users/{uid}": { + "delete": { + "description": " [internal route ID: \"remove-user-from-group\"]\n\n", + "operationId": "remove-user-from-group", + "parameters": [ + { + "in": "path", + "name": "gid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "User removed from group" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "user-group-invalid", + "message": "Only team members of the same team can be added to a user group." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-invalid" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Only team members of the same team can be added to a user group. (label: `user-group-invalid`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "user-group-write-forbidden", + "message": "Only team admins can create, update, or delete user groups." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-write-forbidden" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Only team admins can create, update, or delete user groups. (label: `user-group-write-forbidden`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "user-group-not-found", + "message": "User group not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`gid` or `uid` not found\n\nUser group not found (label: `user-group-not-found`)" + } + } + }, + "post": { + "description": " [internal route ID: \"add-user-to-group\"]\n\n", + "operationId": "add-user-to-group", + "parameters": [ + { + "in": "path", + "name": "gid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "User added to group" + }, + "400": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 400, + "label": "user-group-invalid", + "message": "Only team members of the same team can be added to a user group." + }, + "properties": { + "code": { + "enum": [ + 400 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-invalid" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Only team members of the same team can be added to a user group. (label: `user-group-invalid`)" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "user-group-write-forbidden", + "message": "Only team admins can create, update, or delete user groups." + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-write-forbidden" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Only team admins can create, update, or delete user groups. (label: `user-group-write-forbidden`)" + }, + "404": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "user-group-not-found", + "message": "User group not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "user-group-not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`gid` or `uid` not found\n\nUser group not found (label: `user-group-not-found`)" + } + } + } + }, + "/users/list-clients": { + "post": { + "description": " [internal route ID: \"list-clients-bulk@v2\"]\n\nIf a backend is unreachable, the clients from that backend will be omitted from the response", + "operationId": "list-clients-bulk@v2", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/LimitedQualifiedUserIdList_500" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "properties": { + "qualified_user_map": { + "$ref": "#/components/schemas/QualifiedUserMap_Set_PubClient" + } + }, + "type": "object" + } + } + }, + "description": "" + } + }, + "summary": "List all clients for a set of user ids" + } + }, + "/users/list-prekeys": { + "post": { + "description": " [internal route ID: \"get-multi-user-prekey-bundle-qualified\"]\n\nYou can't request information for more users than maximum conversation size.", + "operationId": "get-multi-user-prekey-bundle-qualified", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/QualifiedUserClients" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/QualifiedUserClientPrekeyMapV4_MzcxOTAxMTYy" + } + } + }, + "description": "" + } + }, + "summary": "(deprecated) Given a map of user IDs to client IDs return a prekey for each one." + } + }, + "/users/{uid_domain}/{uid}": { + "get": { + "description": " [internal route ID: \"get-user-qualified\"]\n\n", + "operationId": "get-user-qualified", + "parameters": [ + { + "in": "path", + "name": "uid_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User Id", + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserProfile_LTQzMTQxMTE1" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/UserProfile_LTQzMTQxMTE1" + } + } + }, + "description": "User found" + }, + "404": { + "content": { + "application/json": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "User not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + }, + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 404, + "label": "not-found", + "message": "User not found" + }, + "properties": { + "code": { + "enum": [ + 404 + ], + "type": "integer" + }, + "label": { + "enum": [ + "not-found" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "`uid_domain` or `uid` or User not found (label: `not-found`)" + } + }, + "summary": "Get a user by Domain and UserId" + } + }, + "/users/{uid_domain}/{uid}/clients/{client}": { + "get": { + "description": " [internal route ID: \"get-user-client-qualified\"]\n\nHint: to list all clients of one or more users, use POST /users/list-clients.", + "operationId": "get-user-client-qualified", + "parameters": [ + { + "in": "path", + "name": "uid_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User Id", + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PubClient" + } + } + }, + "description": "" + } + }, + "summary": "Get a specific client of a user" + } + }, + "/users/{uid_domain}/{uid}/prekeys": { + "get": { + "description": " [internal route ID: \"get-users-prekey-bundle-qualified\"]\n\n", + "operationId": "get-users-prekey-bundle-qualified", + "parameters": [ + { + "in": "path", + "name": "uid_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User Id", + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/PrekeyBundle_MzgzOTk4MjYz" + } + } + }, + "description": "" + } + }, + "summary": "Get a prekey for each client of a user." + } + }, + "/users/{uid_domain}/{uid}/prekeys/{client}": { + "get": { + "description": " [internal route ID: \"get-users-prekeys-client-qualified\"]\n\n", + "operationId": "get-users-prekeys-client-qualified", + "parameters": [ + { + "in": "path", + "name": "uid_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User Id", + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "description": "ClientId", + "in": "path", + "name": "client", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/ClientPrekey_LTcyODUzMTcw" + } + } + }, + "description": "" + } + }, + "summary": "Get a prekey for a specific client of a user." + } + }, + "/users/{uid_domain}/{uid}/supported-protocols": { + "get": { + "description": " [internal route ID: \"get-supported-protocols\"]\n\n", + "operationId": "get-supported-protocols", + "parameters": [ + { + "in": "path", + "name": "uid_domain", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "User Id", + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/BaseProtocolTag_LTM0MDE1NTEx" + }, + "type": "array", + "uniqueItems": true + } + }, + "application/json;charset=utf-8": { + "schema": { + "items": { + "$ref": "#/components/schemas/BaseProtocolTag_LTM0MDE1NTEx" + }, + "type": "array", + "uniqueItems": true + } + } + }, + "description": "Protocols supported by the user" + } + }, + "summary": "Get a user's supported protocols" + } + }, + "/users/{uid}/email": { + "put": { + "description": " [internal route ID: \"update-user-email\"]\n\nIf the user has a pending email validation, the validation email will be resent.", + "operationId": "update-user-email", + "parameters": [ + { + "description": "User Id", + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/EmailUpdate_NjQ5MDg1OTY0" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + } + }, + "description": "" + } + }, + "summary": "Resend email address validation email." + } + }, + "/users/{uid}/rich-info": { + "get": { + "description": " [internal route ID: \"get-rich-info\"]\n\n", + "operationId": "get-rich-info", + "parameters": [ + { + "description": "User Id", + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RichInfoAssocList" + } + }, + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/RichInfoAssocList" + } + } + }, + "description": "Rich info about the user" + }, + "403": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": { + "code": 403, + "label": "insufficient-permissions", + "message": "Insufficient team permissions" + }, + "properties": { + "code": { + "enum": [ + 403 + ], + "type": "integer" + }, + "label": { + "enum": [ + "insufficient-permissions" + ], + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "label", + "message" + ], + "type": "object" + } + } + }, + "description": "Insufficient team permissions (label: `insufficient-permissions`)" + } + }, + "summary": "Get a user's rich info" + } + }, + "/users/{uid}/searchable": { + "post": { + "description": " [internal route ID: \"set-user-searchable\"]\n\n", + "operationId": "set-user-searchable", + "parameters": [ + { + "description": "User Id", + "in": "path", + "name": "uid", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/SetSearchable_NDAxODAxODI5" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "example": [], + "items": {}, + "maxItems": 0, + "type": "array" + } + } + }, + "description": "" + } + }, + "summary": "Set user's visibility in search" + } + }, + "/verification-code/send": { + "post": { + "description": " [internal route ID: \"send-verification-code\"]\n\n", + "operationId": "send-verification-code", + "requestBody": { + "content": { + "application/json;charset=utf-8": { + "schema": { + "$ref": "#/components/schemas/SendVerificationCode_MjgxNDgxODE2" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Verification code sent." + } + }, + "summary": "Send a verification code to a given email address." + } + }, + "/websocket": { + "get": { + "description": " [internal route ID: \"websocket\"]\n\nThis is a temporary copy of await, please do not use it", + "externalDocs": { + "description": "RFC 6455", + "url": "https://datatracker.ietf.org/doc/html/rfc6455" + }, + "operationId": "websocket", + "parameters": [ + { + "description": "Client ID", + "in": "query", + "name": "client", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "101": { + "description": "Connection upgraded." + }, + "426": { + "description": "Upgrade required." + } + }, + "summary": "Establish websocket connection" + } + } + }, + "security": [ + { + "ZAuth": [] + } + ], + "servers": [ + { + "url": "/v18" + } + ] +} diff --git a/services/brig/src/Brig/API/Public.hs b/services/brig/src/Brig/API/Public.hs index dd5471760b1..60cc7a53bf6 100644 --- a/services/brig/src/Brig/API/Public.hs +++ b/services/brig/src/Brig/API/Public.hs @@ -236,10 +236,11 @@ internalEndpointsSwaggerDocsAPIs = -- -- Dual to `internalEndpointsSwaggerDocsAPI`. versionedSwaggerDocsAPI :: Servant.Server VersionedSwaggerDocsAPI -versionedSwaggerDocsAPI (Just (VersionNumber V18)) = +versionedSwaggerDocsAPI (Just (VersionNumber V19)) = swaggerSchemaUIServer $ devVersionSwagger & S.info . S.description ?~ $((unTypeCode . embedText) =<< makeRelativeToProject "docs/swagger.md") +versionedSwaggerDocsAPI (Just (VersionNumber V18)) = swaggerPregenUIServer $(pregenSwagger V18) versionedSwaggerDocsAPI (Just (VersionNumber V17)) = swaggerPregenUIServer $(pregenSwagger V17) versionedSwaggerDocsAPI (Just (VersionNumber V16)) = swaggerPregenUIServer $(pregenSwagger V16) versionedSwaggerDocsAPI (Just (VersionNumber V15)) = swaggerPregenUIServer $(pregenSwagger V15) @@ -1673,7 +1674,12 @@ getSystemSettingsInternal = do { setRestrictUserCreation = fromMaybe False optSettings.restrictUserCreation, nomadProfiles = optSettings.nomadProfiles } - iSettings = SystemSettingsInternal $ fromMaybe False optSettings.enableMLS + iSettings = + SystemSettingsInternal + { ssiSetEnableMls = fromMaybe False optSettings.enableMLS, + ssiSetSsoIdpChangeDetectionEnabled = + deriveSsoIdpChangeDetectionEnabled optSettings.ssoIdpChangeDetectionInputs + } pure $ SystemSettings pSettings iSettings authorizeTeam :: diff --git a/services/brig/src/Brig/API/User.hs b/services/brig/src/Brig/API/User.hs index 10c4a949c2b..d26a22d5fa6 100644 --- a/services/brig/src/Brig/API/User.hs +++ b/services/brig/src/Brig/API/User.hs @@ -1170,7 +1170,7 @@ ensureAccountDeleted luid@(tUnqualified -> uid) = do -- states. Please change this order only with care! -- -- FUTUREWORK(mangoiv): this uses 'UserStore', hence it must be moved to 'UserSubsystem' --- as an effet operation +-- as an effect operation -- FUTUREWORK: this does not need the whole User structure, only the User. deleteAccount :: ( Member (Embed HttpClientIO) r, @@ -1197,8 +1197,10 @@ deleteAccount user = do PropertySubsystem.onUserDeleted uid UserStore.deleteUser user - for_ (userEmail user) $ \email -> - for_ (userTeam user) $ \tid -> + for_ (userTeam user) $ \tid -> do + -- Delete potentially pending team invitations for SCIM users + InvitationStore.deleteInvitation tid (userIdToInvitationId uid) + for_ (userEmail user) $ \email -> InvitationStore.deletePendingScimUser tid email uid traverse_ (removeUserFromAllGroups uid) user.userTeam diff --git a/services/brig/src/Brig/CanonicalInterpreter.hs b/services/brig/src/Brig/CanonicalInterpreter.hs index f866fc5a9ca..d44c91648d3 100644 --- a/services/brig/src/Brig/CanonicalInterpreter.hs +++ b/services/brig/src/Brig/CanonicalInterpreter.hs @@ -419,7 +419,7 @@ runBrigToIO e (AppT ma) = do case e.postgresMigration.user of CassandraStorage -> interpretUserStoreCassandra e.casClient PostgresqlStorage -> interpretUserStorePostgres - MigrationToPostgresql -> error "Migration not implemented for user" + MigrationToPostgresql -> interpretUserStoreToCassandraAndPostgres e.casClient ( either throwM pure <=< ( runFinal diff --git a/services/brig/src/Brig/Index/Eval.hs b/services/brig/src/Brig/Index/Eval.hs index ea72f9aeef5..f931a032769 100644 --- a/services/brig/src/Brig/Index/Eval.hs +++ b/services/brig/src/Brig/Index/Eval.hs @@ -45,8 +45,11 @@ import Hasql.Pool.Extended qualified as Hasql import Imports import Network.HTTP.Client (Manager) import Polysemy +import Polysemy.Async (Async, asyncToIOFinal) +import Polysemy.Conc (Race, interpretRace) import Polysemy.Error import Polysemy.Input +import Polysemy.Resource (Resource, runResource) import Polysemy.TinyLog (TinyLog) import System.Logger qualified as Log import System.Logger.Class (Logger) @@ -59,6 +62,7 @@ import Wire.IndexedUserStore.Bulk.ElasticSearch qualified as IndexedUserStoreBul import Wire.IndexedUserStore.ElasticSearch import Wire.IndexedUserStore.MigrationStore (IndexedUserMigrationStore) import Wire.IndexedUserStore.MigrationStore.ElasticSearch +import Wire.MigrationLock import Wire.ParseException import Wire.PostgresMigrationOpts import Wire.Rpc @@ -79,6 +83,7 @@ type BrigIndexEffectStack = Error IndexedUserStoreError, IndexedUserMigrationStore, Error MigrationException, + Error MigrationLockError, GalleyAPIAccess, Error ParseException, Rpc, @@ -87,6 +92,9 @@ type BrigIndexEffectStack = Input Hasql.Pool, Error UsageError, Error ClientError, + Resource, + Race, + Async, Embed IO, Final IO ] @@ -127,10 +135,13 @@ runSem :: SemDeps -> UserStorageLocation -> Endpoint -> Logger -> Sem BrigIndexE runSem (mgr, casClient, pgPool, bhEnv, indexedUserStoreConfig, reqId, migrationIndexName) userStorage galleyEndpoint logger action = do let userStoreInterpreter = case userStorage.userStorageLocation of CassandraStorage -> interpretUserStoreCassandra casClient - MigrationToPostgresql -> error "Migration not implemented for user" + MigrationToPostgresql -> interpretUserStoreToCassandraAndPostgres casClient PostgresqlStorage -> interpretUserStorePostgres runFinal . embedToFinal + . asyncToIOFinal + . interpretRace + . runResource . throwErrorToIOFinal @ClientError . throwPostgresUsageErrorToIOFinal . runInputConst pgPool @@ -139,6 +150,7 @@ runSem (mgr, casClient, pgPool, bhEnv, indexedUserStoreConfig, reqId, migrationI . runRpcWithHttp mgr reqId . throwErrorToIOFinal @ParseException . interpretGalleyAPIAccessToRpc mempty galleyEndpoint + . throwErrorToIOFinal @MigrationLockError . throwErrorToIOFinal @MigrationException . interpretIndexedUserMigrationStoreES bhEnv migrationIndexName . throwErrorToIOFinal @IndexedUserStoreError diff --git a/services/brig/src/Brig/Options.hs b/services/brig/src/Brig/Options.hs index df05f68fd7d..e69f515a391 100644 --- a/services/brig/src/Brig/Options.hs +++ b/services/brig/src/Brig/Options.hs @@ -35,6 +35,7 @@ import Data.Default import Data.Domain (Domain (..)) import Data.Id import Data.LanguageCodes (ISO639_1 (EN)) +import Data.Map.Strict qualified as Map import Data.Misc (HttpsUrl) import Data.Nonce import Data.Range @@ -549,11 +550,39 @@ data Settings = Settings ephemeralUserCreationEnabled :: !Bool, -- | Determines if this backend supports nomad profiles. nomadProfiles :: !(Maybe Bool), + -- | Raw spar multi-ingress inputs as rendered by the wire-server chart + -- (from @spar.config@; brig only needs their presence, not their contents). + -- 'deriveSsoIdpChangeDetectionEnabled' turns these into the value served + -- by @GET /system/settings@. + ssoIdpChangeDetectionInputs :: !(Maybe SsoIdpChangeDetectionInputs), -- | Determines if consumable notifications are enabled consumableNotifications :: !Bool } deriving (Show, Generic) +-- | Mirror of the multi-ingress-relevant parts of @spar.config@. Keys match +-- what @charts/wire-server/templates/brig/configmap.yaml@ renders from +-- @$.Values.spar.config@; contents are opaque to brig. +data SsoIdpChangeDetectionInputs = SsoIdpChangeDetectionInputs + { multiIngressDomainConfigs :: !(Map Text Value), + idpCertFingerprintAllowlist :: ![Text] + } + deriving (Eq, Show, Generic) + +instance FromJSON SsoIdpChangeDetectionInputs + +-- | @ssoIdpChangeDetectionEnabled@ mirrors spar's multi-ingress +-- configuration: enabled iff inline multi-ingress domain configs AND a +-- non-empty IdP cert fingerprint allowlist are configured (the criterion the +-- wire-server chart previously computed in the template; cf. +-- SAML.WebSSO.Config.isMultiIngressConfig). +deriveSsoIdpChangeDetectionEnabled :: Maybe SsoIdpChangeDetectionInputs -> Bool +deriveSsoIdpChangeDetectionEnabled = \case + Nothing -> False + Just inputs -> + not (Map.null inputs.multiIngressDomainConfigs) + && not (null inputs.idpCertFingerprintAllowlist) + newtype ImplicitNoFederationRestriction = ImplicitNoFederationRestriction {federationDomainConfig :: FederationDomainConfig} deriving (Show, Eq, Generic) diff --git a/services/brig/src/Brig/Run.hs b/services/brig/src/Brig/Run.hs index 7cc07fc7f2d..fd170bdbaff 100644 --- a/services/brig/src/Brig/Run.hs +++ b/services/brig/src/Brig/Run.hs @@ -101,7 +101,7 @@ run opts = withTracer \tracer -> do authMetrics <- Async.async (runBrigToIO e collectAuthMetrics) pendingActivationCleanupAsync <- Async.async (runBrigToIO e pendingActivationCleanup) - inSpan tracer "brig" defaultSpanArguments {kind = Otel.Server} (runSettingsWithShutdown s app Nothing) `finally` do + inSpan tracer "brig" defaultSpanArguments {kind = Otel.Server} (runSettingsWithCleanup (flush e.appLogger) s app Nothing) `finally` do Async.cancelMany $ [internalEventListener, pendingActivationCleanupAsync, authMetrics] <> catMaybes [emailListener, sftDiscovery] diff --git a/services/brig/src/Brig/Schema/Run.hs b/services/brig/src/Brig/Schema/Run.hs index 560cf64f2e7..ca29a34b79d 100644 --- a/services/brig/src/Brig/Schema/Run.hs +++ b/services/brig/src/Brig/Schema/Run.hs @@ -68,6 +68,7 @@ import Brig.Schema.V90_DomainRegistrationTeamIndex qualified as V90_DomainRegist import Brig.Schema.V91_UpdateDomainRegistrationSchema_AddWebappUrl qualified as V91_UpdateDomainRegistrationSchema_AddWebappUrl import Brig.Schema.V92_AddUserType qualified as V92_AddUserType import Brig.Schema.V93_AddScimPendingUserEmail qualified as V93_AddScimPendingUserEmail +import Brig.Schema.V94_ReduceUserGCGracePeriod qualified as V94_ReduceUserGCGracePeriod import Cassandra.MigrateSchema (migrateSchema) import Cassandra.Schema import Control.Exception (finally) @@ -142,7 +143,8 @@ migrations = V90_DomainRegistrationTeamIndex.migration, V91_UpdateDomainRegistrationSchema_AddWebappUrl.migration, V92_AddUserType.migration, - V93_AddScimPendingUserEmail.migration + V93_AddScimPendingUserEmail.migration, + V94_ReduceUserGCGracePeriod.migration -- FUTUREWORK: undo V41 (searchable flag); we stopped using it in -- https://github.com/wireapp/wire-server/pull/964 ] diff --git a/services/brig/src/Brig/Schema/V94_ReduceUserGCGracePeriod.hs b/services/brig/src/Brig/Schema/V94_ReduceUserGCGracePeriod.hs new file mode 100644 index 00000000000..3761b2f7f0a --- /dev/null +++ b/services/brig/src/Brig/Schema/V94_ReduceUserGCGracePeriod.hs @@ -0,0 +1,44 @@ +{-# LANGUAGE QuasiQuotes #-} + +-- This file is part of the Wire Server implementation. +-- +-- Copyright (C) 2026 Wire Swiss GmbH +-- +-- This program is free software: you can redistribute it and/or modify it under +-- the terms of the GNU Affero General Public License as published by the Free +-- Software Foundation, either version 3 of the License, or (at your option) any +-- later version. +-- +-- This program is distributed in the hope that it will be useful, but WITHOUT +-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +-- details. +-- +-- You should have received a copy of the GNU Affero General Public License along +-- with this program. If not, see . +module Brig.Schema.V94_ReduceUserGCGracePeriod + ( migration, + ) +where + +import Cassandra.Schema +import Imports +import Text.RawString.QQ + +migration :: Migration +migration = + Migration 94 "reduce user gc_grace_period" $ do + schema' + [r| ALTER TABLE user WITH gc_grace_seconds = 86400 |] + + schema' + [r| ALTER TABLE user_handle WITH gc_grace_seconds = 86400 |] + + schema' + [r| ALTER TABLE rich_info WITH gc_grace_seconds = 86400 |] + + schema' + [r| ALTER TABLE service_user WITH gc_grace_seconds = 86400 |] + + schema' + [r| ALTER TABLE service_team WITH gc_grace_seconds = 86400 |] diff --git a/services/brig/src/Brig/Team/API.hs b/services/brig/src/Brig/Team/API.hs index 48430fbebab..ce88b50a63f 100644 --- a/services/brig/src/Brig/Team/API.hs +++ b/services/brig/src/Brig/Team/API.hs @@ -69,6 +69,7 @@ import Wire.API.Team.Size import Wire.API.User hiding (fromEmail) import Wire.AuthenticationSubsystem import Wire.BlockListStore +import Wire.ClientStore (ClientStore) import Wire.EmailSubsystem.Interpreter (renderInvitationUrl) import Wire.Error import Wire.Events (Events) @@ -77,18 +78,25 @@ import Wire.GalleyAPIAccess qualified as GalleyAPIAccess import Wire.IndexedUserStore (IndexedUserStore, getTeamSize) import Wire.InvitationStore (InvitationStore (..), PaginatedResult (..), StoredInvitation (..)) import Wire.InvitationStore qualified as Store +import Wire.NotificationSubsystem (NotificationSubsystem) +import Wire.PropertySubsystem (PropertySubsystem) import Wire.Sem.Concurrency +import Wire.SparAPIAccess (SparAPIAccess) +import Wire.SparAPIAccess qualified as SparAPIAccess import Wire.TeamInvitationSubsystem import Wire.TeamInvitationSubsystem.Interpreter (toInvitation) import Wire.TeamSubsystem (TeamSubsystem) import Wire.TeamSubsystem qualified as TeamSubsystem +import Wire.UserGroupSubsystem (UserGroupSubsystem) import Wire.UserKeyStore import Wire.UserPendingActivationStore (UserPendingActivationStore) +import Wire.UserPendingActivationStore qualified as UserPendingActivationStore import Wire.UserStore import Wire.UserSubsystem import Wire.UserSubsystem.Error servantAPI :: + forall p r. ( Member GalleyAPIAccess r, Member TeamInvitationSubsystem r, Member UserSubsystem r, @@ -98,7 +106,18 @@ servantAPI :: Member (Input (Local ())) r, Member (Error UserSubsystemError) r, Member IndexedUserStore r, - Member TeamSubsystem r + Member TeamSubsystem r, + Member SparAPIAccess r, + Member (Embed App.HttpClientIO) r, + Member NotificationSubsystem r, + Member ClientStore r, + Member PropertySubsystem r, + Member UserGroupSubsystem r, + Member Events r, + Member AuthenticationSubsystem r, + Member UserStore r, + Member UserKeyStore r, + Member (UserPendingActivationStore p) r ) => ServerT TeamsAPI (Handler r) servantAPI = @@ -202,9 +221,24 @@ logInvitationRequest context action = pure (Right result) deleteInvitation :: + forall p r. ( Member InvitationStore r, Member (Error UserSubsystemError) r, - Member TeamSubsystem r + Member TeamSubsystem r, + Member SparAPIAccess r, + Member TinyLog r, + Member (Embed App.HttpClientIO) r, + Member NotificationSubsystem r, + Member ClientStore r, + Member PropertySubsystem r, + Member UserGroupSubsystem r, + Member Events r, + Member AuthenticationSubsystem r, + Member UserSubsystem r, + Member UserStore r, + Member UserKeyStore r, + Member (UserPendingActivationStore p) r, + Member (Input (Local ())) r ) => UserId -> TeamId -> @@ -212,6 +246,30 @@ deleteInvitation :: Sem r () deleteInvitation uid tid iid = do ensurePermissions uid tid [AddTeamMember] + mInvitation <- Store.lookupInvitation tid iid + let scimUid = invitationIdToUserId iid + mUser <- getAccountNoFilter =<< qualifyLocal' scimUid + for_ mUser $ \user -> + for_ (userEmail user) $ \email -> do + pendingScimUsers <- Store.lookupPendingScimUsers tid email + let invitationMatches = maybe True (\inv -> inv.email == email) mInvitation + when + ( userId user == scimUid + && user.userTeam == Just tid + && user.userManagedBy == ManagedByScim + && user.userStatus == PendingInvitation + && invitationMatches + && scimUid `elem` pendingScimUsers + ) + $ do + -- Remove Spar's external-id mapping before deleting the Brig account. + -- Otherwise a SCIM retry still sees the old external ID as owned. + SparAPIAccess.deleteScimUser tid scimUid + UserPendingActivationStore.remove scimUid + -- Use the same complete deletion logic as the asynchronous user + -- deletion worker, but run it synchronously before the invitation is + -- removed so a replacement SCIM invitation can be created safely. + API.deleteAccount user Store.deleteInvitation tid iid listInvitations :: diff --git a/services/brig/test/unit/Run.hs b/services/brig/test/unit/Run.hs index a371d3130cc..3fffbfbfdbe 100644 --- a/services/brig/test/unit/Run.hs +++ b/services/brig/test/unit/Run.hs @@ -25,6 +25,7 @@ import Test.Brig.Calling qualified import Test.Brig.Calling.Internal qualified import Test.Brig.InternalNotification qualified import Test.Brig.MLS qualified +import Test.Brig.Options qualified import Test.Tasty main :: IO () @@ -35,5 +36,6 @@ main = [ Test.Brig.Calling.tests, Test.Brig.Calling.Internal.tests, Test.Brig.MLS.tests, - Test.Brig.InternalNotification.tests + Test.Brig.InternalNotification.tests, + Test.Brig.Options.tests ] diff --git a/services/brig/test/unit/Test/Brig/Options.hs b/services/brig/test/unit/Test/Brig/Options.hs new file mode 100644 index 00000000000..ebac8cc7ad9 --- /dev/null +++ b/services/brig/test/unit/Test/Brig/Options.hs @@ -0,0 +1,48 @@ +-- This file is part of the Wire Server implementation. +-- +-- Copyright (C) 2022 Wire Swiss GmbH +-- +-- This program is free software: you can redistribute it and/or modify it under +-- the terms of the GNU Affero General Public License as published by the Free +-- Software Foundation, either version 3 of the License, or (at your option) any +-- later version. +-- +-- This program is distributed in the hope that it will be useful, but WITHOUT +-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +-- details. +-- +-- You should have received a copy of the GNU Affero General Public License along +-- with this program. If not, see . + +module Test.Brig.Options (tests) where + +import Brig.Options +import Data.Aeson (eitherDecode, object) +import Data.Map.Strict qualified as Map +import Imports +import Test.Tasty +import Test.Tasty.HUnit + +tests :: TestTree +tests = + testGroup + "Brig.Options" + [ testGroup + "deriveSsoIdpChangeDetectionEnabled" + [ testCase "absent inputs disable" $ + deriveSsoIdpChangeDetectionEnabled Nothing @?= False, + testCase "empty inputs disable" $ + deriveSsoIdpChangeDetectionEnabled (Just (SsoIdpChangeDetectionInputs Map.empty [])) @?= False, + testCase "domains without allowlist disable" $ + deriveSsoIdpChangeDetectionEnabled (Just (SsoIdpChangeDetectionInputs (Map.singleton "example.com" (object [])) [])) @?= False, + testCase "allowlist without domains disable" $ + deriveSsoIdpChangeDetectionEnabled (Just (SsoIdpChangeDetectionInputs Map.empty ["AA:BB"])) @?= False, + testCase "domains and allowlist enable" $ + deriveSsoIdpChangeDetectionEnabled (Just (SsoIdpChangeDetectionInputs (Map.singleton "example.com" (object [])) ["AA:BB"])) @?= True, + testCase "chart-rendered JSON parses" $ + eitherDecode + "{\"multiIngressDomainConfigs\":{\"example.com\":{}},\"idpCertFingerprintAllowlist\":[\"AA:BB\"]}" + @?= Right (SsoIdpChangeDetectionInputs (Map.singleton "example.com" (object [])) ["AA:BB"]) + ] + ] diff --git a/services/galley/galley.integration.yaml b/services/galley/galley.integration.yaml index 85ec6c320c1..34762762965 100644 --- a/services/galley/galley.integration.yaml +++ b/services/galley/galley.integration.yaml @@ -225,7 +225,7 @@ settings: collabora: edition: COOL storage: - totalLimitBytes: "1000000000000" + totalLimitBytes: "-1" perUserQuotaBytes: "-1" allowedGlobalOperations: status: enabled diff --git a/services/galley/src/Galley/API/Federation.hs b/services/galley/src/Galley/API/Federation.hs index d1e47cae92a..239d6757533 100644 --- a/services/galley/src/Galley/API/Federation.hs +++ b/services/galley/src/Galley/API/Federation.hs @@ -60,6 +60,10 @@ federationSitemap = :<|> Named @(Versioned 'V0 "on-conversation-updated") onConversationUpdatedV0 :<|> Named @"on-conversation-updated" federationOnConversationUpdated :<|> Named @"on-user-deleted-conversations" federationOnUserDeleted + :<|> Named @"on-conversation-system-member-update" federationOnSystemMemberUpdate + :<|> Named @"on-conversation-system-delete" federationOnSystemDelete + :<|> Named @"on-conversation-adminless-reminder" federationOnAdminlessReminder + :<|> Named @"on-conversation-system-adminless-reminder" federationOnSystemAdminlessReminder onConversationUpdatedV0 :: (Member ConversationSubsystem r) => diff --git a/services/spar/src/Spar/API.hs b/services/spar/src/Spar/API.hs index f18e882b496..6886106b97f 100644 --- a/services/spar/src/Spar/API.hs +++ b/services/spar/src/Spar/API.hs @@ -263,6 +263,7 @@ apiINTERNAL :: Member IdPConfigStore r, Member (Error SparError) r, Member SAMLUserStore r, + Member ScimExternalIdStore r, Member ScimUserMetaStore r, Member (Logger (Msg -> Msg)) r, Member Random r, @@ -273,6 +274,7 @@ apiINTERNAL :: apiINTERNAL = Named @"i_status" internalStatus :<|> Named @"i_delete_team" internalDeleteTeam + :<|> Named @"i_delete_scim_user" internalDeleteScimUser :<|> Named @"i_put_sso_settings" internalPutSsoSettings :<|> Named @"i_post_scim_user_info" internalGetScimUserInfo :<|> Named @"i_get_identity_providers" idpGetAllByTeamId @@ -1132,6 +1134,30 @@ internalDeleteTeam teamId = do deleteTeam teamId pure NoContent +internalDeleteScimUser :: + ( Member BrigAPIAccess r, + Member ScimExternalIdStore r, + Member ScimUserMetaStore r, + Member SAMLUserStore r, + Member (Logger (Msg -> Msg)) r + ) => + TeamId -> + UserId -> + Sem r NoContent +internalDeleteScimUser teamId uid = do + Logger.info $ + Log.msg ("Attempting to delete SCIM user data" :: String) + . Log.field "team" (idToText teamId) + . Log.field "user" (idToText uid) + BrigAPIAccess.getAccount WithPendingInvitations uid >>= \case + Just user + | userTeam user == Just teamId + && userManagedBy user == ManagedByScim + && userStatus user == PendingInvitation -> + deleteScimUserData teamId user + _ -> pure () + pure NoContent + internalPutSsoSettings :: ( Member DefaultSsoCode r, Member (Error SparError) r, diff --git a/services/spar/src/Spar/Scim/User.hs b/services/spar/src/Spar/Scim/User.hs index 95e040bc661..c9c6e3a5150 100644 --- a/services/spar/src/Spar/Scim/User.hs +++ b/services/spar/src/Spar/Scim/User.hs @@ -41,6 +41,7 @@ module Spar.Scim.User mkValidScimId, scimFindUserByExternalId, deleteScimUser, + deleteScimUserData, ) where @@ -899,6 +900,20 @@ deleteScimUser tokeninfo@ScimTokenInfo {stiTeam, stiIdP} uid = ScimExternalIdStore.delete stiTeam veid.validScimIdExternal lift $ ScimUserMetaStore.delete uid +deleteScimUserData :: + ( Member ScimExternalIdStore r, + Member ScimUserMetaStore r, + Member SAMLUserStore r + ) => + TeamId -> + User -> + Sem r () +deleteScimUserData teamId account = do + for_ (Intra.oldVeidFromBrigUser account) $ \veid -> do + for_ (justThere veid.validScimIdAuthInfo) (SAMLUserStore.delete (userId account)) + ScimExternalIdStore.delete teamId veid.validScimIdExternal + ScimUserMetaStore.delete (userId account) + ---------------------------------------------------------------------------- -- Utilities diff --git a/tools/stern/test/integration/API.hs b/tools/stern/test/integration/API.hs index b0b30b5afb3..f882fc4c682 100644 --- a/tools/stern/test/integration/API.hs +++ b/tools/stern/test/integration/API.hs @@ -404,7 +404,7 @@ testCellsInternalConfig = do (_, tid, _) <- createTeamWithNMembers 1 cfg <- getFeatureConfig @CellsInternalConfig tid liftIO $ do - cfg.config.storage.totalLimitBytes @?= Just (QuotaBytesFinite (NumBytes (BigIntString 1000000000000))) + cfg.config.storage.totalLimitBytes @?= Just QuotaBytesUnlimited cfg.config.storage.perUserQuotaBytes @?= QuotaBytesUnlimited let newBackend :: HttpsUrl newBackend = fromMaybe (error "invalid url") . fromByteString $ "https://cells-internal.example.com" diff --git a/treefmt.toml b/treefmt.toml index 516cbd86fbb..cc49a82bf60 100644 --- a/treefmt.toml +++ b/treefmt.toml @@ -10,13 +10,6 @@ excludes = [ "dist-newstyle/" ] -[formatter.headroom] -command = "hack/bin/headroom-treefmt.sh" -includes = ["*.hs", "*.hsc", "*.rs"] -excludes = [ - "dist-newstyle/", - "services/wire-server-enterprise/*", -] [formatter.shellcheck] command = "shellcheck"