{"openapi":"3.1.0","info":{"title":"SchemaVaults Mail Server API","version":"0.0.109","description":"API for managing mailing lists and sending transactional email. Admin routes require an admin JWT bearer token; /api/send and /api/templates also accept a mail-server API key. Interactive documentation lives at /docs.","contact":{"email":"support@schemavaults.com"}},"servers":[{"url":"https://mail.schemavaults.com"}],"tags":[{"name":"Send","description":"Send transactional or mailing-list email through a configured transport."},{"name":"Mailing Lists","description":"Mailing lists, double-opt-in subscriptions, and unsubscribes."},{"name":"Templates","description":"The react-email template catalog."},{"name":"Branding","description":"Public white-label branding assets (logo, favicon)."},{"name":"Test Emails","description":"Read emails captured by the fake-send test-database transport, for E2E-testing the /api/send flow."},{"name":"Admin: API Keys","description":"Manage API keys and their audience, sender, and transport scopes (admin only)."},{"name":"Admin: Branding","description":"Upload or remove white-label branding assets (admin only)."},{"name":"Admin: CORS","description":"Manage the CORS origin allowlist for public API routes (admin only)."},{"name":"Admin: Templates","description":"Inspect and preview email templates (admin only)."},{"name":"Admin: Transports","description":"Inspect configured mail transports (admin only)."},{"name":"Meta","description":"API metadata (this OpenAPI document)."}],"components":{"securitySchemes":{"AdminJwtAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Admin JWT access token issued by the auth server. The authenticated user must have the admin role."},"MailApiKeyAuth":{"type":"http","scheme":"bearer","description":"Mail-server API key (`svlts_mail_pk_...`) created by an admin at /admin/keys. Subject to the key's audience, sender, and transport scopes."}},"schemas":{"SuccessMessageResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"}},"required":["success","message"],"description":"Success envelope for operations with no response payload."},"ErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"message":{"type":"string"}},"required":["success","message"],"description":"Error envelope returned by every non-2xx response."},"SendEmailRequestBody":{"type":"object","properties":{"message":{"anyOf":[{"$ref":"#/components/schemas/SendEmailTemplateMessage"},{"$ref":"#/components/schemas/SendEmailRawMessage"}],"description":"Either a template reference (rendered server-side via react-email) or a raw text+html body."},"to":{"anyOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"maxItems":50},{"type":"string","format":"uuid"}],"description":"Recipient email address, array of addresses (max 50), or a mailing-list UUID — the send then goes to every active (non-unsubscribed) subscriber of that list."},"from":{"type":"string","description":"Sender, as a bare address or `Display Name <address>` form. Defaults to the server's configured MAIL_FROM sender.","example":"Example <noreply@example.com>"},"subject":{"type":"string","example":"Welcome!"},"replyTo":{"type":"string"},"cc":{"anyOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"}}]},"bcc":{"anyOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"}}]},"dryRun":{"type":"boolean","description":"When true, validates the request (and renders the template, if any) without dispatching mail."},"transport":{"$ref":"#/components/schemas/MailTransportKind"}},"required":["message","to","subject"]},"SendEmailTemplateMessage":{"type":"object","properties":{"template_id":{"type":"string","description":"Name of a template from this server's catalog (see GET /api/templates).","example":"mailing-list-confirmation"},"template_props":{"description":"Props passed to the react-email template component."}},"required":["template_id"]},"SendEmailRawMessage":{"type":"object","properties":{"text":{"type":"string","description":"Plain-text body."},"html":{"type":"string","description":"HTML body."}},"required":["text","html"]},"MailTransportKind":{"type":"string","enum":["resend","smtp","test-database-transport"],"description":"Which configured transport should deliver this message. Defaults to the deployment's MAIL_TRANSPORT."},"MailingList":{"type":"object","properties":{"mailing_list_id":{"type":"string","format":"uuid","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"name":{"type":"string","minLength":3,"maxLength":64,"example":"Product updates"},"description":{"type":"string","minLength":3,"maxLength":256,"example":"Occasional announcements about new features."},"public":{"type":"boolean","description":"Whether the list is shown in the public mailing list directory."},"created_at":{"type":"number","minimum":0,"description":"Creation time as a Unix timestamp in milliseconds."}},"required":["mailing_list_id","name","description","public","created_at"],"additionalProperties":false},"CreateMailingListSuccessResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"resource_id":{"type":"string","format":"uuid","description":"ID of the newly created mailing list."}},"required":["success","message","resource_id"]},"CreateMailingListRequestBody":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":64,"example":"Product updates"},"description":{"type":"string","minLength":3,"maxLength":256,"example":"Occasional announcements about new features."},"public":{"type":"boolean","description":"Whether the list is shown in the public mailing list directory."}},"required":["name","description","public"],"additionalProperties":false},"JoinMailingListRequestBody":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"Email address to subscribe.","example":"subscriber@example.com"},"mailing_list_id":{"type":"string","format":"uuid","description":"ID of the mailing list to join.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"}},"required":["email","mailing_list_id"],"additionalProperties":false,"description":"Starts a double-opt-in subscription: a confirmation email is sent to the address before it is added to the list."},"ConfirmSubscriptionSuccessResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"mailing_list_id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"}},"required":["success","mailing_list_id","email"]},"ConfirmSubscriptionRequestBody":{"type":"object","properties":{"token":{"type":"string","minLength":43,"maxLength":43,"description":"43-character URL-safe base64 confirmation token from the confirmation email link."},"email":{"type":"string","format":"email","description":"Email address the confirmation was sent to.","example":"subscriber@example.com"}},"required":["token","email"],"additionalProperties":false},"LeaveMailingListRequestBody":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"Email address to unsubscribe.","example":"subscriber@example.com"},"mailing_list_id":{"type":"string","format":"uuid","description":"ID of the mailing list to leave.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"}},"required":["email","mailing_list_id"],"additionalProperties":false},"MailingListSubscriber":{"type":"object","properties":{"mailing_list_id":{"type":"string","format":"uuid"},"subscribe_time":{"type":"number","minimum":0,"description":"Subscription time as a Unix timestamp in milliseconds."},"email":{"type":"string","format":"email"}},"required":["mailing_list_id","subscribe_time","email"]},"EmailTemplateListItem":{"type":"object","properties":{"id":{"type":"string","description":"Template name, usable as `message.template_id` in POST /api/send.","example":"mailing-list-confirmation"},"description":{"type":"string"}},"required":["id","description"]},"TestEmail":{"type":"object","properties":{"test_email_id":{"type":"string","format":"uuid"},"from_address":{"type":"string","description":"The `from` the send was dispatched with (bare address or `Display Name <address>` form).","example":"Example <noreply@example.com>"},"to_addresses":{"type":"array","items":{"type":"string"},"minItems":1,"description":"Recipient addresses, after any mailing-list expansion."},"cc_addresses":{"type":"array","items":{"type":"string"}},"bcc_addresses":{"type":"array","items":{"type":"string"}},"reply_to_addresses":{"type":"array","items":{"type":"string"}},"subject":{"type":"string"},"html":{"type":["string","null"],"description":"Rendered HTML body (templates are rendered before the transport runs), or null for text-only sends."},"text":{"type":["string","null"]},"created_at":{"type":"number","minimum":0,"description":"Unix epoch milliseconds when the fake send was stored."}},"required":["test_email_id","from_address","to_addresses","cc_addresses","bcc_addresses","reply_to_addresses","subject","html","text","created_at"],"description":"An email captured by the test-database-transport instead of being delivered. Used to verify /api/send behavior in E2E tests."},"BrandingAssetKind":{"type":"string","enum":["logo","favicon"],"description":"Kind of white-label branding asset."},"ApiKeyRecord":{"type":"object","properties":{"api_key_id":{"type":"string","format":"uuid"},"name":{"type":"string","minLength":1,"maxLength":64},"key_prefix":{"type":"string","minLength":1},"created_at":{"type":"number","minimum":0},"created_by_user_id":{"type":"string","format":"uuid"},"last_used_at":{"type":["number","null"],"minimum":0},"revoked_at":{"type":["number","null"],"minimum":0},"allow_any_audience":{"type":"boolean"}},"required":["api_key_id","name","key_prefix","created_at","created_by_user_id","last_used_at","revoked_at","allow_any_audience"],"description":"An API key as returned by the admin endpoints. Never includes the secret hash or the plaintext token."},"CreatedApiKey":{"type":"object","properties":{"api_key_id":{"type":"string","format":"uuid"},"name":{"type":"string","minLength":1,"maxLength":64},"key_prefix":{"type":"string","minLength":1},"created_at":{"type":"number","minimum":0},"created_by_user_id":{"type":"string","format":"uuid"},"plaintext":{"type":"string","description":"The full API key token. Returned EXACTLY ONCE, on creation — it is stored only as a hash.","example":"svlts_mail_pk_..."}},"required":["api_key_id","name","key_prefix","created_at","created_by_user_id","plaintext"]},"CreateApiKeyRequestBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":64,"description":"Human-facing API key label (1-64 characters).","example":"marketing-site"}},"required":["name"]},"UpdateApiKeyRequestBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":64,"description":"Human-facing API key label (1-64 characters).","example":"marketing-site"},"allow_any_audience":{"type":"boolean","description":"When true, the key may send to ANY recipient and its audience allowlists are ignored."}}},"ApiKeyAllowlistMutationBody":{"type":"object","properties":{"mailing_list_id":{"type":"string","format":"uuid","description":"Mailing list to add to / remove from the key's audience."}},"required":["mailing_list_id"]},"ApiKeyRecipientMutationBody":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"Individual recipient address to add to / remove from the key's audience.","example":"customer@example.com"}},"required":["email"]},"ApiKeySenderMutationBody":{"type":"object","properties":{"sender":{"type":"string","description":"A lowercase email address, or a `*@domain` wildcard permitting any local part at that domain.","example":"*@example.com"}},"required":["sender"]},"ApiKeyTransportMutationBody":{"type":"object","properties":{"transport_id":{"allOf":[{"$ref":"#/components/schemas/MailTransportKind"},{"description":"A mail transport this server knows about."}]}},"required":["transport_id"]},"BrandingAssetMetadata":{"type":"object","properties":{"asset_kind":{"$ref":"#/components/schemas/BrandingAssetKind"},"content_type":{"$ref":"#/components/schemas/BrandingAssetContentType"},"updated_at":{"type":"number","minimum":0,"description":"Upload time as a Unix timestamp in milliseconds."}},"required":["asset_kind","content_type","updated_at"]},"BrandingAssetContentType":{"type":"string","enum":["image/png","image/jpeg","image/webp","image/svg+xml","image/x-icon","image/vnd.microsoft.icon"],"description":"MIME types accepted for uploaded branding assets."},"BrandingAssetUploadForm":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"The image file (png, jpeg, webp, svg, or ico)."}},"required":["file"]},"CorsAllowedOrigin":{"type":"object","properties":{"cors_origin_id":{"type":"string","format":"uuid"},"origin":{"type":"string","minLength":1,"maxLength":255,"description":"A web origin of the form scheme://host[:port] with no path or trailing slash.","example":"https://app.example.com"},"description":{"type":["string","null"],"maxLength":255},"created_at":{"type":"number","minimum":0},"created_by_user_id":{"type":"string","format":"uuid"}},"required":["cors_origin_id","origin","description","created_at","created_by_user_id"],"additionalProperties":false},"AddCorsOriginRequestBody":{"type":"object","properties":{"origin":{"type":"string","minLength":1,"maxLength":255,"description":"A web origin of the form scheme://host[:port] with no path or trailing slash.","example":"https://app.example.com"},"description":{"type":"string","maxLength":255,"description":"Optional human-readable note about the origin."}},"required":["origin"]},"TemplatePreviewErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"}},"required":["success","error"]},"TemplatePreviewRequestBody":{"type":"object","properties":{"template_id":{"type":"string","description":"Template to render.","example":"mailing-list-confirmation"},"props":{"type":"object","additionalProperties":{},"description":"Props passed to the template component. Non-object values are treated as {}."}},"required":["template_id"]},"TransportStatus":{"type":"object","properties":{"id":{"allOf":[{"$ref":"#/components/schemas/MailTransportKind"},{"description":"A mail transport this server knows about."}]},"configured":{"type":"boolean","description":"Whether the transport's env vars are present on this deployment."},"is_default":{"type":"boolean","description":"Whether MAIL_TRANSPORT selects this transport when a send request omits `transport`."},"enabled":{"type":"boolean","description":"Whether an admin has left this transport enabled at runtime. Only the test-database-transport can currently be disabled (from /admin/transports); a disabled transport rejects sends even when configured."}},"required":["id","configured","is_default","enabled"]},"UpdateTransportRequestBody":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether the transport may be used for sends. Only supported for the test-database-transport."}},"required":["enabled"]}},"parameters":{}},"paths":{"/api/send":{"post":{"tags":["Send"],"summary":"Send an email","description":"Sends a transactional email or a mailing-list send (when `to` is a mailing-list UUID). Accepts either an admin JWT or a mail-server API key; API-key callers are checked against the key's audience, sender, and transport scopes — admins bypass all scopes.","security":[{"AdminJwtAuth":[]},{"MailApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailRequestBody"}}}},"responses":{"200":{"description":"The email was sent (or validated, for dry runs).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"Invalid request body, unknown/unconfigured/admin-disabled transport, invalid template, or empty/oversized mailing list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The API key's audience, sender, or transport scope forbids this send.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to prepare or dispatch the email.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/mailing-lists":{"get":{"tags":["Mailing Lists"],"summary":"List mailing lists","description":"Public directory of mailing lists. Anonymous callers only see public lists; an optional admin bearer token widens the listing to private ones.","responses":{"200":{"description":"The mailing lists visible to the caller.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/MailingList"}}},"required":["success","data"]}}}},"500":{"description":"Failed to list mailing lists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Mailing Lists"],"summary":"Create a mailing list","security":[{"AdminJwtAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMailingListRequestBody"}}}},"responses":{"200":{"description":"The mailing list was created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMailingListSuccessResponse"}}}},"400":{"description":"Invalid request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to create the mailing list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/mailing-lists/join":{"post":{"tags":["Mailing Lists"],"summary":"Start a mailing list subscription (double opt-in)","description":"Sends a confirmation email to the address; the subscription only becomes active once the emailed link is confirmed via POST /api/mailing-lists/confirm. The response does not reveal whether the address was already subscribed. Subject to the CORS origin allowlist for cross-origin browser calls.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinMailingListRequestBody"}}}},"responses":{"200":{"description":"A confirmation email has been sent (or the address was already subscribed).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"Invalid request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to start the subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/mailing-lists/confirm":{"post":{"tags":["Mailing Lists"],"summary":"Confirm a pending mailing list subscription","description":"Completes the double opt-in started by POST /api/mailing-lists/join, using the token from the confirmation email. Confirming an already-confirmed subscription succeeds idempotently.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmSubscriptionRequestBody"}}}},"responses":{"200":{"description":"The subscription is confirmed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmSubscriptionSuccessResponse"}}}},"400":{"description":"The confirmation link is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"The confirmation link has expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to confirm the subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/mailing-lists/unsubscribe":{"post":{"tags":["Mailing Lists"],"summary":"Unsubscribe from a mailing list","description":"Records an unsubscribe for the address on the given mailing list; future sends to that list skip the address.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaveMailingListRequestBody"}}}},"responses":{"200":{"description":"The address was unsubscribed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"Invalid request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to unsubscribe the address.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/mailing-lists/subscribers":{"get":{"tags":["Mailing Lists"],"summary":"List a mailing list's subscribers","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"ID of the mailing list whose subscribers to list.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"required":true,"description":"ID of the mailing list whose subscribers to list.","name":"mailing_list_id","in":"query"}],"responses":{"200":{"description":"The mailing list's subscribers.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/MailingListSubscriber"}}},"required":["success","data"]}}}},"400":{"description":"Invalid or missing mailing_list_id query parameter.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list subscribers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/templates":{"get":{"tags":["Templates"],"summary":"List available email templates","description":"Lists the react-email templates in this server's catalog. Accepts either a mail-server API key or an admin JWT.","security":[{"AdminJwtAuth":[]},{"MailApiKeyAuth":[]}],"responses":{"200":{"description":"The template catalog.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/EmailTemplateListItem"}}},"required":["success","data"]}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list email templates.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/test-emails":{"get":{"tags":["Test Emails"],"summary":"List emails captured by the test-database transport","description":"Lists emails 'sent' through the fake test-database-transport, newest first. Accepts an admin JWT, or a mail-server API key whose transport scope permits the test-database transport. Intended for E2E tests verifying the full /api/send flow without real delivery.","security":[{"AdminJwtAuth":[]},{"MailApiKeyAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":200,"description":"Page size (default 50, max 200).","example":50},"required":false,"description":"Page size (default 50, max 200).","name":"limit","in":"query"},{"schema":{"type":["integer","null"],"minimum":0,"description":"Rows to skip, for paging (default 0).","example":0},"required":false,"description":"Rows to skip, for paging (default 0).","name":"offset","in":"query"}],"responses":{"200":{"description":"The captured test emails, newest first.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/TestEmail"}}},"required":["success","data"]}}}},"400":{"description":"Invalid limit/offset query parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The API key's transport scope does not permit the test-database transport.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list test emails.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/test-emails/{test_email_id}":{"get":{"tags":["Test Emails"],"summary":"Read one email captured by the test-database transport","description":"Reads a single fake-sent email by ID (the ID is also returned as the transport's message ID). Same authorization as the list endpoint.","security":[{"AdminJwtAuth":[]},{"MailApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"ID of the captured test email.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"required":true,"description":"ID of the captured test email.","name":"test_email_id","in":"path"}],"responses":{"200":{"description":"The captured test email.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/TestEmail"}},"required":["success","data"]}}}},"400":{"description":"Invalid test_email_id; must be a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The API key's transport scope does not permit the test-database transport.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No test email exists with this ID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to read the test email.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/branding/{asset_kind}":{"get":{"tags":["Branding"],"summary":"Serve a branding asset (logo or favicon)","description":"Public, unauthenticated. Serves the admin-uploaded asset for the kind; kinds without an upload (or with the database unreachable) redirect to the bundled default asset.","parameters":[{"schema":{"$ref":"#/components/schemas/BrandingAssetKind"},"required":true,"description":"Kind of white-label branding asset.","name":"asset_kind","in":"path"}],"responses":{"200":{"description":"The uploaded asset's image bytes.","content":{"image/*":{"schema":{"type":"string","format":"binary"}}}},"307":{"description":"Redirect to the bundled default asset for this kind (no custom upload)."},"404":{"description":"Unknown branding asset kind.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/api-keys":{"get":{"tags":["Admin: API Keys"],"summary":"List active API keys","security":[{"AdminJwtAuth":[]}],"responses":{"200":{"description":"The active (non-revoked) API keys.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyRecord"}}},"required":["success","data"]}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list API keys.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Admin: API Keys"],"summary":"Create an API key","description":"Creates a key with allow_any_audience=false and no scope entries, so it can send to nobody until its audience is configured. The plaintext token is returned exactly once.","security":[{"AdminJwtAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequestBody"}}}},"responses":{"200":{"description":"The created key, including its plaintext token (shown only this once).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CreatedApiKey"},"message":{"type":"string"}},"required":["success","data","message"]}}}},"400":{"description":"Invalid request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to create the API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/api-keys/{api_key_id}":{"patch":{"tags":["Admin: API Keys"],"summary":"Update an API key","description":"`name` renames the key's label; `allow_any_audience` toggles the key's permission to send to any recipient. The key's ID, secret and scope entries are unchanged either way.","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"ID of the API key.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"required":true,"description":"ID of the API key.","name":"api_key_id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateApiKeyRequestBody"}}}},"responses":{"200":{"description":"The updated key.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/ApiKeyRecord"},"message":{"type":"string"}},"required":["success","data","message"]}}}},"400":{"description":"Invalid api_key_id or request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No active API key with this ID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to update the API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Admin: API Keys"],"summary":"Revoke an API key","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"ID of the API key.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"required":true,"description":"ID of the API key.","name":"api_key_id","in":"path"}],"responses":{"200":{"description":"The key was revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"Invalid api_key_id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to revoke the API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/api-keys/{api_key_id}/allowlist":{"get":{"tags":["Admin: API Keys"],"summary":"List an API key's audience mailing-list allowlist entries","description":"Mailing-list entries and individual-recipient entries form ONE combined audience allowlist for the key (unless the key's allow_any_audience flag is set).","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"ID of the API key.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"required":true,"description":"ID of the API key.","name":"api_key_id","in":"path"}],"responses":{"200":{"description":"The key's audience mailing-list allowlist entries.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"string","format":"uuid","description":"An allowlisted mailing list ID."}}},"required":["success","data"]}}}},"400":{"description":"Invalid api_key_id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list the key's audience mailing-list allowlist entries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Admin: API Keys"],"summary":"Add a mailing list to an API key's audience mailing-list allowlist","description":"Mailing-list entries and individual-recipient entries form ONE combined audience allowlist for the key (unless the key's allow_any_audience flag is set).","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"ID of the API key.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"required":true,"description":"ID of the API key.","name":"api_key_id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyAllowlistMutationBody"}}}},"responses":{"200":{"description":"The mailing list was added.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"Invalid api_key_id, invalid body, or unknown referenced resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to add the mailing list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Admin: API Keys"],"summary":"Remove a mailing list from an API key's audience mailing-list allowlist","description":"Mailing-list entries and individual-recipient entries form ONE combined audience allowlist for the key (unless the key's allow_any_audience flag is set).","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"ID of the API key.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"required":true,"description":"ID of the API key.","name":"api_key_id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyAllowlistMutationBody"}}}},"responses":{"200":{"description":"The mailing list was removed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"Invalid api_key_id or invalid body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to remove the mailing list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/api-keys/{api_key_id}/recipients":{"get":{"tags":["Admin: API Keys"],"summary":"List an API key's audience recipient allowlist entries","description":"Individual-recipient entries and mailing-list entries form ONE combined audience allowlist for the key (unless the key's allow_any_audience flag is set).","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"ID of the API key.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"required":true,"description":"ID of the API key.","name":"api_key_id","in":"path"}],"responses":{"200":{"description":"The key's audience recipient allowlist entries.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"string","format":"email","description":"An allowlisted individual recipient address."}}},"required":["success","data"]}}}},"400":{"description":"Invalid api_key_id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list the key's audience recipient allowlist entries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Admin: API Keys"],"summary":"Add a recipient to an API key's audience recipient allowlist","description":"Individual-recipient entries and mailing-list entries form ONE combined audience allowlist for the key (unless the key's allow_any_audience flag is set).","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"ID of the API key.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"required":true,"description":"ID of the API key.","name":"api_key_id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyRecipientMutationBody"}}}},"responses":{"200":{"description":"The recipient was added.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"Invalid api_key_id, invalid body, or unknown referenced resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to add the recipient.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Admin: API Keys"],"summary":"Remove a recipient from an API key's audience recipient allowlist","description":"Individual-recipient entries and mailing-list entries form ONE combined audience allowlist for the key (unless the key's allow_any_audience flag is set).","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"ID of the API key.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"required":true,"description":"ID of the API key.","name":"api_key_id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyRecipientMutationBody"}}}},"responses":{"200":{"description":"The recipient was removed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"Invalid api_key_id or invalid body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to remove the recipient.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/api-keys/{api_key_id}/senders":{"get":{"tags":["Admin: API Keys"],"summary":"List an API key's allowed-senders scope entries","description":"With zero entries the sender dimension is unrestricted; otherwise the send's `from` (after default fallback) and `replyTo` must each match an entry (exact address or `*@domain` wildcard).","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"ID of the API key.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"required":true,"description":"ID of the API key.","name":"api_key_id","in":"path"}],"responses":{"200":{"description":"The key's allowed-senders scope entries.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"string","description":"A lowercase email address, or a `*@domain` wildcard permitting any local part at that domain.","example":"*@example.com"}}},"required":["success","data"]}}}},"400":{"description":"Invalid api_key_id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list the key's allowed-senders scope entries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Admin: API Keys"],"summary":"Add a sender to an API key's allowed-senders scope","description":"With zero entries the sender dimension is unrestricted; otherwise the send's `from` (after default fallback) and `replyTo` must each match an entry (exact address or `*@domain` wildcard).","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"ID of the API key.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"required":true,"description":"ID of the API key.","name":"api_key_id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeySenderMutationBody"}}}},"responses":{"200":{"description":"The sender was added.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"Invalid api_key_id, invalid body, or unknown referenced resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to add the sender.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Admin: API Keys"],"summary":"Remove a sender from an API key's allowed-senders scope","description":"With zero entries the sender dimension is unrestricted; otherwise the send's `from` (after default fallback) and `replyTo` must each match an entry (exact address or `*@domain` wildcard).","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"ID of the API key.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"required":true,"description":"ID of the API key.","name":"api_key_id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeySenderMutationBody"}}}},"responses":{"200":{"description":"The sender was removed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"Invalid api_key_id or invalid body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to remove the sender.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/api-keys/{api_key_id}/transports":{"get":{"tags":["Admin: API Keys"],"summary":"List an API key's allowed-transports scope entries","description":"With zero entries the transport dimension is unrestricted; otherwise the send's resolved transport (explicit or deployment default) must be an entry.","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"ID of the API key.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"required":true,"description":"ID of the API key.","name":"api_key_id","in":"path"}],"responses":{"200":{"description":"The key's allowed-transports scope entries.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/MailTransportKind"},{"description":"A mail transport this server knows about."}]}}},"required":["success","data"]}}}},"400":{"description":"Invalid api_key_id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list the key's allowed-transports scope entries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Admin: API Keys"],"summary":"Add a transport to an API key's allowed-transports scope","description":"With zero entries the transport dimension is unrestricted; otherwise the send's resolved transport (explicit or deployment default) must be an entry.","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"ID of the API key.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"required":true,"description":"ID of the API key.","name":"api_key_id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyTransportMutationBody"}}}},"responses":{"200":{"description":"The transport was added.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"Invalid api_key_id, invalid body, or unknown referenced resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to add the transport.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Admin: API Keys"],"summary":"Remove a transport from an API key's allowed-transports scope","description":"With zero entries the transport dimension is unrestricted; otherwise the send's resolved transport (explicit or deployment default) must be an entry.","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"ID of the API key.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"required":true,"description":"ID of the API key.","name":"api_key_id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyTransportMutationBody"}}}},"responses":{"200":{"description":"The transport was removed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"Invalid api_key_id or invalid body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to remove the transport.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/branding/{asset_kind}":{"put":{"tags":["Admin: Branding"],"summary":"Upload a custom branding asset","description":"Multipart form upload with the image under the `file` field (max 1MB). Replaces any previously uploaded asset of the same kind.","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"$ref":"#/components/schemas/BrandingAssetKind"},"required":true,"description":"Kind of white-label branding asset.","name":"asset_kind","in":"path"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/BrandingAssetUploadForm"}}}},"responses":{"200":{"description":"The asset was uploaded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/BrandingAssetMetadata"},"message":{"type":"string"}},"required":["success","data","message"]}}}},"400":{"description":"Missing file field, unsupported image type, or oversized image.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Unknown branding asset kind.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to store the asset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Admin: Branding"],"summary":"Remove a custom branding asset","description":"Reverts the app to the bundled default asset for the kind.","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"$ref":"#/components/schemas/BrandingAssetKind"},"required":true,"description":"Kind of white-label branding asset.","name":"asset_kind","in":"path"}],"responses":{"200":{"description":"The custom asset was removed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Unknown branding asset kind.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to remove the asset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/cors-origins":{"get":{"tags":["Admin: CORS"],"summary":"List allowed CORS origins","security":[{"AdminJwtAuth":[]}],"responses":{"200":{"description":"The allowed CORS origins.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/CorsAllowedOrigin"}}},"required":["success","data"]}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list allowed CORS origins.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Admin: CORS"],"summary":"Allow a CORS origin","security":[{"AdminJwtAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddCorsOriginRequestBody"}}}},"responses":{"200":{"description":"The origin was allowed.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CorsAllowedOrigin"},"message":{"type":"string"}},"required":["success","data","message"]}}}},"400":{"description":"Invalid request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The origin is already allowed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to allow the CORS origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/cors-origins/{cors_origin_id}":{"delete":{"tags":["Admin: CORS"],"summary":"Remove an allowed CORS origin","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"ID of the allowed-origin entry.","example":"b7d1f9c2-4a3e-4d24-9f6b-2f42f8f0a111"},"required":true,"description":"ID of the allowed-origin entry.","name":"cors_origin_id","in":"path"}],"responses":{"200":{"description":"The origin was removed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"Invalid cors_origin_id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to remove the CORS origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/templates":{"get":{"tags":["Admin: Templates"],"summary":"List email template IDs","security":[{"AdminJwtAuth":[]}],"responses":{"200":{"description":"The template IDs in this server's catalog.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"string"}}},"required":["success","data"]}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/templates/preview":{"get":{"tags":["Admin: Templates"],"summary":"Preview a template with sample props","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Template to render with its bundled sample props."},"required":true,"description":"Template to render with its bundled sample props.","name":"template_id","in":"query"}],"responses":{"200":{"description":"The rendered template HTML.","content":{"text/html":{"schema":{"type":"string","example":"<html>...</html>"}}}},"400":{"description":"Unknown template, invalid props, or invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplatePreviewErrorResponse"}}}}}},"post":{"tags":["Admin: Templates"],"summary":"Preview a template with custom props","security":[{"AdminJwtAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplatePreviewRequestBody"}}}},"responses":{"200":{"description":"The rendered template HTML.","content":{"text/html":{"schema":{"type":"string","example":"<html>...</html>"}}}},"400":{"description":"Unknown template, invalid props, or invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplatePreviewErrorResponse"}}}}}}},"/api/admin/transports":{"get":{"tags":["Admin: Transports"],"summary":"List mail transports with configured/default status","security":[{"AdminJwtAuth":[]}],"responses":{"200":{"description":"The transports this server knows about.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/TransportStatus"}}},"required":["success","data"]}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to resolve mail transport availability.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/transports/{transport_id}":{"patch":{"tags":["Admin: Transports"],"summary":"Enable or disable the test-database transport","description":"Toggles a transport's runtime kill switch. Only the fake-send `test-database-transport` supports this — it lets an admin stop fake sending in production without a redeploy. The real delivery transports (`resend`, `smtp`) are controlled by environment variables and reject this call.","security":[{"AdminJwtAuth":[]}],"parameters":[{"schema":{"allOf":[{"$ref":"#/components/schemas/MailTransportKind"},{"description":"The transport to update.","example":"test-database-transport"}]},"required":true,"description":"The transport to update.","name":"transport_id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTransportRequestBody"}}}},"responses":{"200":{"description":"The transport's updated status.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/TransportStatus"},"message":{"type":"string"}},"required":["success","data","message"]}}}},"400":{"description":"Unknown transport, a transport that cannot be toggled, or an invalid request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid admin credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to update the transport setting.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/openapi.json":{"get":{"tags":["Meta"],"summary":"This OpenAPI document","description":"The OpenAPI 3.1 description of this mail server's API. Rendered interactively at /docs.","responses":{"200":{"description":"The OpenAPI document.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{},"description":"An OpenAPI 3.1 document."}}}}}}}},"webhooks":{}}