mirror of
https://github.com/stalwartlabs/stalwart.git
synced 2026-08-19 08:01:08 +00:00
587 lines
19 KiB
YAML
587 lines
19 KiB
YAML
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: jane@example.com
|
|
accountSecret: s3cret
|
|
clientId: webadmin
|
|
redirectUri: https://mail.example.com/login
|
|
codeChallenge: E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
|
|
codeChallengeMethod: S256
|
|
authDevice:
|
|
summary: Device-flow completion
|
|
value:
|
|
type: authDevice
|
|
accountName: jane@example.com
|
|
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
|