{"owner":"stalwartlabs","repo":"stalwart","hasSpec":true,"specFile":"api/v1/openapi.yml","branch":"HEAD","format":"yaml","version":"3.x (YAML)","title":"stalwart","description":"","endpoints":[],"spec":"openapi: 3.0.3\ninfo:\n  title: Stalwart Management API\n  description: |\n    REST Management API for Stalwart server. These endpoints are helpers\n    that complement the JMAP API — most of the server's configuration and data\n    is managed via JMAP (see `POST /jmap/`). The endpoints documented here cover\n    interactive login, account introspection, configuration schema retrieval and\n    live (Server-Sent Events) telemetry streams.\n  version: \"1.0\"\n  license:\n    name: AGPL-3.0-only OR LicenseRef-SEL\nservers:\n  - url: https://{host}\n    description: Stalwart server\n    variables:\n      host:\n        default: mail.example.com\n        description: The hostname of Stalwart server\nsecurity:\n  - bearerAuth: []\n  - basicAuth: []\npaths:\n  /api/auth:\n    post:\n      operationId: login\n      summary: Authenticate a user and obtain an authorization code\n      description: |\n        Anonymous endpoint used by the web UI and device-flow clients to exchange\n        user credentials (plus optional MFA token and PKCE challenge) for an\n        OAuth authorization `client_code` that can then be exchanged for an\n        access token via `POST /auth/token`. Rate-limited as an anonymous request.\n      security: []\n      tags: [Authentication]\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/LoginRequest'\n            examples:\n              authCode:\n                summary: Authorization-code flow (web UI)\n                value:\n                  type: authCode\n                  accountName: jane@example.com\n                  accountSecret: s3cret\n                  clientId: webadmin\n                  redirectUri: https://mail.example.com/login\n                  codeChallenge: E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM\n                  codeChallengeMethod: S256\n              authDevice:\n                summary: Device-flow completion\n                value:\n                  type: authDevice\n                  accountName: jane@example.com\n                  accountSecret: s3cret\n                  code: BDWP-HQPK\n      responses:\n        '200':\n          description: Result of the authentication attempt\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/LoginResponse'\n              examples:\n                authenticated:\n                  value:\n                    type: authenticated\n                    clientCode: 3F7A9C1E4B2D8E6F\n                mfaRequired:\n                  value:\n                    type: mfaRequired\n                failure:\n                  value:\n                    type: failure\n        '400':\n          $ref: '#/components/responses/BadRequest'\n        '429':\n          $ref: '#/components/responses/TooManyRequests'\n\n  /api/discover/{email}:\n    get:\n      operationId: discoverOidc\n      summary: Discover the OpenID Connect provider for an email address\n      description: |\n        Returns the OpenID Connect discovery document for the directory that\n        owns the domain part of `email`. If the domain is not bound to an\n        external OIDC directory, the server's own OIDC discovery document\n        (equivalent to `/.well-known/openid-configuration`) is returned.\n        Anonymous endpoint, rate-limited.\n      security: []\n      tags: [Authentication]\n      parameters:\n        - name: email\n          in: path\n          required: true\n          description: Email address or account name\n          schema:\n            type: string\n            format: email\n      responses:\n        '200':\n          description: OpenID Connect discovery document\n          content:\n            application/json:\n              schema:\n                type: object\n                description: OIDC discovery metadata (RFC 8414)\n                additionalProperties: true\n        '404':\n          $ref: '#/components/responses/NotFound'\n        '429':\n          $ref: '#/components/responses/TooManyRequests'\n\n  /api/account:\n    get:\n      operationId: getAccount\n      summary: Return the authenticated account's permissions, edition and locale\n      tags: [Account]\n      responses:\n        '200':\n          description: Account descriptor\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/Account'\n        '401':\n          $ref: '#/components/responses/Unauthorized'\n\n  /api/schema:\n    get:\n      operationId: getSchemaRedirect\n      summary: Redirect to the versioned configuration schema URL\n      description: |\n        Redirects (302) to `/api/schema/{hash}` where `{hash}` is the SHA-256\n        of the current configuration schema. Use this when you do not yet know\n        the hash; once you have cached a schema at a given hash the immutable\n        cache will never require re-download.\n      tags: [Schema]\n      responses:\n        '302':\n          description: Redirect to the hashed schema URL\n          headers:\n            Location:\n              schema:\n                type: string\n                example: /api/schema/a1b2c3d4e5f6...\n        '401':\n          $ref: '#/components/responses/Unauthorized'\n\n  /api/schema/{hash}:\n    get:\n      operationId: getSchema\n      summary: Return the configuration schema at a specific hash\n      description: |\n        Returns the JSON Schema describing the full Stalwart configuration tree.\n        The response is always gzip-encoded (`Content-Encoding: gzip`) and served\n        with an immutable cache policy — the schema for a given hash never\n        changes. If the hash does not match the server's current schema, the\n        server redirects to the correct URL.\n      tags: [Schema]\n      parameters:\n        - name: hash\n          in: path\n          required: true\n          description: SHA-256 hex digest of the configuration schema\n          schema:\n            type: string\n      responses:\n        '200':\n          description: Gzipped JSON Schema document\n          headers:\n            Content-Encoding:\n              schema:\n                type: string\n                example: gzip\n            Cache-Control:\n              schema:\n                type: string\n                example: public, max-age=31536000, immutable\n          content:\n            application/json:\n              schema:\n                type: object\n                description: JSON Schema document describing Stalwart config\n                additionalProperties: true\n        '302':\n          description: Redirect to the current schema URL when the hash is stale\n        '401':\n          $ref: '#/components/responses/Unauthorized'\n\n  /api/token/delivery:\n    get:\n      operationId: issueDeliveryToken\n      summary: Issue a short-lived token for live delivery diagnostics\n      description: |\n        Returns a plain-text bearer token, valid for 60 seconds, that authorises\n        connecting to `/api/live/delivery/{target}` as a query parameter\n        (`?token=...`). Useful for EventSource clients that cannot send\n        `Authorization` headers. Requires `LiveDeliveryTest` permission.\n      tags: [Live Telemetry]\n      responses:\n        '200':\n          description: Short-lived delivery token\n          content:\n            text/plain:\n              schema:\n                type: string\n                example: eyJhbGciOi...\n        '401':\n          $ref: '#/components/responses/Unauthorized'\n        '403':\n          $ref: '#/components/responses/Forbidden'\n\n  /api/token/tracing:\n    get:\n      operationId: issueTracingToken\n      summary: Issue a short-lived token for live tracing (Enterprise)\n      description: |\n        Returns a plain-text bearer token, valid for 60 seconds, that authorises\n        connecting to `/api/live/tracing` as a query parameter. Requires the\n        `LiveTracing` permission. Available only in the Enterprise edition.\n      tags: [Live Telemetry]\n      responses:\n        '200':\n          description: Short-lived tracing token\n          content:\n            text/plain:\n              schema:\n                type: string\n        '401':\n          $ref: '#/components/responses/Unauthorized'\n        '403':\n          $ref: '#/components/responses/Forbidden'\n        '404':\n          description: Enterprise feature not available in this edition\n\n  /api/token/metrics:\n    get:\n      operationId: issueMetricsToken\n      summary: Issue a short-lived token for live metrics (Enterprise)\n      description: |\n        Returns a plain-text bearer token, valid for 60 seconds, that authorises\n        connecting to `/api/live/metrics` as a query parameter. Requires the\n        `LiveMetrics` permission. Available only in the Enterprise edition.\n      tags: [Live Telemetry]\n      responses:\n        '200':\n          description: Short-lived metrics token\n          content:\n            text/plain:\n              schema:\n                type: string\n        '401':\n          $ref: '#/components/responses/Unauthorized'\n        '403':\n          $ref: '#/components/responses/Forbidden'\n        '404':\n          description: Enterprise feature not available in this edition\n\n  /api/live/delivery/{target}:\n    get:\n      operationId: liveDelivery\n      summary: Stream outbound-delivery diagnostics as Server-Sent Events\n      description: |\n        Opens a `text/event-stream` connection that streams each stage of an\n        outbound delivery attempt to `target` (a domain or email address): MX\n        lookup, MTA-STS fetch, TLSA/DANE validation, SMTP conversation, and so\n        on. Each SSE frame carries a JSON-encoded `DeliveryStage` wrapped in a\n        single-element array (`data: [{...}]`). The stream ends with a final\n        `completed` event. Requires `LiveDeliveryTest` permission; may also be\n        authenticated via the `?token=` query parameter obtained from\n        `/api/token/delivery`.\n      tags: [Live Telemetry]\n      security:\n        - bearerAuth: []\n        - basicAuth: []\n        - liveToken: []\n      parameters:\n        - name: target\n          in: path\n          required: true\n          description: Target domain or email address to diagnose\n          schema:\n            type: string\n        - name: timeout\n          in: query\n          required: false\n          description: Maximum stream lifetime in seconds (minimum 1, default 30)\n          schema:\n            type: integer\n            minimum: 1\n            default: 30\n      responses:\n        '200':\n          description: Server-Sent Events stream of delivery-diagnose stages\n          content:\n            text/event-stream:\n              schema:\n                type: string\n                description: |\n                  Series of SSE frames. Each `event: event` frame carries\n                  `data: [<DeliveryStage JSON>]`; the final frame's stage is\n                  `{\"type\":\"completed\"}`.\n        '401':\n          $ref: '#/components/responses/Unauthorized'\n        '403':\n          $ref: '#/components/responses/Forbidden'\n\n  /api/live/tracing:\n    get:\n      operationId: liveTracing\n      summary: Stream live tracing events (Enterprise)\n      description: |\n        Opens a `text/event-stream` connection streaming server trace events in\n        real time. Requires `LiveTracing` permission; may be authenticated via\n        the `?token=` query parameter from `/api/token/tracing`. Enterprise only.\n      tags: [Live Telemetry]\n      security:\n        - bearerAuth: []\n        - basicAuth: []\n        - liveToken: []\n      responses:\n        '200':\n          description: Server-Sent Events stream of tracing events\n          content:\n            text/event-stream:\n              schema:\n                type: string\n        '401':\n          $ref: '#/components/responses/Unauthorized'\n        '403':\n          $ref: '#/components/responses/Forbidden'\n        '404':\n          description: Enterprise feature not available in this edition\n\n  /api/live/metrics:\n    get:\n      operationId: liveMetrics\n      summary: Stream live metrics events (Enterprise)\n      description: |\n        Opens a `text/event-stream` connection streaming server metrics in real\n        time. Requires `LiveMetrics` permission; may be authenticated via the\n        `?token=` query parameter from `/api/token/metrics`. Enterprise only.\n      tags: [Live Telemetry]\n      security:\n        - bearerAuth: []\n        - basicAuth: []\n        - liveToken: []\n      responses:\n        '200':\n          description: Server-Sent Events stream of metric events\n          content:\n            text/event-stream:\n              schema:\n                type: string\n        '401':\n          $ref: '#/components/responses/Unauthorized'\n        '403':\n          $ref: '#/components/responses/Forbidden'\n        '404':\n          description: Enterprise feature not available in this edition\n\ncomponents:\n  securitySchemes:\n    bearerAuth:\n      type: http\n      scheme: bearer\n      bearerFormat: JWT\n      description: OAuth2 access token issued by `POST /auth/token`.\n    basicAuth:\n      type: http\n      scheme: basic\n      description: HTTP Basic authentication using account name and secret.\n    liveToken:\n      type: apiKey\n      in: query\n      name: token\n      description: |\n        Short-lived token (60s lifetime) issued by `/api/token/{kind}` and used\n        to authorise Server-Sent Events streams where an `Authorization` header\n        cannot be set (e.g. browser `EventSource`).\n\n  responses:\n    BadRequest:\n      description: Request payload is malformed or fails validation\n      content:\n        application/problem+json:\n          schema:\n            $ref: '#/components/schemas/ProblemDetails'\n    Unauthorized:\n      description: Missing or invalid credentials\n      headers:\n        WWW-Authenticate:\n          schema:\n            type: string\n            example: Bearer realm=\"Stalwart Server\"\n      content:\n        application/problem+json:\n          schema:\n            $ref: '#/components/schemas/ProblemDetails'\n    Forbidden:\n      description: Authenticated principal lacks the required permission\n      content:\n        application/problem+json:\n          schema:\n            $ref: '#/components/schemas/ProblemDetails'\n    NotFound:\n      description: Resource not found\n      content:\n        application/problem+json:\n          schema:\n            $ref: '#/components/schemas/ProblemDetails'\n    TooManyRequests:\n      description: Anonymous-request rate limit exceeded\n      content:\n        application/problem+json:\n          schema:\n            $ref: '#/components/schemas/ProblemDetails'\n\n  schemas:\n    LoginRequest:\n      type: object\n      description: |\n        Tagged union discriminated by `type`. Use `authCode` for the standard\n        OAuth authorization-code flow (optionally with PKCE) and `authDevice`\n        to complete an OAuth device-authorization flow.\n      oneOf:\n        - $ref: '#/components/schemas/LoginRequestAuthCode'\n        - $ref: '#/components/schemas/LoginRequestAuthDevice'\n      discriminator:\n        propertyName: type\n        mapping:\n          authCode: '#/components/schemas/LoginRequestAuthCode'\n          authDevice: '#/components/schemas/LoginRequestAuthDevice'\n\n    LoginRequestAuthCode:\n      type: object\n      required: [type, accountName, accountSecret, clientId]\n      properties:\n        type:\n          type: string\n          enum: [authCode]\n        accountName:\n          type: string\n        accountSecret:\n          type: string\n          format: password\n        mfaToken:\n          type: string\n          nullable: true\n          description: MFA token returned by a previous `mfaRequired` response\n        clientId:\n          type: string\n          description: OAuth client identifier\n        redirectUri:\n          type: string\n          format: uri\n          nullable: true\n          description: Must use `https://` unless the server is in recovery or dev mode\n        nonce:\n          type: string\n          nullable: true\n        scope:\n          type: string\n          nullable: true\n        codeChallenge:\n          type: string\n          nullable: true\n          description: PKCE code challenge (RFC 7636)\n        codeChallengeMethod:\n          type: string\n          enum: [plain, S256]\n          nullable: true\n          description: Defaults to `plain` when a `codeChallenge` is present\n        state:\n          type: string\n          nullable: true\n\n    LoginRequestAuthDevice:\n      type: object\n      required: [type, accountName, accountSecret, code]\n      properties:\n        type:\n          type: string\n          enum: [authDevice]\n        accountName:\n          type: string\n        accountSecret:\n          type: string\n          format: password\n        mfaToken:\n          type: string\n          nullable: true\n        code:\n          type: string\n          description: User-facing device code issued by `POST /auth/device`\n\n    LoginResponse:\n      type: object\n      description: Tagged union discriminated by `type`.\n      oneOf:\n        - $ref: '#/components/schemas/LoginResponseAuthenticated'\n        - $ref: '#/components/schemas/LoginResponseVerified'\n        - $ref: '#/components/schemas/LoginResponseMfaRequired'\n        - $ref: '#/components/schemas/LoginResponseFailure'\n      discriminator:\n        propertyName: type\n        mapping:\n          authenticated: '#/components/schemas/LoginResponseAuthenticated'\n          verified: '#/components/schemas/LoginResponseVerified'\n          mfaRequired: '#/components/schemas/LoginResponseMfaRequired'\n          failure: '#/components/schemas/LoginResponseFailure'\n\n    LoginResponseAuthenticated:\n      type: object\n      required: [type, clientCode]\n      properties:\n        type:\n          type: string\n          enum: [authenticated]\n        clientCode:\n          type: string\n          description: Authorization code to exchange at `POST /auth/token`\n\n    LoginResponseVerified:\n      type: object\n      required: [type]\n      properties:\n        type:\n          type: string\n          enum: [verified]\n\n    LoginResponseMfaRequired:\n      type: object\n      required: [type]\n      properties:\n        type:\n          type: string\n          enum: [mfaRequired]\n\n    LoginResponseFailure:\n      type: object\n      required: [type]\n      properties:\n        type:\n          type: string\n          enum: [failure]\n\n    Account:\n      type: object\n      required: [permissions, edition, locale]\n      properties:\n        permissions:\n          type: array\n          description: |\n            Effective permissions for the authenticated principal, filtered to\n            exclude internal/system-only permissions. Values are from the\n            `Permission` enum (e.g. `authenticate`, `jmap-email-get`,\n            `sys-account-settings-get`).\n          items:\n            type: string\n        edition:\n          type: string\n          enum: [oss, community, enterprise]\n          description: Server edition\n        locale:\n          type: string\n          description: Preferred locale for the account (IETF BCP 47-style tag)\n\n    ProblemDetails:\n      type: object\n      description: RFC 7807 problem details document\n      properties:\n        type:\n          type: string\n          format: uri\n        title:\n          type: string\n        status:\n          type: integer\n        detail:\n          type: string\n        instance:\n          type: string\n"}