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