{
  "openapi": "3.0.0",
  "paths": {
    "/api/v1/me": {
      "get": {
        "operationId": "Me_me",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserProfileBody"
                },
                "example": {
                  "user_id": "client-john",
                  "display_name": "John Client",
                  "email": "john@example.com",
                  "avatar_url": null
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "The signed-in user's Chat profile",
        "tags": [
          "Context"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "principal_not_allowed",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Context in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/tenants-and-applications/"
        }
      }
    },
    "/api/v1/me/tenants": {
      "get": {
        "operationId": "Me_tenants",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantSummaryList"
                },
                "example": {
                  "items": [
                    {
                      "tenant_id": "fitness",
                      "name": "Fitness Inc.",
                      "slug": "fitness",
                      "logo_url": null
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Chat-enabled tenants the user belongs to",
        "tags": [
          "Context"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "principal_not_allowed",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Context in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/tenants-and-applications/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/applications": {
      "get": {
        "description": "Chat-enabled applications are listed only when the caller can access them; chat-disabled ones are listed with chat_enabled: false. A machine client, or a user token of a tenant application's own client, sees only its own application.",
        "operationId": "TenantContext_applications",
        "parameters": [
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApplicationSummaryList"
                },
                "example": {
                  "items": [
                    {
                      "application_id": "fitness-app",
                      "name": "Fitness App",
                      "slug": "fitness-app",
                      "logo_url": null,
                      "type": "TENANT",
                      "chat_enabled": true
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "The tenant's applications, with whether each can use Chat",
        "tags": [
          "Context"
        ],
        "x-audience": [
          "user",
          "machine"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ],
          "machine": [
            "chat:sync",
            "chat:conversations.read",
            "chat:conversations.manage",
            "chat:groups.manage",
            "chat:channels.manage",
            "chat:messages.send",
            "chat:users.lookup"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Context in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/tenants-and-applications/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/me/capabilities": {
      "get": {
        "operationId": "TenantContext_tenantCapabilities",
        "parameters": [
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CapabilitiesBody"
                },
                "example": {
                  "tenant_id": "fitness",
                  "application_id": "fitness-app",
                  "principal_type": "user",
                  "roles": [
                    "coach"
                  ],
                  "capabilities": [
                    "conversations.read",
                    "messages.read",
                    "messages.send",
                    "messages.update"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "The caller's tenant-level Chat permissions (e.g. administration.*)",
        "tags": [
          "Context"
        ],
        "x-audience": [
          "user",
          "machine"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ],
          "machine": [
            "chat:sync",
            "chat:conversations.read",
            "chat:conversations.manage",
            "chat:groups.manage",
            "chat:channels.manage",
            "chat:messages.send",
            "chat:users.lookup"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Context in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/tenants-and-applications/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/applications/{application_id}/me/capabilities": {
      "get": {
        "description": "Use it to show or hide controls; Chat enforces the permissions on every call regardless.",
        "operationId": "TenantContext_applicationCapabilities",
        "parameters": [
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CapabilitiesBody"
                },
                "example": {
                  "tenant_id": "fitness",
                  "application_id": "fitness-app",
                  "principal_type": "user",
                  "roles": [
                    "coach"
                  ],
                  "capabilities": [
                    "conversations.read",
                    "messages.read",
                    "messages.send",
                    "messages.update"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "The caller's Chat permissions in an application context",
        "tags": [
          "Context"
        ],
        "x-audience": [
          "user",
          "machine"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ],
          "machine": [
            "chat:sync",
            "chat:conversations.read",
            "chat:conversations.manage",
            "chat:groups.manage",
            "chat:channels.manage",
            "chat:messages.send",
            "chat:users.lookup"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "application_not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Context in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/tenants-and-applications/"
        }
      }
    },
    "/api/v1/notifications/vapid-public-key": {
      "get": {
        "operationId": "Notifications_getVapidPublicKey",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VapidPublicKeyBody"
                },
                "example": {
                  "public_key": "BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "summary": "Web push VAPID public key",
        "tags": [
          "Notifications"
        ],
        "x-audience": [
          "public"
        ],
        "externalDocs": {
          "description": "Notifications in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/realtime/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/notifications/push/devices": {
      "post": {
        "description": "web: the PushSubscription; fcm/apns: the native device token. Users only.",
        "operationId": "Notifications_registerDevice",
        "parameters": [
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterPushDeviceDto"
              },
              "example": {
                "platform": "web",
                "subscription": {
                  "endpoint": "https://push.example/send/abc",
                  "keys": {
                    "p256dh": "BN…",
                    "auth": "k8…"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No content. The device receives push notifications."
          },
          "400": {
            "description": "Error. `error` is one of: `invalid_request`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "invalid_request",
                  "message": "The request is malformed: a required field is missing, a value has the wrong type or format, or a field the route does not accept was sent",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Register a push device",
        "tags": [
          "Notifications"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-error-codes": [
          "invalid_request",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "principal_not_allowed",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Notifications in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/realtime/"
        }
      },
      "delete": {
        "operationId": "Notifications_unregisterDevice",
        "parameters": [
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UnregisterPushDeviceDto"
              },
              "example": {
                "token": "https://push.example/send/abc"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No content. The device no longer receives push notifications."
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Unregister a push device",
        "tags": [
          "Notifications"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "principal_not_allowed",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Notifications in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/realtime/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/applications/{application_id}/conversations": {
      "get": {
        "description": "Users: conversations they are a member of, plus PUBLIC channels. Machines: every conversation of the context. Most recently active first.",
        "operationId": "Conversations_list",
        "parameters": [
          {
            "name": "type",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "DIRECT",
                "GROUP",
                "CHANNEL"
              ],
              "type": "string"
            }
          },
          {
            "name": "before",
            "required": false,
            "in": "query",
            "description": "The `next_cursor` of the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversationPage"
                },
                "example": {
                  "items": [
                    {
                      "conversation_id": "6b1f4c7e-3c52-4a0a-9a39-7d2e2f1f8a10",
                      "tenant_id": "fitness",
                      "application_id": "fitness-app",
                      "type": "DIRECT",
                      "visibility": null,
                      "name": null,
                      "description": null,
                      "status": "ACTIVE",
                      "created_by_user_id": null,
                      "created_by_client_id": "2f1c9e5a-7f4d-4f0e-8c35-9b1a3d6e4c21",
                      "last_activity_at": "2026-10-14T09:30:00.000Z",
                      "created_at": "2026-10-14T09:00:00.000Z",
                      "updated_at": "2026-10-14T09:30:00.000Z",
                      "members": [
                        {
                          "user_id": "coach-ana",
                          "display_name": "Ana Coach",
                          "avatar_url": null
                        },
                        {
                          "user_id": "client-john",
                          "display_name": "John Client",
                          "avatar_url": null
                        }
                      ],
                      "member_count": 2,
                      "my_role": "MEMBER",
                      "has_unread": true
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "description": "Error. `error` is one of: `invalid_request`, `invalid_cursor`, `invalid_limit`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "invalid_request",
                  "message": "The request is malformed: a required field is missing, a value has the wrong type or format, or a field the route does not accept was sent",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List conversations",
        "tags": [
          "Conversations"
        ],
        "x-audience": [
          "user",
          "machine"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ],
          "machine": [
            "chat:sync",
            "chat:conversations.read"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "conversations.read"
          ]
        },
        "x-error-codes": [
          "invalid_request",
          "invalid_cursor",
          "invalid_limit",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "application_not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Conversations in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/conversations/"
        }
      },
      "post": {
        "description": "Needs conversations.create (+ groups.create / channels.create). DIRECT dedupes on its two members. Every member must be an eligible member of the tenant and application (422 target_user_not_eligible).",
        "operationId": "Conversations_create",
        "parameters": [
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateConversationDto"
              },
              "example": {
                "type": "DIRECT",
                "member_user_ids": [
                  "coach-ana",
                  "client-john"
                ],
                "actor_user_id": "coach-ana"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The conversation. For a DIRECT conversation that already exists, the existing one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversationBody"
                },
                "example": {
                  "conversation_id": "6b1f4c7e-3c52-4a0a-9a39-7d2e2f1f8a10",
                  "tenant_id": "fitness",
                  "application_id": "fitness-app",
                  "type": "DIRECT",
                  "visibility": null,
                  "name": null,
                  "description": null,
                  "status": "ACTIVE",
                  "created_by_user_id": null,
                  "created_by_client_id": "2f1c9e5a-7f4d-4f0e-8c35-9b1a3d6e4c21",
                  "last_activity_at": "2026-10-14T09:30:00.000Z",
                  "created_at": "2026-10-14T09:00:00.000Z",
                  "updated_at": "2026-10-14T09:30:00.000Z",
                  "members": [
                    {
                      "user_id": "coach-ana",
                      "display_name": "Ana Coach",
                      "avatar_url": null
                    },
                    {
                      "user_id": "client-john",
                      "display_name": "John Client",
                      "avatar_url": null
                    }
                  ],
                  "member_count": 2,
                  "my_role": "MEMBER",
                  "has_unread": true
                }
              }
            }
          },
          "400": {
            "description": "Error. `error` is one of: `invalid_request`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "invalid_request",
                  "message": "The request is malformed: a required field is missing, a value has the wrong type or format, or a field the route does not accept was sent",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "422": {
            "description": "Error. `error` is one of: `target_user_not_eligible`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 422,
                  "error": "target_user_not_eligible",
                  "message": "A user you referenced (member, actor) is not an active member of the tenant with access to the application.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Create a conversation",
        "tags": [
          "Conversations"
        ],
        "x-audience": [
          "user",
          "machine"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ],
          "machine": [
            "chat:sync",
            "chat:conversations.manage"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "conversations.create"
          ]
        },
        "x-error-codes": [
          "invalid_request",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "application_not_found",
          "target_user_not_eligible",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Conversations in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/conversations/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/applications/{application_id}/conversations/{conversation_id}": {
      "get": {
        "operationId": "Conversations_get",
        "parameters": [
          {
            "name": "conversation_id",
            "required": true,
            "in": "path",
            "description": "A Chat conversation id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversationBody"
                },
                "example": {
                  "conversation_id": "6b1f4c7e-3c52-4a0a-9a39-7d2e2f1f8a10",
                  "tenant_id": "fitness",
                  "application_id": "fitness-app",
                  "type": "DIRECT",
                  "visibility": null,
                  "name": null,
                  "description": null,
                  "status": "ACTIVE",
                  "created_by_user_id": null,
                  "created_by_client_id": "2f1c9e5a-7f4d-4f0e-8c35-9b1a3d6e4c21",
                  "last_activity_at": "2026-10-14T09:30:00.000Z",
                  "created_at": "2026-10-14T09:00:00.000Z",
                  "updated_at": "2026-10-14T09:30:00.000Z",
                  "members": [
                    {
                      "user_id": "coach-ana",
                      "display_name": "Ana Coach",
                      "avatar_url": null
                    },
                    {
                      "user_id": "client-john",
                      "display_name": "John Client",
                      "avatar_url": null
                    }
                  ],
                  "member_count": 2,
                  "my_role": "MEMBER",
                  "has_unread": true
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `not_conversation_member`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`, `not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get a conversation",
        "tags": [
          "Conversations"
        ],
        "x-audience": [
          "user",
          "machine"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ],
          "machine": [
            "chat:sync",
            "chat:conversations.read"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "conversations.read"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "not_conversation_member",
          "application_not_found",
          "not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Conversations in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/conversations/"
        }
      },
      "patch": {
        "description": "GROUP/CHANNEL: OWNER/ADMIN or groups.manage / channels.manage. DIRECT: only `status`, and only by a machine client (archive / reactivate).",
        "operationId": "Conversations_update",
        "parameters": [
          {
            "name": "conversation_id",
            "required": true,
            "in": "path",
            "description": "A Chat conversation id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateConversationDto"
              },
              "example": {
                "status": "ARCHIVED"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversationBody"
                },
                "example": {
                  "conversation_id": "6b1f4c7e-3c52-4a0a-9a39-7d2e2f1f8a10",
                  "tenant_id": "fitness",
                  "application_id": "fitness-app",
                  "type": "DIRECT",
                  "visibility": null,
                  "name": null,
                  "description": null,
                  "status": "ACTIVE",
                  "created_by_user_id": null,
                  "created_by_client_id": "2f1c9e5a-7f4d-4f0e-8c35-9b1a3d6e4c21",
                  "last_activity_at": "2026-10-14T09:30:00.000Z",
                  "created_at": "2026-10-14T09:00:00.000Z",
                  "updated_at": "2026-10-14T09:30:00.000Z",
                  "members": [
                    {
                      "user_id": "coach-ana",
                      "display_name": "Ana Coach",
                      "avatar_url": null
                    },
                    {
                      "user_id": "client-john",
                      "display_name": "John Client",
                      "avatar_url": null
                    }
                  ],
                  "member_count": 2,
                  "my_role": "MEMBER",
                  "has_unread": true
                }
              }
            }
          },
          "400": {
            "description": "Error. `error` is one of: `invalid_request`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "invalid_request",
                  "message": "The request is malformed: a required field is missing, a value has the wrong type or format, or a field the route does not accept was sent",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`, `not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "422": {
            "description": "Error. `error` is one of: `direct_conversation_immutable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 422,
                  "error": "direct_conversation_immutable",
                  "message": "Someone tried to change a DIRECT conversation other than its status, or a user tried to change its status.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Update a conversation",
        "tags": [
          "Conversations"
        ],
        "x-audience": [
          "user",
          "machine"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ],
          "machine": [
            "chat:sync",
            "chat:conversations.manage"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "conversations.update"
          ]
        },
        "x-error-codes": [
          "invalid_request",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "application_not_found",
          "not_found",
          "direct_conversation_immutable",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Conversations in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/conversations/"
        }
      },
      "delete": {
        "operationId": "Conversations_remove",
        "parameters": [
          {
            "name": "conversation_id",
            "required": true,
            "in": "path",
            "description": "A Chat conversation id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No content. The conversation is soft-deleted."
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`, `not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Delete a conversation (soft delete)",
        "tags": [
          "Conversations"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "conversations.delete"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "application_not_found",
          "not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Conversations in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/conversations/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/applications/{application_id}/conversations/{conversation_id}/members": {
      "get": {
        "operationId": "Conversations_listMembers",
        "parameters": [
          {
            "name": "conversation_id",
            "required": true,
            "in": "path",
            "description": "A Chat conversation id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "before",
            "required": false,
            "in": "query",
            "description": "The `next_cursor` of the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MemberPage"
                },
                "example": {
                  "items": [
                    {
                      "user_id": "client-john",
                      "display_name": "John Client",
                      "avatar_url": null,
                      "member_id": "9a7e1c52-3b6d-4d2f-8e40-1f5a6b7c8d90",
                      "role": "MEMBER",
                      "status": "ACTIVE",
                      "joined_at": "2026-10-14T09:00:00.000Z"
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "description": "Error. `error` is one of: `invalid_cursor`, `invalid_limit`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "invalid_cursor",
                  "message": "The `before` cursor is not one this list issued.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`, `not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List members",
        "tags": [
          "Conversations"
        ],
        "x-audience": [
          "user",
          "machine"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ],
          "machine": [
            "chat:sync",
            "chat:conversations.read"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "conversations.read"
          ]
        },
        "x-error-codes": [
          "invalid_cursor",
          "invalid_limit",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "application_not_found",
          "not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Conversations in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/conversations/"
        }
      },
      "post": {
        "description": "GROUP: groups.manage, or groups.create as OWNER/ADMIN. CHANNEL: channels.manage, or joining a PUBLIC channel yourself. DIRECT members never change.",
        "operationId": "Conversations_addMember",
        "parameters": [
          {
            "name": "conversation_id",
            "required": true,
            "in": "path",
            "description": "A Chat conversation id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddMemberDto"
              },
              "example": {
                "user_id": "client-sarah",
                "display_name": "Sarah Client"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MemberBody"
                },
                "example": {
                  "user_id": "client-john",
                  "display_name": "John Client",
                  "avatar_url": null,
                  "member_id": "9a7e1c52-3b6d-4d2f-8e40-1f5a6b7c8d90",
                  "role": "MEMBER",
                  "status": "ACTIVE",
                  "joined_at": "2026-10-14T09:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Error. `error` is one of: `invalid_request`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "invalid_request",
                  "message": "The request is malformed: a required field is missing, a value has the wrong type or format, or a field the route does not accept was sent",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`, `not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "422": {
            "description": "Error. `error` is one of: `target_user_not_eligible`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 422,
                  "error": "target_user_not_eligible",
                  "message": "A user you referenced (member, actor) is not an active member of the tenant with access to the application.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Add a member",
        "tags": [
          "Conversations"
        ],
        "x-audience": [
          "user",
          "machine"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ],
          "machine": [
            "chat:sync",
            "chat:groups.manage",
            "chat:channels.manage"
          ]
        },
        "x-error-codes": [
          "invalid_request",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "application_not_found",
          "not_found",
          "target_user_not_eligible",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Conversations in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/conversations/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/applications/{application_id}/conversations/{conversation_id}/members/{user_id}": {
      "delete": {
        "description": "Leaving (user_id = the caller) is always allowed; removing others follows the add rules.",
        "operationId": "Conversations_removeMember",
        "parameters": [
          {
            "name": "conversation_id",
            "required": true,
            "in": "path",
            "description": "A Chat conversation id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "user_id",
            "required": true,
            "in": "path",
            "description": "An Identity Server user id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No content. The member was removed, or left."
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`, `not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Remove a member, or leave",
        "tags": [
          "Conversations"
        ],
        "x-audience": [
          "user",
          "machine"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ],
          "machine": [
            "chat:sync",
            "chat:groups.manage",
            "chat:channels.manage"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "application_not_found",
          "not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Conversations in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/conversations/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/applications/{application_id}/conversations/{conversation_id}/messages": {
      "get": {
        "description": "Newest first. Deleted messages are tombstones (status DELETED, empty body).",
        "operationId": "Messages_list",
        "parameters": [
          {
            "name": "conversation_id",
            "required": true,
            "in": "path",
            "description": "A Chat conversation id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "before",
            "required": false,
            "in": "query",
            "description": "The `next_cursor` of the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessagePage"
                },
                "example": {
                  "items": [
                    {
                      "message_id": "0d9e6a52-8b0c-4c47-b1f2-5c9a2c1d7e33",
                      "conversation_id": "6b1f4c7e-3c52-4a0a-9a39-7d2e2f1f8a10",
                      "tenant_id": "fitness",
                      "application_id": "fitness-app",
                      "sender_user_id": "coach-ana",
                      "sender_client_id": null,
                      "sender": {
                        "user_id": "coach-ana",
                        "display_name": "Ana Coach",
                        "avatar_url": null
                      },
                      "body": "See you at 9!",
                      "message_type": "TEXT",
                      "reply_to_message_id": null,
                      "attachments": [],
                      "status": "ACTIVE",
                      "edited_at": null,
                      "deleted_at": null,
                      "created_at": "2026-10-14T09:30:00.000Z",
                      "updated_at": "2026-10-14T09:30:00.000Z",
                      "reactions": [
                        {
                          "emoji": "👍",
                          "count": 1,
                          "reacted_by_me": false
                        }
                      ],
                      "mentioned_user_ids": []
                    }
                  ],
                  "next_cursor": "0d9e6a52-8b0c-4c47-b1f2-5c9a2c1d7e32"
                }
              }
            }
          },
          "400": {
            "description": "Error. `error` is one of: `invalid_cursor`, `invalid_limit`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "invalid_cursor",
                  "message": "The `before` cursor is not one this list issued.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `not_conversation_member`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`, `not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List messages",
        "tags": [
          "Messages"
        ],
        "x-audience": [
          "user",
          "machine"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ],
          "machine": [
            "chat:sync",
            "chat:conversations.read"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "messages.read"
          ]
        },
        "x-error-codes": [
          "invalid_cursor",
          "invalid_limit",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "not_conversation_member",
          "application_not_found",
          "not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Messages in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/messages/"
        }
      },
      "post": {
        "description": "Needs membership; 422 conversation_archived when the conversation is not ACTIVE. Machines send on behalf of `actor_user_id`, or a sender-less SYSTEM message.",
        "operationId": "Messages_send",
        "parameters": [
          {
            "name": "conversation_id",
            "required": true,
            "in": "path",
            "description": "A Chat conversation id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendMessageDto"
              },
              "example": {
                "body": "See you at 9!",
                "actor_user_id": "coach-ana"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageBody"
                },
                "example": {
                  "message_id": "0d9e6a52-8b0c-4c47-b1f2-5c9a2c1d7e33",
                  "conversation_id": "6b1f4c7e-3c52-4a0a-9a39-7d2e2f1f8a10",
                  "tenant_id": "fitness",
                  "application_id": "fitness-app",
                  "sender_user_id": "coach-ana",
                  "sender_client_id": null,
                  "sender": {
                    "user_id": "coach-ana",
                    "display_name": "Ana Coach",
                    "avatar_url": null
                  },
                  "body": "See you at 9!",
                  "message_type": "TEXT",
                  "reply_to_message_id": null,
                  "attachments": [],
                  "status": "ACTIVE",
                  "edited_at": null,
                  "deleted_at": null,
                  "created_at": "2026-10-14T09:30:00.000Z",
                  "updated_at": "2026-10-14T09:30:00.000Z",
                  "reactions": [
                    {
                      "emoji": "👍",
                      "count": 1,
                      "reacted_by_me": false
                    }
                  ],
                  "mentioned_user_ids": []
                }
              }
            }
          },
          "400": {
            "description": "Error. `error` is one of: `invalid_request`, `body_too_long`, `too_many_attachments`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "invalid_request",
                  "message": "The request is malformed: a required field is missing, a value has the wrong type or format, or a field the route does not accept was sent",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `not_conversation_member`, `system_message_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`, `not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "422": {
            "description": "Error. `error` is one of: `conversation_archived`, `invalid_reply`, `actor_not_member`, `target_user_not_eligible`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 422,
                  "error": "conversation_archived",
                  "message": "Someone tried to post to an archived conversation",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Send a message",
        "tags": [
          "Messages"
        ],
        "x-audience": [
          "user",
          "machine"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ],
          "machine": [
            "chat:sync",
            "chat:messages.send"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "messages.send"
          ]
        },
        "x-error-codes": [
          "invalid_request",
          "body_too_long",
          "too_many_attachments",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "not_conversation_member",
          "system_message_not_allowed",
          "application_not_found",
          "not_found",
          "conversation_archived",
          "invalid_reply",
          "actor_not_member",
          "target_user_not_eligible",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Messages in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/messages/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/applications/{application_id}/conversations/{conversation_id}/messages/{message_id}": {
      "patch": {
        "description": "The author with messages.update, or a moderator with messages.delete.",
        "operationId": "Messages_edit",
        "parameters": [
          {
            "name": "conversation_id",
            "required": true,
            "in": "path",
            "description": "A Chat conversation id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "message_id",
            "required": true,
            "in": "path",
            "description": "A Chat message id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EditMessageDto"
              },
              "example": {
                "body": "See you at 9:30!"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageBody"
                },
                "example": {
                  "message_id": "0d9e6a52-8b0c-4c47-b1f2-5c9a2c1d7e33",
                  "conversation_id": "6b1f4c7e-3c52-4a0a-9a39-7d2e2f1f8a10",
                  "tenant_id": "fitness",
                  "application_id": "fitness-app",
                  "sender_user_id": "coach-ana",
                  "sender_client_id": null,
                  "sender": {
                    "user_id": "coach-ana",
                    "display_name": "Ana Coach",
                    "avatar_url": null
                  },
                  "body": "See you at 9!",
                  "message_type": "TEXT",
                  "reply_to_message_id": null,
                  "attachments": [],
                  "status": "ACTIVE",
                  "edited_at": null,
                  "deleted_at": null,
                  "created_at": "2026-10-14T09:30:00.000Z",
                  "updated_at": "2026-10-14T09:30:00.000Z",
                  "reactions": [
                    {
                      "emoji": "👍",
                      "count": 1,
                      "reacted_by_me": false
                    }
                  ],
                  "mentioned_user_ids": []
                }
              }
            }
          },
          "400": {
            "description": "Error. `error` is one of: `invalid_request`, `body_too_long`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "invalid_request",
                  "message": "The request is malformed: a required field is missing, a value has the wrong type or format, or a field the route does not accept was sent",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`, `not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Edit a message",
        "tags": [
          "Messages"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "any": [
            "messages.update",
            "messages.delete"
          ]
        },
        "x-error-codes": [
          "invalid_request",
          "body_too_long",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "application_not_found",
          "not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Messages in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/messages/"
        }
      },
      "delete": {
        "description": "The author with messages.update, or a moderator with messages.delete. Never machines.",
        "operationId": "Messages_remove",
        "parameters": [
          {
            "name": "conversation_id",
            "required": true,
            "in": "path",
            "description": "A Chat conversation id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "message_id",
            "required": true,
            "in": "path",
            "description": "A Chat message id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No content. The message is now a tombstone."
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`, `not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Delete a message (tombstone)",
        "tags": [
          "Messages"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "any": [
            "messages.update",
            "messages.delete"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "application_not_found",
          "not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Messages in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/messages/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/applications/{application_id}/conversations/{conversation_id}/messages/{message_id}/reactions": {
      "post": {
        "description": "Users only.",
        "operationId": "Messages_addReaction",
        "parameters": [
          {
            "name": "conversation_id",
            "required": true,
            "in": "path",
            "description": "A Chat conversation id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "message_id",
            "required": true,
            "in": "path",
            "description": "A Chat message id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddReactionDto"
              },
              "example": {
                "emoji": "👍"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No content. The reaction was added."
          },
          "400": {
            "description": "Error. `error` is one of: `invalid_request`, `user_required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "invalid_request",
                  "message": "The request is malformed: a required field is missing, a value has the wrong type or format, or a field the route does not accept was sent",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`, `not_conversation_member`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`, `not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Add a reaction",
        "tags": [
          "Messages"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "messages.read"
          ]
        },
        "x-error-codes": [
          "invalid_request",
          "user_required",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "not_conversation_member",
          "application_not_found",
          "not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Messages in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/messages/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/applications/{application_id}/conversations/{conversation_id}/messages/{message_id}/reactions/{emoji}": {
      "delete": {
        "description": "Users only.",
        "operationId": "Messages_removeReaction",
        "parameters": [
          {
            "name": "conversation_id",
            "required": true,
            "in": "path",
            "description": "A Chat conversation id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "message_id",
            "required": true,
            "in": "path",
            "description": "A Chat message id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "emoji",
            "required": true,
            "in": "path",
            "description": "The reaction, URL-encoded.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No content. The reaction was removed."
          },
          "400": {
            "description": "Error. `error` is one of: `user_required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "user_required",
                  "message": "A machine token called a route that acts as a signed-in user (reactions, read state, typing).",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`, `not_conversation_member`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`, `not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Remove a reaction",
        "tags": [
          "Messages"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "messages.read"
          ]
        },
        "x-error-codes": [
          "user_required",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "not_conversation_member",
          "application_not_found",
          "not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Messages in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/messages/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/applications/{application_id}/conversations/{conversation_id}/read": {
      "post": {
        "description": "Up to `message_id`, default the latest message. Users only.",
        "operationId": "Messages_markRead",
        "parameters": [
          {
            "name": "conversation_id",
            "required": true,
            "in": "path",
            "description": "A Chat conversation id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MarkReadDto"
              },
              "example": {
                "message_id": "0d9e6a52-8b0c-4c47-b1f2-5c9a2c1d7e33"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No content. The read state was updated."
          },
          "400": {
            "description": "Error. `error` is one of: `user_required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "user_required",
                  "message": "A machine token called a route that acts as a signed-in user (reactions, read state, typing).",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`, `not_conversation_member`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`, `not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Mark read",
        "tags": [
          "Messages"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "messages.read"
          ]
        },
        "x-error-codes": [
          "user_required",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "not_conversation_member",
          "application_not_found",
          "not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Messages in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/messages/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/applications/{application_id}/conversations/{conversation_id}/typing": {
      "post": {
        "description": "Ephemeral, never stored. Users only.",
        "operationId": "Messages_typing",
        "parameters": [
          {
            "name": "conversation_id",
            "required": true,
            "in": "path",
            "description": "A Chat conversation id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No content. Members see the typing indicator."
          },
          "400": {
            "description": "Error. `error` is one of: `user_required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "user_required",
                  "message": "A machine token called a route that acts as a signed-in user (reactions, read state, typing).",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`, `not_conversation_member`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`, `not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Signal typing",
        "tags": [
          "Messages"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "messages.read"
          ]
        },
        "x-error-codes": [
          "user_required",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "not_conversation_member",
          "application_not_found",
          "not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Messages in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/messages/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/applications/{application_id}/notifications/realtime-token": {
      "get": {
        "description": "Subscribe-only: the caller's own channel, CHANNEL conversations they are in, and optionally one PUBLIC channel they are viewing. Users only.",
        "operationId": "RealtimeToken_realtimeToken",
        "parameters": [
          {
            "name": "conversation_id",
            "required": false,
            "in": "query",
            "description": "A PUBLIC channel being viewed.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RealtimeTokenBody"
                },
                "example": {
                  "stream_url": "https://realtime.example/sse?token=…",
                  "expires": 1791970800000,
                  "user_id": "coach-ana"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Realtime stream credential",
        "tags": [
          "Notifications"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "principal_not_allowed",
          "application_not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Notifications in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/realtime/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/applications/{application_id}/users/lookup": {
      "get": {
        "description": "Members Chat already knows (min 2 characters, max 20 results); with users.lookup.directory also the Identity Server directory.",
        "operationId": "UserLookup_search",
        "parameters": [
          {
            "name": "q",
            "required": true,
            "in": "query",
            "description": "At least 2 characters.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server id of a chat-enabled tenant application.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserProfileList"
                },
                "example": {
                  "items": [
                    {
                      "user_id": "client-john",
                      "display_name": "John Client",
                      "email": "john@example.com",
                      "avatar_url": null
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Error. `error` is one of: `query_too_short`, `query_too_long`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "query_too_short",
                  "message": "The user lookup query `q` has fewer than 2 characters.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `application_not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "application_not_found",
                  "message": "The application does not exist in the tenant, or Chat is not enabled for it.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Look up tenant members",
        "tags": [
          "Users"
        ],
        "x-audience": [
          "user",
          "machine"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ],
          "machine": [
            "chat:sync",
            "chat:users.lookup"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "users.lookup"
          ]
        },
        "x-error-codes": [
          "query_too_short",
          "query_too_long",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "application_not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Users in the guides",
          "url": "https://docs.chat.centralcodestation.com/guides/backend/lookup-users/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/presence/heartbeat": {
      "post": {
        "description": "About every 30 s while the app is in the foreground. Users only; presence is tenant-wide.",
        "operationId": "Presence_heartbeat",
        "parameters": [
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No content. The user is online for the next minute."
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Presence heartbeat",
        "tags": [
          "Presence"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "principal_not_allowed",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Presence in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/presence/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/presence/offline": {
      "post": {
        "operationId": "Presence_markOffline",
        "parameters": [
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No content. The user is offline."
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Go offline",
        "tags": [
          "Presence"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "principal_not_allowed",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Presence in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/presence/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/presence": {
      "get": {
        "description": "Ids that are not members of the tenant are dropped.",
        "operationId": "Presence_statuses",
        "parameters": [
          {
            "name": "user_ids",
            "required": false,
            "in": "query",
            "description": "Comma-separated user ids.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PresenceStatusList"
                },
                "example": {
                  "items": [
                    {
                      "user_id": "client-john",
                      "status": "online",
                      "last_seen_at": "2026-10-14T09:29:40.000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Presence of users",
        "tags": [
          "Presence"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "principal_not_allowed",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Presence in the guides",
          "url": "https://docs.chat.centralcodestation.com/concepts/presence/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/admin/overview": {
      "get": {
        "operationId": "Administration_overview",
        "parameters": [
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminOverviewBody"
                },
                "example": {
                  "tenant": {
                    "tenant_id": "fitness",
                    "name": "Fitness Inc.",
                    "slug": "fitness",
                    "logo_url": null
                  },
                  "applications": 3,
                  "chat_enabled_applications": 2,
                  "members": 48,
                  "conversations": {
                    "direct": 30,
                    "group": 4,
                    "channel": 2,
                    "total": 36
                  }
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Tenant overview",
        "tags": [
          "Administration"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "administration.read"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Administration in the guides",
          "url": "https://docs.chat.centralcodestation.com/administration/overview/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/admin/role-permissions": {
      "get": {
        "operationId": "Administration_rolePermissions",
        "parameters": [
          {
            "name": "application_id",
            "required": false,
            "in": "query",
            "description": "A chat-enabled tenant application; omit for the tenant-wide mapping.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RolePermissionsBody"
                },
                "example": {
                  "application_id": "fitness-app",
                  "available_capabilities": [
                    {
                      "key": "conversations.read",
                      "description": "List and open conversations the caller belongs to."
                    },
                    {
                      "key": "messages.send",
                      "description": "Send messages."
                    }
                  ],
                  "missing_capabilities": [],
                  "items": [
                    {
                      "role_id": "role-owner",
                      "role": "tenant_owner",
                      "display_name": "Owner",
                      "role_scope": "tenant",
                      "system": true,
                      "locked": true,
                      "capabilities": [
                        "conversations.read",
                        "messages.send"
                      ]
                    },
                    {
                      "role_id": "role-coach",
                      "role": "coach",
                      "display_name": "Coach",
                      "role_scope": "application",
                      "system": false,
                      "locked": false,
                      "capabilities": [
                        "conversations.read",
                        "messages.read",
                        "messages.send",
                        "messages.update"
                      ]
                    }
                  ],
                  "note": "Roles and their assignment to people are managed in the Identity Server."
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "The tenant's roles with their Chat capabilities in one context",
        "tags": [
          "Administration"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "administration.read"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Administration in the guides",
          "url": "https://docs.chat.centralcodestation.com/administration/overview/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/admin/role-permissions/{role_id}": {
      "put": {
        "description": "Stored at the Identity Server. tenant_owner is locked (400).",
        "operationId": "Administration_setRolePermissions",
        "parameters": [
          {
            "name": "role_id",
            "required": true,
            "in": "path",
            "description": "An Identity Server role id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "application_id",
            "required": false,
            "in": "query",
            "description": "A chat-enabled tenant application; omit for the tenant-wide mapping.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetRolePermissionsDto"
              },
              "example": {
                "capabilities": [
                  "conversations.read",
                  "messages.read",
                  "messages.send",
                  "messages.update"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RolePermissionBody"
                },
                "example": {
                  "role_id": "role-coach",
                  "role": "coach",
                  "display_name": "Coach",
                  "role_scope": "application",
                  "system": false,
                  "locked": false,
                  "capabilities": [
                    "conversations.read",
                    "messages.read",
                    "messages.send",
                    "messages.update"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Error. `error` is one of: `invalid_request`, `role_locked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "invalid_request",
                  "message": "The request is malformed: a required field is missing, a value has the wrong type or format, or a field the route does not accept was sent",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `not_found`, `role_not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "not_found",
                  "message": "The resource does not exist, or belongs to another tenant or application",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Replace a role's Chat capabilities in one context",
        "tags": [
          "Administration"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "administration.manage"
          ]
        },
        "x-error-codes": [
          "invalid_request",
          "role_locked",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "not_found",
          "role_not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Administration in the guides",
          "url": "https://docs.chat.centralcodestation.com/administration/overview/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/admin/members": {
      "get": {
        "operationId": "Administration_members",
        "parameters": [
          {
            "name": "q",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "before",
            "required": false,
            "in": "query",
            "description": "The `next_cursor` of the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminMemberPage"
                },
                "example": {
                  "items": [
                    {
                      "user_id": "coach-ana",
                      "display_name": "Ana Coach",
                      "email": "ana@example.com",
                      "avatar_url": null,
                      "roles": [
                        "coach"
                      ],
                      "capabilities": [
                        "conversations.read",
                        "messages.send"
                      ],
                      "roles_synced_at": "2026-10-14T09:00:00.000Z"
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Members known to Chat, with their roles and capabilities",
        "tags": [
          "Administration"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "administration.read"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Administration in the guides",
          "url": "https://docs.chat.centralcodestation.com/administration/overview/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/admin/applications": {
      "get": {
        "operationId": "Administration_applications",
        "parameters": [
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminApplicationList"
                },
                "example": {
                  "items": [
                    {
                      "application_id": "fitness-app",
                      "name": "Fitness App",
                      "slug": "fitness-app",
                      "logo_url": null,
                      "type": "TENANT",
                      "access_mode": "ALL_TENANT_MEMBERS",
                      "identity_status": "ACTIVE",
                      "chat_enabled": true,
                      "synced_at": "2026-10-14T09:00:00.000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "The tenant's applications as Chat stores them",
        "tags": [
          "Administration"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "administration.read"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Administration in the guides",
          "url": "https://docs.chat.centralcodestation.com/administration/overview/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/admin/settings": {
      "get": {
        "operationId": "Administration_settings",
        "parameters": [
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SettingsBody"
                },
                "example": {
                  "message_retention_days": 365
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Chat settings",
        "tags": [
          "Administration"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "administration.read"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Administration in the guides",
          "url": "https://docs.chat.centralcodestation.com/administration/overview/"
        }
      },
      "patch": {
        "operationId": "Administration_updateSettings",
        "parameters": [
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateSettingsDto"
              },
              "example": {
                "message_retention_days": 365
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SettingsBody"
                },
                "example": {
                  "message_retention_days": 365
                }
              }
            }
          },
          "400": {
            "description": "Error. `error` is one of: `invalid_request`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "invalid_request",
                  "message": "The request is malformed: a required field is missing, a value has the wrong type or format, or a field the route does not accept was sent",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Update Chat settings",
        "tags": [
          "Administration"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "administration.manage"
          ]
        },
        "x-error-codes": [
          "invalid_request",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Administration in the guides",
          "url": "https://docs.chat.centralcodestation.com/administration/overview/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/admin/identity-refresh": {
      "post": {
        "description": "Expires every stored Identity Server row of the tenant.",
        "operationId": "Administration_identityRefresh",
        "parameters": [
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No content."
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Refresh from the Identity Server",
        "tags": [
          "Administration"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "administration.manage"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Administration in the guides",
          "url": "https://docs.chat.centralcodestation.com/administration/overview/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/admin/conversations": {
      "get": {
        "operationId": "Administration_conversations",
        "parameters": [
          {
            "name": "application_id",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "DIRECT",
                "GROUP",
                "CHANNEL"
              ],
              "type": "string"
            }
          },
          {
            "name": "before",
            "required": false,
            "in": "query",
            "description": "The `next_cursor` of the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversationPage"
                },
                "example": {
                  "items": [
                    {
                      "conversation_id": "6b1f4c7e-3c52-4a0a-9a39-7d2e2f1f8a10",
                      "tenant_id": "fitness",
                      "application_id": "fitness-app",
                      "type": "DIRECT",
                      "visibility": null,
                      "name": null,
                      "description": null,
                      "status": "ACTIVE",
                      "created_by_user_id": null,
                      "created_by_client_id": "2f1c9e5a-7f4d-4f0e-8c35-9b1a3d6e4c21",
                      "last_activity_at": "2026-10-14T09:30:00.000Z",
                      "created_at": "2026-10-14T09:00:00.000Z",
                      "updated_at": "2026-10-14T09:30:00.000Z",
                      "members": [
                        {
                          "user_id": "coach-ana",
                          "display_name": "Ana Coach",
                          "avatar_url": null
                        },
                        {
                          "user_id": "client-john",
                          "display_name": "John Client",
                          "avatar_url": null
                        }
                      ],
                      "member_count": 2,
                      "my_role": "MEMBER",
                      "has_unread": true
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "description": "Error. `error` is one of: `invalid_cursor`, `invalid_limit`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "invalid_cursor",
                  "message": "The `before` cursor is not one this list issued.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Every conversation of the tenant (moderation)",
        "tags": [
          "Administration"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "administration.read"
          ]
        },
        "x-error-codes": [
          "invalid_cursor",
          "invalid_limit",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Administration in the guides",
          "url": "https://docs.chat.centralcodestation.com/administration/overview/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/admin/conversations/{conversation_id}": {
      "delete": {
        "operationId": "Administration_deleteConversation",
        "parameters": [
          {
            "name": "conversation_id",
            "required": true,
            "in": "path",
            "description": "A Chat conversation id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No content."
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "not_found",
                  "message": "The resource does not exist, or belongs to another tenant or application",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Delete a conversation (moderation)",
        "tags": [
          "Administration"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "administration.manage"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Administration in the guides",
          "url": "https://docs.chat.centralcodestation.com/administration/overview/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/admin/conversations/{conversation_id}/members/{user_id}": {
      "delete": {
        "operationId": "Administration_removeMember",
        "parameters": [
          {
            "name": "conversation_id",
            "required": true,
            "in": "path",
            "description": "A Chat conversation id (uuid).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "user_id",
            "required": true,
            "in": "path",
            "description": "An Identity Server user id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No content."
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "404": {
            "description": "Error. `error` is one of: `not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 404,
                  "error": "not_found",
                  "message": "The resource does not exist, or belongs to another tenant or application",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Remove a member from a conversation (moderation)",
        "tags": [
          "Administration"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "administration.manage"
          ]
        },
        "x-error-codes": [
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "not_found",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Administration in the guides",
          "url": "https://docs.chat.centralcodestation.com/administration/overview/"
        }
      }
    },
    "/api/v1/tenants/{tenant_id}/admin/audit-logs": {
      "get": {
        "operationId": "Administration_auditLogs",
        "parameters": [
          {
            "name": "action",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "actor_user_id",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "before",
            "required": false,
            "in": "query",
            "description": "The `next_cursor` of the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "tenant_id",
            "required": true,
            "in": "path",
            "description": "The Identity Server tenant id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditLogPage"
                },
                "example": {
                  "items": [
                    {
                      "audit_id": "3c8f1a52-6d1e-4b7e-9a20-0e5d7b1c2f44",
                      "tenant_id": "fitness",
                      "application_id": "fitness-app",
                      "actor_type": "CLIENT",
                      "actor_user_id": null,
                      "actor_client_id": "2f1c9e5a-7f4d-4f0e-8c35-9b1a3d6e4c21",
                      "action": "CONVERSATION_CREATED",
                      "target_type": "CONVERSATION",
                      "target_id": "6b1f4c7e-3c52-4a0a-9a39-7d2e2f1f8a10",
                      "metadata": {
                        "type": "DIRECT"
                      },
                      "changes": null,
                      "request_id": null,
                      "ip": null,
                      "user_agent": null,
                      "created_at": "2026-10-14T09:00:00.000Z"
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "description": "Error. `error` is one of: `invalid_cursor`, `invalid_limit`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 400,
                  "error": "invalid_cursor",
                  "message": "The `before` cursor is not one this list issued.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Error. `error` is one of: `invalid_token`, `token_revoked`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 401,
                  "error": "invalid_token",
                  "message": "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "403": {
            "description": "Error. `error` is one of: `not_tenant_member`, `no_application_access`, `tenant_not_available`, `insufficient_scope`, `client_context_mismatch`, `missing_capability`, `principal_not_allowed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 403,
                  "error": "not_tenant_member",
                  "message": "The user is not an active member of the tenant in the URL.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "429": {
            "description": "Error. `error` is one of: `rate_limited`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 429,
                  "error": "rate_limited",
                  "message": "The caller exceeded a rate limit",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "503": {
            "description": "Error. `error` is one of: `identity_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                },
                "example": {
                  "status_code": 503,
                  "error": "identity_unavailable",
                  "message": "Chat could not reach the Identity Server and has no fresh cached answer.",
                  "path": "/api/v1/tenants/fitness/applications/fitness-app/conversations",
                  "timestamp": "2026-10-14T09:30:00.000Z"
                }
              }
            }
          },
          "default": {
            "description": "Error — see `error` for the code.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Audit log",
        "tags": [
          "Administration"
        ],
        "x-audience": [
          "user"
        ],
        "x-required-scopes": {
          "user": [
            "chat:access"
          ]
        },
        "x-required-capabilities": {
          "all": [
            "administration.read"
          ]
        },
        "x-error-codes": [
          "invalid_cursor",
          "invalid_limit",
          "invalid_token",
          "token_revoked",
          "not_tenant_member",
          "no_application_access",
          "tenant_not_available",
          "insufficient_scope",
          "client_context_mismatch",
          "missing_capability",
          "principal_not_allowed",
          "rate_limited",
          "identity_unavailable"
        ],
        "externalDocs": {
          "description": "Administration in the guides",
          "url": "https://docs.chat.centralcodestation.com/administration/overview/"
        }
      }
    }
  },
  "info": {
    "title": "CCS Chat API",
    "description": "REST API of chat.centralcodestation.com. Every route is under `/api/v1`; routes are kebab-case and every field is snake_case.\n\nAuthentication: a bearer access token issued by the CCS Identity Server for the Chat API resource (`aud` = `chat-api`).\n- **User tokens** need the `chat:access` scope. What the user may do comes from their Chat permissions in the tenant/application context. A token issued to a tenant application's own client works only in that application.\n- **Machine tokens** (`client_credentials`) need `chat:sync` or a granular scope (`chat:conversations.read`, `chat:conversations.manage`, `chat:groups.manage`, `chat:channels.manage`, `chat:messages.send`, `chat:users.lookup`) and work only in their own tenant and TENANT application.\n\nErrors are `{ status_code, error, message, path, timestamp }`; `error` is a stable snake_case code. Lists page with `?before=<next_cursor>&limit=` (max 100).",
    "version": "1.0",
    "contact": {
      "name": "CCS Chat support",
      "url": "https://docs.chat.centralcodestation.com/resources/support/",
      "email": ""
    }
  },
  "tags": [
    {
      "name": "Context",
      "description": "Who the caller is and where they may use Chat: profile, tenants, applications, and the caller's Chat permissions.",
      "externalDocs": {
        "description": "Learn more",
        "url": "https://docs.chat.centralcodestation.com/concepts/tenants-and-applications/"
      }
    },
    {
      "name": "Conversations",
      "description": "Direct conversations, groups and channels, and their members.",
      "externalDocs": {
        "description": "Learn more",
        "url": "https://docs.chat.centralcodestation.com/concepts/conversations/"
      }
    },
    {
      "name": "Messages",
      "description": "Messages, replies, reactions, read state and typing.",
      "externalDocs": {
        "description": "Learn more",
        "url": "https://docs.chat.centralcodestation.com/concepts/messages/"
      }
    },
    {
      "name": "Users",
      "description": "Look up tenant members.",
      "externalDocs": {
        "description": "Learn more",
        "url": "https://docs.chat.centralcodestation.com/guides/backend/lookup-users/"
      }
    },
    {
      "name": "Presence",
      "description": "Who is online in a tenant.",
      "externalDocs": {
        "description": "Learn more",
        "url": "https://docs.chat.centralcodestation.com/concepts/presence/"
      }
    },
    {
      "name": "Notifications",
      "description": "Realtime stream credentials and web push registration.",
      "externalDocs": {
        "description": "Learn more",
        "url": "https://docs.chat.centralcodestation.com/concepts/realtime/"
      }
    },
    {
      "name": "Administration",
      "description": "Chat Administration for tenant owners and admins: role permissions, settings, moderation, audit log.",
      "externalDocs": {
        "description": "Learn more",
        "url": "https://docs.chat.centralcodestation.com/administration/overview/"
      }
    }
  ],
  "servers": [
    {
      "url": "https://chat.centralcodestation.com",
      "description": "Production (routes are under /api/v1)"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearer": {
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "type": "http"
      }
    },
    "schemas": {
      "ErrorBody": {
        "type": "object",
        "properties": {
          "status_code": {
            "type": "number",
            "example": 403
          },
          "error": {
            "type": "string",
            "example": "missing_capability",
            "description": "Stable snake_case error code.",
            "enum": [
              "invalid_request",
              "invalid_cursor",
              "invalid_limit",
              "body_too_long",
              "query_too_short",
              "query_too_long",
              "user_required",
              "invalid_json",
              "invalid_id_token",
              "invalid_redirect_uri",
              "too_many_attachments",
              "role_locked",
              "invalid_grant",
              "invalid_token",
              "token_revoked",
              "missing_capability",
              "insufficient_scope",
              "not_tenant_member",
              "no_application_access",
              "tenant_not_available",
              "not_conversation_member",
              "client_context_mismatch",
              "principal_not_allowed",
              "system_message_not_allowed",
              "chat_access_not_granted",
              "not_found",
              "application_not_found",
              "role_not_found",
              "payload_too_large",
              "target_user_not_eligible",
              "actor_not_member",
              "conversation_archived",
              "direct_conversation_immutable",
              "invalid_reply",
              "rate_limited",
              "server_error",
              "identity_unavailable"
            ],
            "x-enum-descriptions": [
              "The request is malformed: a required field is missing, a value has the wrong type or format, or a field the route does not accept was sent. `message` lists every problem.",
              "The `before` cursor is not one this list issued.",
              "`limit` is not a positive integer.",
              "The message body is longer than the maximum message length.",
              "The user lookup query `q` has fewer than 2 characters.",
              "The user lookup query `q` is longer than the maximum.",
              "A machine token called a route that acts as a signed-in user (reactions, read state, typing).",
              "The request body is not valid JSON.",
              "Chat web sign-in only: the ID token returned by the Identity Server failed validation.",
              "Chat web sign-in only: the `redirect_uri` is not registered for Chat web.",
              "The message has more attachments than the maximum per message.",
              "Administration: the role cannot be changed (the tenant owner always holds every permission).",
              "An OAuth grant was refused. Chat's own web sign-in returns it for an invalid, expired or already used code or refresh token. Your backend also meets it from the Identity Server when a token exchange fails because the user's own token expired or their session ended.",
              "The bearer token is missing, malformed, expired, signed by an unknown key, has the wrong audience (`aud` must be `chat-api`), or lacks the required scope.",
              "The token was revoked at the Identity Server (sign-out, user disabled, removed from the tenant). Only checked on administration writes when strict revocation is on.",
              "The caller lacks the Chat permission (capability) the route needs, in this tenant application. `message` names it.",
              "A machine token does not carry a scope that grants the route's capability, or a user token lacks `chat:access`.",
              "The user is not an active member of the tenant in the URL.",
              "The user has no access to the application in the URL.",
              "The tenant is not active or has Chat switched off.",
              "The user is not an active member of the conversation (and it is not a PUBLIC channel).",
              "The token was issued to a client of another tenant or application than the one in the URL. Machine tokens and tokens of a tenant application's client work only in their own context.",
              "The route does not accept this kind of token: user-only routes reject machine tokens.",
              "A user tried to send a SYSTEM message. Only machine clients may.",
              "Chat web sign-in only: the Identity Server did not grant the user a Chat access token (audience `chat-api`, scope `chat:access`).",
              "The resource does not exist, or belongs to another tenant or application. Chat does not reveal which.",
              "The application does not exist in the tenant, or Chat is not enabled for it.",
              "Administration: the role is not part of the chosen context.",
              "The request body is larger than 256 kB.",
              "A user you referenced (member, actor) is not an active member of the tenant with access to the application.",
              "The `actor_user_id` of an on-behalf-of message is not a member of the conversation.",
              "Someone tried to post to an archived conversation. Archived conversations are read-only.",
              "Someone tried to change a DIRECT conversation other than its status, or a user tried to change its status.",
              "`reply_to_message_id` does not name a message of the same conversation.",
              "The caller exceeded a rate limit. The `Retry-After` header says how many seconds to wait.",
              "An unexpected error in Chat.",
              "Chat could not reach the Identity Server and has no fresh cached answer."
            ]
          },
          "message": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ],
            "example": "Missing Chat capability messages.send"
          },
          "path": {
            "type": "string",
            "example": "/api/v1/tenants/t1/applications/a1/conversations"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "status_code",
          "error",
          "message",
          "path",
          "timestamp"
        ]
      },
      "ExchangeCodeRequestDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "maxLength": 2048
          },
          "code_verifier": {
            "type": "string",
            "minLength": 43,
            "maxLength": 128
          },
          "redirect_uri": {
            "type": "string",
            "description": "One of the Chat web client’s registered redirect URIs."
          },
          "nonce": {
            "type": "string"
          }
        },
        "required": [
          "code",
          "code_verifier",
          "redirect_uri",
          "nonce"
        ]
      },
      "TokenResponseBody": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string"
          },
          "refresh_token": {
            "type": "string",
            "nullable": true
          },
          "id_token": {
            "type": "string",
            "nullable": true
          },
          "expires_in": {
            "type": "number",
            "description": "Seconds."
          },
          "token_type": {
            "type": "string",
            "example": "Bearer"
          }
        },
        "required": [
          "access_token",
          "refresh_token",
          "id_token",
          "expires_in",
          "token_type"
        ]
      },
      "RefreshTokenRequestDto": {
        "type": "object",
        "properties": {
          "refresh_token": {
            "type": "string"
          }
        },
        "required": [
          "refresh_token"
        ]
      },
      "UserProfileBody": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "nullable": true
          },
          "avatar_url": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "user_id",
          "display_name",
          "email",
          "avatar_url"
        ]
      },
      "TenantSummaryBody": {
        "type": "object",
        "properties": {
          "tenant_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "logo_url": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "tenant_id",
          "name",
          "slug",
          "logo_url"
        ]
      },
      "TenantSummaryList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TenantSummaryBody"
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "ApplicationSummaryBody": {
        "type": "object",
        "properties": {
          "application_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "logo_url": {
            "type": "string",
            "nullable": true
          },
          "type": {
            "type": "string",
            "enum": [
              "PLATFORM",
              "TENANT"
            ]
          },
          "chat_enabled": {
            "type": "boolean"
          }
        },
        "required": [
          "application_id",
          "name",
          "slug",
          "logo_url",
          "type",
          "chat_enabled"
        ]
      },
      "ApplicationSummaryList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApplicationSummaryBody"
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "CapabilitiesBody": {
        "type": "object",
        "properties": {
          "tenant_id": {
            "type": "string"
          },
          "application_id": {
            "type": "string",
            "nullable": true,
            "description": "null on the tenant-level route."
          },
          "principal_type": {
            "type": "string",
            "enum": [
              "user",
              "machine"
            ]
          },
          "roles": {
            "description": "The user's role names in this context — display only.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "capabilities": {
            "description": "The Chat permission keys the caller holds here, e.g. messages.send.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "tenant_id",
          "application_id",
          "principal_type",
          "roles",
          "capabilities"
        ]
      },
      "VapidPublicKeyBody": {
        "type": "object",
        "properties": {
          "public_key": {
            "type": "string",
            "description": "Not a secret: pass it to the browser's PushManager.subscribe()."
          }
        },
        "required": [
          "public_key"
        ]
      },
      "WebPushSubscriptionKeysDto": {
        "type": "object",
        "properties": {
          "p256dh": {
            "type": "string"
          },
          "auth": {
            "type": "string"
          }
        },
        "required": [
          "p256dh",
          "auth"
        ]
      },
      "WebPushSubscriptionDto": {
        "type": "object",
        "properties": {
          "endpoint": {
            "type": "string"
          },
          "keys": {
            "$ref": "#/components/schemas/WebPushSubscriptionKeysDto"
          }
        },
        "required": [
          "endpoint",
          "keys"
        ]
      },
      "RegisterPushDeviceDto": {
        "type": "object",
        "properties": {
          "platform": {
            "type": "string",
            "enum": [
              "fcm",
              "apns",
              "web"
            ]
          },
          "token": {
            "type": "string",
            "description": "Required for fcm/apns: the native device token."
          },
          "subscription": {
            "description": "Required for web: what PushManager.subscribe() returned.",
            "allOf": [
              {
                "$ref": "#/components/schemas/WebPushSubscriptionDto"
              }
            ]
          }
        },
        "required": [
          "platform"
        ]
      },
      "UnregisterPushDeviceDto": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "description": "The native token, or the web subscription endpoint."
          }
        },
        "required": [
          "token"
        ]
      },
      "UserRefBody": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string"
          },
          "display_name": {
            "type": "string",
            "description": "Falls back to the user id when Chat has no profile."
          },
          "avatar_url": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "user_id",
          "display_name",
          "avatar_url"
        ]
      },
      "ConversationBody": {
        "type": "object",
        "properties": {
          "conversation_id": {
            "type": "string"
          },
          "tenant_id": {
            "type": "string",
            "description": "The Identity Server tenant id."
          },
          "application_id": {
            "type": "string",
            "description": "The Identity Server application id (the context)."
          },
          "type": {
            "type": "string",
            "enum": [
              "DIRECT",
              "GROUP",
              "CHANNEL"
            ]
          },
          "visibility": {
            "type": "string",
            "enum": [
              "PUBLIC",
              "PRIVATE"
            ],
            "nullable": true,
            "description": "CHANNEL only."
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "ARCHIVED",
              "DELETED"
            ],
            "description": "ARCHIVED is read-only."
          },
          "created_by_user_id": {
            "type": "string",
            "nullable": true
          },
          "created_by_client_id": {
            "type": "string",
            "nullable": true,
            "description": "Set when a machine client created it."
          },
          "last_activity_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "members": {
            "description": "On list/get: ACTIVE members for DIRECT/GROUP (bounded), omitted for CHANNEL.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserRefBody"
            }
          },
          "member_count": {
            "type": "number"
          },
          "my_role": {
            "type": "string",
            "enum": [
              "OWNER",
              "ADMIN",
              "MEMBER"
            ],
            "nullable": true,
            "description": "The caller's membership role (users only)."
          },
          "has_unread": {
            "type": "boolean",
            "description": "Users only."
          }
        },
        "required": [
          "conversation_id",
          "tenant_id",
          "application_id",
          "type",
          "visibility",
          "name",
          "description",
          "status",
          "created_by_user_id",
          "created_by_client_id",
          "last_activity_at",
          "created_at",
          "updated_at"
        ]
      },
      "ConversationPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConversationBody"
            }
          },
          "next_cursor": {
            "type": "string",
            "nullable": true,
            "description": "Pass as `before` for the next (older) page; null on the last page."
          }
        },
        "required": [
          "items",
          "next_cursor"
        ]
      },
      "CreateConversationDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "DIRECT",
              "GROUP",
              "CHANNEL"
            ]
          },
          "name": {
            "type": "string",
            "maxLength": 200,
            "description": "Required for GROUP and CHANNEL."
          },
          "description": {
            "type": "string",
            "maxLength": 2000
          },
          "visibility": {
            "type": "string",
            "enum": [
              "PUBLIC",
              "PRIVATE"
            ],
            "description": "CHANNEL only; default PUBLIC."
          },
          "member_user_ids": {
            "maxItems": 100,
            "description": "Users: the other members (the caller is always added). Machines: required, every member. DIRECT = exactly 2 members in total.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "actor_user_id": {
            "type": "string",
            "description": "Machines only: the tenant user recorded as creator (and GROUP/CHANNEL OWNER). Ignored for users."
          }
        },
        "required": [
          "type"
        ]
      },
      "UpdateConversationDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200
          },
          "description": {
            "type": "string",
            "maxLength": 2000
          },
          "visibility": {
            "type": "string",
            "enum": [
              "PUBLIC",
              "PRIVATE"
            ],
            "description": "CHANNEL only."
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "ARCHIVED"
            ],
            "description": "The only field a DIRECT conversation accepts (machines only)."
          }
        }
      },
      "MemberBody": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string"
          },
          "display_name": {
            "type": "string",
            "description": "Falls back to the user id when Chat has no profile."
          },
          "avatar_url": {
            "type": "string",
            "nullable": true
          },
          "member_id": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "OWNER",
              "ADMIN",
              "MEMBER"
            ],
            "description": "Content ownership only — never authorization."
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "LEFT",
              "REMOVED"
            ]
          },
          "joined_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "user_id",
          "display_name",
          "avatar_url",
          "member_id",
          "role",
          "status",
          "joined_at"
        ]
      },
      "MemberPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MemberBody"
            }
          },
          "next_cursor": {
            "type": "string",
            "nullable": true,
            "description": "Pass as `before` for the next (older) page; null on the last page."
          }
        },
        "required": [
          "items",
          "next_cursor"
        ]
      },
      "AddMemberDto": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string"
          },
          "display_name": {
            "type": "string",
            "maxLength": 200,
            "description": "Machines: profile hint for a user Chat has never seen."
          },
          "email": {
            "type": "string",
            "maxLength": 320,
            "description": "Machines: profile hint for a user Chat has never seen."
          }
        },
        "required": [
          "user_id"
        ]
      },
      "AttachmentBody": {
        "type": "object",
        "properties": {
          "file_id": {
            "type": "string",
            "description": "A file id owned by a File/Media platform — Chat never stores bytes."
          },
          "name": {
            "type": "string"
          },
          "mime_type": {
            "type": "string"
          },
          "size": {
            "type": "number"
          },
          "url": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "file_id",
          "name",
          "mime_type",
          "size",
          "url"
        ]
      },
      "ReactionSummaryBody": {
        "type": "object",
        "properties": {
          "emoji": {
            "type": "string"
          },
          "count": {
            "type": "number"
          },
          "reacted_by_me": {
            "type": "boolean"
          }
        },
        "required": [
          "emoji",
          "count",
          "reacted_by_me"
        ]
      },
      "MessageBody": {
        "type": "object",
        "properties": {
          "message_id": {
            "type": "string"
          },
          "conversation_id": {
            "type": "string"
          },
          "tenant_id": {
            "type": "string"
          },
          "application_id": {
            "type": "string"
          },
          "sender_user_id": {
            "type": "string",
            "nullable": true
          },
          "sender_client_id": {
            "type": "string",
            "nullable": true,
            "description": "Set when a machine client sent it (on behalf of sender_user_id, or as SYSTEM)."
          },
          "sender": {
            "nullable": true,
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/UserRefBody"
              }
            ]
          },
          "body": {
            "type": "string",
            "description": "Empty for a deleted message (tombstone)."
          },
          "message_type": {
            "type": "string",
            "enum": [
              "TEXT",
              "SYSTEM",
              "FILE"
            ]
          },
          "reply_to_message_id": {
            "type": "string",
            "nullable": true
          },
          "attachments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AttachmentBody"
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "EDITED",
              "DELETED"
            ]
          },
          "edited_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "deleted_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "reactions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReactionSummaryBody"
            }
          },
          "mentioned_user_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "message_id",
          "conversation_id",
          "tenant_id",
          "application_id",
          "sender_user_id",
          "sender_client_id",
          "sender",
          "body",
          "message_type",
          "reply_to_message_id",
          "attachments",
          "status",
          "edited_at",
          "deleted_at",
          "created_at",
          "updated_at",
          "reactions",
          "mentioned_user_ids"
        ]
      },
      "MessagePage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MessageBody"
            }
          },
          "next_cursor": {
            "type": "string",
            "nullable": true,
            "description": "Pass as `before` for the next (older) page; null on the last page."
          }
        },
        "required": [
          "items",
          "next_cursor"
        ]
      },
      "AttachmentDto": {
        "type": "object",
        "properties": {
          "file_id": {
            "type": "string",
            "maxLength": 256
          },
          "name": {
            "type": "string",
            "maxLength": 512
          },
          "mime_type": {
            "type": "string",
            "maxLength": 255
          },
          "size": {
            "type": "number",
            "minimum": 0
          }
        },
        "required": [
          "file_id",
          "name",
          "mime_type",
          "size"
        ]
      },
      "SendMessageDto": {
        "type": "object",
        "properties": {
          "body": {
            "type": "string",
            "description": "Up to 10,000 characters; longer bodies are rejected with body_too_long."
          },
          "message_type": {
            "type": "string",
            "enum": [
              "TEXT",
              "SYSTEM",
              "FILE"
            ],
            "description": "Default TEXT, or FILE with attachments. SYSTEM is machine-only."
          },
          "reply_to_message_id": {
            "type": "string"
          },
          "attachments": {
            "description": "At most 10 per message; more are rejected with too_many_attachments.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AttachmentDto"
            }
          },
          "mentioned_user_ids": {
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "actor_user_id": {
            "type": "string",
            "description": "Machines only: the member the message is sent on behalf of; required unless message_type is SYSTEM. Ignored for users."
          }
        },
        "required": [
          "body"
        ]
      },
      "EditMessageDto": {
        "type": "object",
        "properties": {
          "body": {
            "type": "string"
          }
        },
        "required": [
          "body"
        ]
      },
      "AddReactionDto": {
        "type": "object",
        "properties": {
          "emoji": {
            "type": "string",
            "maxLength": 32
          }
        },
        "required": [
          "emoji"
        ]
      },
      "MarkReadDto": {
        "type": "object",
        "properties": {
          "message_id": {
            "type": "string",
            "description": "Default: the latest message."
          }
        }
      },
      "RealtimeTokenBody": {
        "type": "object",
        "properties": {
          "stream_url": {
            "type": "string",
            "description": "Open with EventSource; subscribe-only."
          },
          "expires": {
            "type": "number",
            "description": "Expiry, epoch milliseconds. Reconnect with a fresh token before it."
          },
          "user_id": {
            "type": "string",
            "description": "The caller's user id — lets the client recognise events about itself (e.g. its own `member.added`)."
          }
        },
        "required": [
          "stream_url",
          "expires",
          "user_id"
        ]
      },
      "UserProfileList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserProfileBody"
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "PresenceStatusBody": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "online",
              "offline"
            ]
          },
          "last_seen_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "required": [
          "user_id",
          "status",
          "last_seen_at"
        ]
      },
      "PresenceStatusList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PresenceStatusBody"
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "ConversationCountsBody": {
        "type": "object",
        "properties": {
          "direct": {
            "type": "number"
          },
          "group": {
            "type": "number"
          },
          "channel": {
            "type": "number"
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "direct",
          "group",
          "channel",
          "total"
        ]
      },
      "AdminOverviewBody": {
        "type": "object",
        "properties": {
          "tenant": {
            "$ref": "#/components/schemas/TenantSummaryBody"
          },
          "applications": {
            "type": "number",
            "description": "ACTIVE applications of the tenant."
          },
          "chat_enabled_applications": {
            "type": "number"
          },
          "members": {
            "type": "number",
            "description": "ACTIVE members known to Chat."
          },
          "conversations": {
            "$ref": "#/components/schemas/ConversationCountsBody"
          }
        },
        "required": [
          "tenant",
          "applications",
          "chat_enabled_applications",
          "members",
          "conversations"
        ]
      },
      "CapabilityDescriptorBody": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "description": {
            "type": "string"
          }
        },
        "required": [
          "key",
          "description"
        ]
      },
      "RolePermissionBody": {
        "type": "object",
        "properties": {
          "role_id": {
            "type": "string"
          },
          "role": {
            "type": "string"
          },
          "display_name": {
            "type": "string",
            "nullable": true
          },
          "role_scope": {
            "type": "string",
            "enum": [
              "tenant",
              "application"
            ]
          },
          "system": {
            "type": "boolean"
          },
          "locked": {
            "type": "boolean",
            "description": "true for tenant_owner: holds every capability, not editable."
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "role_id",
          "role",
          "display_name",
          "role_scope",
          "system",
          "locked",
          "capabilities"
        ]
      },
      "RolePermissionsBody": {
        "type": "object",
        "properties": {
          "application_id": {
            "type": "string",
            "nullable": true,
            "description": "The context: a tenant application, or null for the tenant-wide mapping."
          },
          "available_capabilities": {
            "description": "Grantable: the Identity Server catalog keys Chat enforces.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CapabilityDescriptorBody"
            }
          },
          "missing_capabilities": {
            "description": "Keys Chat enforces that the catalog does not define.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RolePermissionBody"
            }
          },
          "note": {
            "type": "string"
          }
        },
        "required": [
          "application_id",
          "available_capabilities",
          "missing_capabilities",
          "items",
          "note"
        ]
      },
      "SetRolePermissionsDto": {
        "type": "object",
        "properties": {
          "capabilities": {
            "description": "The complete set of Chat capabilities the role grants in this context.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "capabilities"
        ]
      },
      "AdminMemberBody": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "nullable": true
          },
          "avatar_url": {
            "type": "string",
            "nullable": true
          },
          "roles": {
            "description": "Standalone roles: tenant roles plus Chat-application roles.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "roles_synced_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "required": [
          "user_id",
          "display_name",
          "email",
          "avatar_url",
          "roles",
          "capabilities",
          "roles_synced_at"
        ]
      },
      "AdminMemberPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AdminMemberBody"
            }
          },
          "next_cursor": {
            "type": "string",
            "nullable": true,
            "description": "Pass as `before` for the next (older) page; null on the last page."
          }
        },
        "required": [
          "items",
          "next_cursor"
        ]
      },
      "AdminApplicationBody": {
        "type": "object",
        "properties": {
          "application_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "logo_url": {
            "type": "string",
            "nullable": true
          },
          "type": {
            "type": "string",
            "enum": [
              "PLATFORM",
              "TENANT"
            ]
          },
          "access_mode": {
            "type": "string",
            "enum": [
              "ALL_TENANT_MEMBERS",
              "ASSIGNED_ONLY"
            ]
          },
          "identity_status": {
            "type": "string"
          },
          "chat_enabled": {
            "type": "boolean"
          },
          "synced_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "required": [
          "application_id",
          "name",
          "slug",
          "logo_url",
          "type",
          "access_mode",
          "identity_status",
          "chat_enabled",
          "synced_at"
        ]
      },
      "AdminApplicationList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AdminApplicationBody"
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "SettingsBody": {
        "type": "object",
        "properties": {
          "message_retention_days": {
            "type": "number",
            "nullable": true,
            "description": "null keeps messages forever."
          }
        },
        "required": [
          "message_retention_days"
        ]
      },
      "UpdateSettingsDto": {
        "type": "object",
        "properties": {
          "message_retention_days": {
            "type": "number",
            "minimum": 1,
            "nullable": true,
            "description": "null keeps messages forever."
          }
        }
      },
      "AuditLogBody": {
        "type": "object",
        "properties": {
          "audit_id": {
            "type": "string"
          },
          "tenant_id": {
            "type": "string"
          },
          "application_id": {
            "type": "string",
            "nullable": true
          },
          "actor_type": {
            "type": "string",
            "enum": [
              "USER",
              "CLIENT",
              "SYSTEM"
            ]
          },
          "actor_user_id": {
            "type": "string",
            "nullable": true
          },
          "actor_client_id": {
            "type": "string",
            "nullable": true
          },
          "action": {
            "type": "string",
            "enum": [
              "CONVERSATION_CREATED",
              "CONVERSATION_UPDATED",
              "CONVERSATION_DELETED",
              "GROUP_CREATED",
              "GROUP_UPDATED",
              "MEMBER_ADDED",
              "MEMBER_REMOVED",
              "MESSAGE_DELETED_BY_MODERATOR",
              "APPLICATION_CHAT_ENABLED",
              "APPLICATION_CHAT_DISABLED",
              "SETTINGS_UPDATED",
              "IDENTITY_REFRESH_REQUESTED",
              "ROLE_PERMISSIONS_UPDATED",
              "ROLE_PERMISSIONS_RESET",
              "ADMIN_LOGIN",
              "ADMIN_ACTION"
            ]
          },
          "target_type": {
            "type": "string",
            "enum": [
              "CONVERSATION",
              "MEMBER",
              "MESSAGE",
              "APPLICATION",
              "SETTINGS",
              "TENANT",
              "ROLE"
            ]
          },
          "target_id": {
            "type": "string"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true
          },
          "changes": {
            "type": "object",
            "nullable": true,
            "properties": {
              "before": {},
              "after": {}
            }
          },
          "request_id": {
            "type": "string",
            "nullable": true
          },
          "ip": {
            "type": "string",
            "nullable": true
          },
          "user_agent": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "required": [
          "audit_id",
          "tenant_id",
          "application_id",
          "actor_type",
          "actor_user_id",
          "actor_client_id",
          "action",
          "target_type",
          "target_id",
          "metadata",
          "changes",
          "request_id",
          "ip",
          "user_agent",
          "created_at"
        ]
      },
      "AuditLogPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AuditLogBody"
            }
          },
          "next_cursor": {
            "type": "string",
            "nullable": true,
            "description": "Pass as `before` for the next (older) page; null on the last page."
          }
        },
        "required": [
          "items",
          "next_cursor"
        ]
      }
    }
  }
}
