Werkmail Docs
Contents

API

API endpoint reference

Base: https://werkmail.eu. {id} on /api/practices/{id} is the workspace UUID.

This table is the full live router. /openapi.yaml has the same paths and methods, plus request and response field names. A CI check fails if the router, this page, and the OpenAPI disagree. Rows marked Planned are not implemented.

GET /openapi.json returns JSON (application/json). GET /openapi.yaml returns YAML. GET /api/reference on the product origin is public, the same catalog as this page.

How an agent should call the API

  1. Send Authorization: Bearer $TOKEN on every route whose Auth column is bearer or platform admin. Public routes do not take a bearer.
  2. Prefer a project token (wm_proj_…) or team token (wm_team_…). GET /api/projects/me lists scopes (team tokens include audit.view and consent.view).
  3. Branch on the JSON code field. Retry only when x-error-codes marks that code retryable: true, and send Idempotency-Key (or X-Idempotency-Key) on the retry.
  4. Treat a send as accepted only when the status is 202 and the body has message_id and id. Then poll GET /api/emails/{id}.
  5. Do not call provider or billing callbacks (/api/public/ses-events, the inbound provider callback, POST /api/public/creem-webhook). POST /api/public/unsubscribe is 410.
Job Call
Send one message POST /api/emails or POST /api/practices/{id}/send
Send status GET /api/emails/{id}
List messages GET /api/emails (array; next page is X-Next-Cursor)
Counters GET /api/emails/stats
Suppress an address POST /api/practices/{id}/suppression or POST /api/suppressions
Webhook POST /api/practices/{id}/webhooks

Topic guides: Send, Messages, Drop-in, Webhooks, Suppressions, Inbound, Lists and campaigns, Errors.

Meta and documents

Method Path Auth Notes
GET /healthz public Liveness
GET /readyz public Readiness: database, migrations and worker heartbeat. 503 lists the failing checks.
GET /metrics bearer Prometheus metrics. Requires the ops/admin bearer or the dedicated metrics token.
GET /openapi.yaml public This OpenAPI document
GET|HEAD /bimi-logo.svg public Default BIMI logo · Default BIMI logo headers
GET /openapi.json public This OpenAPI document as JSON. Content-Type is application/json.
GET /api/reference public Public endpoint reference (this page). No bearer.
GET /api/reference.md public This page as Markdown. No bearer.
GET|POST /unsubscribe public Hosted unsubscribe page · Hosted unsubscribe form

Auth, meta, regions

Method Path Auth Notes
GET /api/regions bearer List supported European cloud regions. Returns the selectable European data processing regions (Frankfurt, Ireland, Paris, Stockholm, Milan, Zurich). London (eu-west-2) is not offered because the United Kingdom is outside the EU.
POST /api/templates/render bearer Compile MJML or Markdown/HTML into responsive email markup
GET /api/meta bearer Runtime flags, attachment policy, safe mode, and compliance gates
POST /api/auth/request-otp public Email a sign-in code — Always returns a generic 200 so the endpoint cannot be used to enumerate accounts.
POST /api/auth/verify-otp public Exchange a sign-in code for a session bearer
POST /api/auth/login-password public Password login (when enabled)
POST /api/auth/totp/verify public Complete a sign-in with the second factor
GET /api/auth/sso/start public Start single sign-on in the browser
GET /api/auth/sso/callback public Identity provider callback
GET /api/auth/totp bearer Second factor status of the signed-in user
POST /api/auth/totp/enroll bearer Start authenticator setup
POST /api/auth/totp/confirm bearer Confirm the first code and turn the second factor on
POST /api/auth/totp/disable bearer Turn the second factor off (needs a valid code)
POST /api/auth/totp/recovery-codes bearer Replace the recovery codes (needs a valid code)
POST /api/auth/logout bearer Revoke the current session bearer
GET /api/auth/me bearer Current session identity
GET /api/rbac/permissions bearer List permission strings used by roles and tokens

Workspaces, projects, access

Method Path Auth Notes
POST /api/practices/{id}/integrations/ics-preview bearer Preview ICS without sending
POST /api/practices/{id}/integrations/test-termin bearer Send test Termin with ICS attachment
GET|PUT /api/practices/{id}/regions bearer Get workspace primary and fallback European cloud regions · Update workspace primary and fallback European cloud regions
GET /api/practices/{id}/audit-export bearer Export DPO compliance audit report (CSV or JSON)
GET /api/practices/{id}/avv bearer Get Data Processing Agreement (AVV) template
POST /api/practices/{id}/avv/sign bearer Electronically sign Data Processing Agreement (AVV)
GET /api/practices/{id}/consent-audit/export bearer Workspace-wide consent ledger audit export (JSON or CSV). Requires consent.view (team tokens include it). Project tokens get 403 forbidden; the hint names consent.view.
GET /api/practices/{id}/reports/recipients bearer One row per recipient and send (message_id, to, subject, status, delivered_at, opened, clicked, bounced, complained, last_event). Empty workspace returns [].
GET /api/practices/{id}/reports/recipients/export bearer CSV with the same columns as the recipient send list
GET /api/practices/{id}/reports/recipients/{email} bearer Same rows as the recipient send list, for one address. Unknown address is 200 []. The body is never null.
GET /api/projects/me bearer Token self-introspection. Returns the workspace, projects, and scopes. Team tokens include audit.view and consent.view. Project tokens do not. Requires a practice token (wm_proj_... / wm_team_...).
GET|POST /api/practices bearer List workspaces visible to the caller · Create a workspace (alias of POST /api/projects)
GET /api/practices/{id} bearer Get one workspace
POST /api/practices/{id}/pause bearer Pause sending for a workspace
POST /api/practices/{id}/resume bearer Resume sending for a workspace
POST /api/practices/{id}/plan platform admin Set plan and monthly send cap (platform admin)
GET /api/practices/{id}/overview bearer Dashboard overview (plan usage, warm-up, reputation)
GET /api/practices/{id}/onboarding bearer Onboarding wizard status
GET /api/practices/{id}/cutover bearer Go-live checklist
GET /api/practices/{id}/billing bearer Billing summary for a workspace
GET /api/practices/{id}/sandbox bearer Sandbox checklist, progress and verified addresses
GET|PUT|DELETE /api/practices/{id}/sso bearer Single sign-on configuration, domains and SCIM tokens · Save the OpenID Connect connection · Remove the single sign-on connection
POST /api/practices/{id}/sso/domains bearer Claim an email domain and get the DNS TXT proof
POST /api/practices/{id}/sso/domains/verify bearer Check the DNS TXT record and verify the domain
DELETE /api/practices/{id}/sso/domains/{domain} bearer Remove a claimed domain
POST /api/practices/{id}/scim-tokens bearer Create a SCIM token (plaintext shown once)
DELETE /api/practices/{id}/scim-tokens/{tokenID} bearer Revoke a SCIM token
GET|POST /api/practices/{id}/verified-recipients bearer List test addresses and whether they are confirmed · Add a test address and send the confirmation link
POST /api/practices/{id}/first-send bearer Send a short test message to a confirmed address (guided first send)
DELETE /api/practices/{id}/verified-recipients/{recipientID} bearer Remove a test address
POST /api/practices/{id}/production-access bearer Request production access after the checklist is complete
GET /api/practices/{id}/plan-grant/certificate bearer Printable certificate for a time-limited plan
POST /api/practices/{id}/billing/checkout bearer Create a checkout session
POST /api/practices/{id}/billing/portal bearer Open the customer billing portal
GET|PATCH /api/practices/{id}/compliance bearer Read compliance settings (fields plus impressum_ok and impressum_error) · Update Impressum, from_name, legal sender fields, and compliance toggles, including unsubscribe_footer_enabled (visible unsubscribe line in the footer, default false; List-Unsubscribe headers are always sent). Requires settings.edit (team token or workspace role). Project send tokens (wm_proj_…) cannot call this endpoint.
GET /api/practices/{id}/events bearer Recent workspace event stream
GET /api/practices/{id}/audit bearer Workspace audit log. Requires audit.view (team tokens include it). Project tokens get 403 forbidden; the hint names audit.view.
GET|POST /api/practices/{id}/projects bearer List projects (route groups) in a workspace · Create a project (route group)
PATCH /api/practices/{id}/projects/{projectID} bearer Update a project
GET|POST /api/practices/{id}/routes bearer List sending routes · Create a sending route
PATCH|DELETE /api/practices/{id}/routes/{routeID} bearer Update route tracking settings · Delete a sending route (409 for the default, built-in, or in-use routes)
POST /api/practices/{id}/routes/{routeID}/default bearer Set the default route
GET|POST /api/practices/{id}/api-tokens bearer List practice API tokens (secrets never returned). Requires team.manage. · Create a team or project API token
GET|POST /api/practices/{id}/roles bearer List workspace roles. Requires team.manage. · Create a custom role (roles.manage)
PATCH|DELETE /api/practices/{id}/members/{memberID} bearer Update a member's role and project access · Remove a workspace member. DELETE requires team.manage.
POST /api/practices/{id}/demo/seed bearer Seed demo contacts and messages on one workspace
POST /api/projects bearer Create a workspace — Alias of POST /api/practices. Omit domain to start on the managed host.
PATCH /api/practices/{id}/workspace bearer Update workspace name and slug
POST /api/practices/{id}/presets/seed bearer Seed default routes and starter content
GET /api/practices/{id}/cockpit bearer Workspace health snapshot for the dashboard
GET /api/practices/{id}/bounce-reasons bearer Grouped bounce reasons
GET /api/practices/{id}/content-scores bearer Recent content-gate scores
GET /api/practices/{id}/exports/bi bearer BI CSV export — Query kind is stats, campaigns, bounces, scores, or audit.
GET /api/practices/{id}/practice-semantics bearer Practice mail semantics for the workspace
POST /api/practices/{id}/practice-mail/check bearer Check a practice-mail address
GET /api/practices/{id}/analytics bearer Workspace analytics
GET /api/practices/{id}/stats bearer Workspace send counters
GET /api/practices/{id}/rates bearer Daily send rates for one workspace
GET /api/practices/{id}/unsub-feedback bearer Unsubscribe reasons collected from the signed link
GET|PUT /api/practices/{id}/weekly-report bearer Read the weekly report schedule. Requires team.manage. · Update the weekly report schedule
GET|POST /api/practices/{id}/members bearer List workspace members · Invite a workspace member
PATCH|DELETE /api/practices/{id}/roles/{roleID} bearer Update a custom role · Delete a custom role
DELETE /api/practices/{id}/api-tokens/{tokenID} bearer Revoke an API token
POST /api/practices/{id}/api-tokens/{tokenID}/rotate bearer Rotate an API token. Requires team.manage. The replacement is returned once; the old token is revoked now or after a grace period of up to 7 days.
POST /api/practices/{id}/projects/{projectID}/client-portal-tokens bearer Create a client-portal link token — The raw token is returned once.

SCIM provisioning

SCIM 2.0 for identity providers. Authenticate with a workspace SCIM token (wm_scim_…) as bearer. Needs the Compliance plan or higher. See Single sign-on and SCIM.

Method Path Auth Notes
GET /scim/v2/ServiceProviderConfig SCIM token SCIM service provider configuration
GET /scim/v2/ResourceTypes SCIM token SCIM resource types
GET|POST /scim/v2/Users SCIM token List members. Supports filter=userName eq "value" · Create a member with the default role
GET|PUT|PATCH|DELETE /scim/v2/Users/{id} SCIM token Get a member · Replace a member (active=false removes the membership) · Patch a member (active, displayName) · Remove a member from the workspace
GET|POST /scim/v2/Groups SCIM token List workspace roles as groups · Not supported: roles are managed in the dashboard
GET|PATCH|PUT|DELETE /scim/v2/Groups/{id} SCIM token Get a role as a group · Add or remove group members (assigns the role) · Not supported: roles are managed in the dashboard

DNS and deliverability

Method Path Auth Notes
GET /api/practices/{id}/dns-records bearer DKIM / MAIL FROM / DMARC records to publish
POST /api/practices/{id}/check-dns bearer Verify DKIM / MAIL FROM DNS live
GET /api/practices/{id}/dns-records/cloudflare-zone bearer Download a BIND zone file for the workspace records
GET|POST /api/practices/{id}/domain-connect/cloudflare bearer One-click Domain Connect apply URL. GET and POST return the same apply_url and redirect_uri.
GET /api/practices/{id}/deliverability bearer SPF / DKIM / DMARC / BIMI posture and channel mix
GET /api/practices/{id}/channel-mix bearer Transactional vs broadcast send mix
GET /api/practices/{id}/placement bearer Subject-line placement / spam risk hints
POST /api/practices/{id}/custom-domain bearer Attach a custom sending domain
POST /api/practices/{id}/restore-managed-domain bearer Restore the managed sending domain
POST /api/projects/{id}/custom-domain bearer Attach a custom sending domain — Flat alias of POST /api/practices/{id}/custom-domain. Body field domain.
POST /api/projects/{id}/restore-managed-domain bearer Restore the managed sending host — Flat alias of POST /api/practices/{id}/restore-managed-domain.
GET|PUT|DELETE /api/practices/{id}/bimi-logo bearer Read the workspace BIMI logo · Upload the workspace BIMI logo · Remove the workspace BIMI logo

Send and messages

Method Path Auth Notes
POST /api/practices/{id}/send bearer Send transactional or broadcast email
GET|PUT /api/practices/{id}/sending-profile bearer Get the workspace sending lane (managed or BYOK) and comparison view · Set the workspace sending lane (managed or BYOK)
POST /api/practices/{id}/sending-profile/migrate bearer Migrate a workspace between managed and BYOK with a cutover checklist
POST /api/practices/{id}/send/batch bearer Send a batch of up to 500 messages
POST /api/practices/{id}/send/bulk bearer Templated bulk send with per-recipient variables
POST /api/practices/{id}/send/score bearer Dry-run the content and consent gates. Does not send. Returns the score, reasons, and warnings a real send would see. from must be a bare address (invalid_from, retryable false). from_name sets the display name.
POST /api/practices/{id}/send-test bearer Send a test through the mailbox simulator or a real quality address. kind real returns 422 code suppressed when the address is suppressed, same as POST /api/practices/{id}/send.
POST /api/practices/{id}/validate-emails bearer Validate recipient addresses (syntax, disposable, risk)
GET /api/practices/{id}/messages bearer List messages. Same filters as /messages/search (q, status, to, route_id, project_id, days, limit, offset). Empty filters return the recent list.
GET /api/practices/{id}/messages/search bearer Search messages
GET /api/practices/{id}/messages/{messageID} bearer Get one message. messageID is the Werkmail UUID (id from the send). The provider message id returns 400 bad_id (retryable false).
GET /api/practices/{id}/messages/{messageID}/timeline bearer Message plus its delivery / engagement event timeline. messageID is the Werkmail UUID, not the provider message id.
GET /api/practices/{id}/messages/{messageID}/events bearer Delivery / engagement events for one message. messageID is the Werkmail UUID, not the provider message id.

Drop-in send

Method Path Auth Notes
POST /api/compat/resend/emails bearer Resend-compatible send
POST /api/compat/postmark/email bearer Postmark-compatible send
POST /api/compat/lettermint/send bearer Lettermint-compatible send
POST /api/compat/lettermint/emails bearer Lettermint-compatible send via /emails
POST /api/compat/eu/send bearer Alias of Lettermint-compatible send
POST /api/compat/resend/emails/batch bearer Resend-compatible batch send (max 100)
GET /api/compat/resend/emails/{id} bearer Resend-compatible retrieve one email
POST /api/compat/postmark/email/batch bearer Postmark-compatible batch send (1-500)
POST /api/compat/lettermint/send/batch bearer Lettermint-compatible batch send (max 100)
POST /api/compat/eu/send/batch bearer Alias of the Lettermint-compatible batch send — Maximum 100 messages.
POST /api/compat/lettermind/send bearer Typo alias of the Lettermint-compatible send — Prefer /api/compat/lettermint/send.
POST /api/compat/lettermind/emails bearer Typo alias of the Lettermint-compatible emails send — Prefer /api/compat/lettermint/emails.
POST /api/compat/lettermind/send/batch bearer Typo alias of the Lettermint-compatible batch send — Prefer /api/compat/lettermint/send/batch.

Flat messages and account stream

Method Path Auth Notes
GET|POST /api/emails bearer List recent messages for the token's own workspace / project — Newest first. The body is a JSON array (empty => [], never 404). When more pages exist the opaque cursor is returned in the X-Next-Cursor response header; pass it back as cursor. A project token sees only its own project. · Send with workspace from the token
POST /api/emails/send-bulk bearer Templated bulk send (flat alias)
GET /api/emails/stats bearer Lightweight counters for the token's own workspace / project — Sent, delivered, bounced, complained, opened, and clicked over a window (max 90 days).
GET /api/emails/{id} bearer Status of one message for the token's own project — Poll-based status check after a 202 send, so webhooks are optional. Status transitions through queued, processed, delivered, opened, clicked, soft_bounced, hard_bounced, complained, unsubscribed, or suppressed.
GET /api/events platform admin Account-wide recent delivery events
GET /api/rates platform admin Account-wide daily send rates

Suppressions

Method Path Auth Notes
GET|POST /api/practices/{id}/suppression bearer List suppressed addresses · Add suppressed addresses (team / project / route scope)
POST /api/practices/{id}/suppression/import bearer Import suppressions from CSV
GET /api/practices/{id}/suppression/export bearer Export suppressions as CSV
POST /api/practices/{id}/suppression/bulk-delete bearer Bulk-delete suppressions (max 1000)
DELETE /api/practices/{id}/suppression/{suppressionID} bearer Delete one suppression
GET|POST /api/suppressions bearer List suppressions for a workspace — Query project_id is the workspace id. · Add a suppression — Body or query project_id is the workspace id.
DELETE /api/suppressions/{suppressionID} bearer Delete one suppression — Query project_id is the workspace id.

Contacts, lists, campaigns, journeys

Method Path Auth Notes
GET|POST /api/practices/{id}/topics bearer List marketing topics for a workspace · Create a marketing topic
PUT /api/practices/{id}/topics/order bearer Set the topic display order atomically. Body {"topic_ids":[...]}; listed topics come first, the rest keep their relative order. Unknown or duplicate ids return 400
GET|PATCH|DELETE /api/practices/{id}/topics/{topicID} bearer Read a single topic · Update topic name/description/visibility (default_subscription immutable). Partial update: omitted fields keep their value, an explicit empty description clears it. Sending default_subscription returns 422 code immutable_field. The response always includes description (empty string when unset). Topics and preference-center writes require projects.manage, contacts.manage, or settings.edit, not a project send token. Compliance/legal stays settings.edit only. · Delete a topic
GET /api/practices/{id}/contacts/lookup bearer Look up a contact by email and return the signed preference link — Returns preference_url plus signed p, e, t for GET/POST /api/public/portal and the /preferences SPA. Scoped to the token's workspace.
GET|PUT /api/practices/{id}/contacts/{contactID}/topics bearer List a contact's topic subscriptions · Replace a contact's topic subscriptions atomically
GET|PUT|PATCH /api/practices/{id}/preference-center bearer Get the workspace Preference Center branding · Replace the branding (full replacement, omitted fields are cleared) · Update single fields (partial, omitted fields keep their value). channels configures which consent channels contacts see on the public page, their order, label and description. Colours must be hex (#rgb, #rrggbb, #rrggbbaa), the logo must be an https URL; empty string clears a field
GET|PUT /api/practices/{id}/segments/{segmentID}/members bearer List a segment's explicit members (static membership) · Replace a segment's explicit membership atomically (marks segment static)
GET /api/practices/{id}/reports/campaigns/{campaignID} bearer Campaign aggregate report (sent/delivered/open/click + rates)
GET /api/practices/{id}/contacts/{contactID}/consent bearer Per-contact consent ledger
GET /api/practices/{id}/contacts/{contactID}/consent-history bearer Alias of GET .../consent
POST /api/practices/{id}/dsar-export bearer DSAR export for one contact (body contact_id). 202 when ready.
GET /api/practices/{id}/contacts/{contactID}/export bearer DSAR-ready contact export
GET|PATCH|DELETE /api/practices/{id}/contacts/{contactID} bearer Get one contact · Update a contact · Erase a contact (DSAR)
GET|POST /api/practices/{id}/lists bearer List contact lists · Create a contact list
GET /api/practices/{id}/lists/stats bearer Subscriber and active counts per list
GET|POST /api/practices/{id}/lists/{listID}/subscribers bearer List subscribers of a list · Add a subscriber — Without status=active, the response includes confirm_token for GET /api/public/confirm?token=. status=active or skip_doi=true skips DOI and writes a newsletter-channel consent grant (source active_import). The public subscribe API does not return a confirm token.
GET|POST /api/practices/{id}/campaigns bearer List broadcast campaigns · Create, schedule, or queue a broadcast campaign
GET /api/practices/{id}/contacts bearer List contacts
GET|POST /api/practices/{id}/fields bearer List custom contact fields · Create a custom contact field
DELETE /api/practices/{id}/fields/{fieldID} bearer Delete a custom contact field
GET|POST /api/practices/{id}/segments bearer List segments · Create a segment
GET|PATCH|DELETE /api/practices/{id}/segments/{segmentID} bearer Read a single segment · Update a segment · Delete a segment
GET /api/practices/{id}/segments/{segmentID}/preview bearer Preview which contacts match a segment
GET|POST /api/practices/{id}/templates bearer List message templates · Create a message template
GET|PATCH|DELETE /api/practices/{id}/templates/{templateID} bearer Read a single message template · Update a message template · Delete a message template
DELETE /api/practices/{id}/lists/{listID} bearer Delete a subscriber list
POST /api/practices/{id}/lists/{listID}/subscribers/import bearer Import subscribers — JSON emails array, or a CSV upload.
DELETE /api/practices/{id}/lists/{listID}/subscribers/{subID} bearer Remove a subscriber
GET|PATCH /api/practices/{id}/campaigns/{campaignID} bearer Get one campaign · Update a draft campaign
POST /api/practices/{id}/campaigns/{campaignID}/start bearer Queue a campaign now
POST /api/practices/{id}/campaigns/{campaignID}/schedule bearer Schedule a campaign — Body field scheduled_at (RFC3339).
POST /api/practices/{id}/campaigns/{campaignID}/cancel bearer Cancel a campaign
POST /api/practices/{id}/campaigns/{campaignID}/test bearer Send a campaign test
GET /api/practices/{id}/campaigns/{campaignID}/stats bearer Campaign delivery stats
GET /api/practices/{id}/campaigns/{campaignID}/links bearer Campaign link click stats
GET|PUT /api/practices/{id}/campaigns/{campaignID}/variants bearer A/B variant stats · Replace A/B variants
POST /api/practices/{id}/campaigns/{campaignID}/ab-winner bearer Pick the A/B winner and send the remainder
GET|POST /api/practices/{id}/journeys bearer List journeys · Create a journey
POST /api/practices/{id}/journeys/seed-termin-recall bearer Seed the termin-to-recall journey
GET|PATCH|DELETE /api/practices/{id}/journeys/{journeyID} bearer Get one journey · Update a journey · Delete a journey

Webhooks, alerts, inbound

Method Path Auth Notes
GET|PATCH /api/practices/{id}/inbound bearer Inbound receiving status and MX checklist · Update inbound webhook URL
POST /api/practices/{id}/inbound/enable bearer Enable inbound receiving for in.
GET|POST /api/practices/{id}/inbound-hooks bearer List inbound send hooks · Create inbound send hook
GET|POST /api/practices/{id}/alerts bearer List Slack/Teams alert endpoints · Create Slack or Teams alert endpoint
GET|POST /api/practices/{id}/webhooks bearer List signed outbound webhooks · Create signed outbound webhook
DELETE /api/practices/{id}/webhooks/{webhookID} bearer Delete a webhook
POST /api/practices/{id}/webhooks/{webhookID}/test bearer Send a test webhook delivery
GET /api/practices/{id}/webhooks/{webhookID}/deliveries bearer Webhook delivery log (paginated, latest first)
POST /api/practices/{id}/webhooks/{webhookID}/deliveries/{deliveryID}/replay bearer Replay a delivery
POST /api/practices/{id}/webhooks/{webhookID}/enable bearer Enable a webhook
POST /api/practices/{id}/webhooks/{webhookID}/rotate-secret bearer Rotate the webhook signing secret
GET /api/practices/{id}/inbound/messages bearer Recently received inbound messages
DELETE /api/practices/{id}/alerts/{alertID} bearer Delete a Slack or Teams alert
POST /api/practices/{id}/alerts/{alertID}/test bearer Send a test alert
POST /api/practices/{id}/inbound/disable bearer Disable inbound receiving
POST /api/practices/{id}/inbound/check bearer Re-check inbound DNS
POST /api/practices/{id}/inbound/apply-dns bearer Publish inbound MX when DNS apply is enabled
GET /api/practices/{id}/inbound/messages/{messageID} bearer Get one inbound message
DELETE /api/practices/{id}/inbound-hooks/{hookID} bearer Delete an inbound send hook
POST /api/practices/{id}/inbound-hooks/{hookID}/rotate bearer Rotate an inbound hook secret — The new secret is returned once.
POST /api/practices/{id}/inbound-hooks/{hookID}/test bearer Send a test message through an inbound hook

Public

Method Path Auth Notes
POST /api/public/hooks/{id}/send public Inbound send webhook (Zapier/Make/n8n) — Authenticate with header X-Werkmail-Hook-Secret.
Same body as /api/practices/{id}/send.
POST /api/public/ses-inbound public Inbound receiving event notifications
GET|POST /api/public/portal public Unified preference center payload — Two auth modes, mutually exclusive. (1) token — long-lived contact portal token from the contact profile (?token=). (2) signed link — p (practice UUID), e (email), t (HMAC from PreferenceCenterURL / contacts/lookup). Errors use {code,error,hint}: bad_auth (400), contact_not_found (404). · Save preference center changes (JSON) — Same auth as GET (token or p/e/t in the body or query).
GET|POST /api/public/preferences public Branded preference center page (signed link) — Redirects to /preferences SPA; prefer /api/public/portal JSON. · Save topic checkboxes or unsubscribe from all (signed link)
GET /api/public/domain-connect/template public Domain Connect template for the provider
GET /api/public/domain-connect/meta public Domain Connect discovery metadata
GET|POST /api/public/unsub public One-click unsubscribe (signed link) · One-click unsubscribe (RFC 8058 List-Unsubscribe=One-Click)
GET /api/public/confirm public Double opt-in confirmation
GET|POST /api/public/abuse public Abuse desk information · Submit an abuse report
POST /api/public/subscribe public Public list subscribe (double opt-in)
POST /api/public/waitlist public Join the product waitlist
GET /api/public/landing public Public landing content for a workspace host
GET /api/public/site public Public site catalog and legal pointers
GET /api/public/client-portal public Client portal dashboard — Query token is the client-portal token.
GET /api/public/bimi/{id} public Public BIMI logo. Path id is {workspaceUUID}.svg. 200 SVG or 404 bimi_logo_not_hosted.
POST /api/public/creem-webhook public Billing provider webhook — Not a send API. Signed with the creem-signature header.
GET /api/public/creem-return public Billing checkout return URL — Not a send API.
POST /api/public/ses-events public Provider delivery-event callback — Not a customer send API. Signature-checked provider notifications.
POST /api/public/unsubscribe public Retired unsubscribe endpoint — Always 410. Use the signed /api/public/unsub link.
GET /api/public/waitlist/admin-action public Signed waitlist admin link from email — Not a bearer API.
GET|POST /api/public/waitlist/join public Preview a waitlist invite · Complete a waitlist invite
POST /api/public/access/redeem public Redeem an access code for an account invitation
GET /api/public/status public Platform status, 90 day uptime and incidents
GET /api/public/verified-recipients/confirm public Confirm a sandbox test address from the emailed link

Operator routes

Authenticated routes for operators. Rows marked platform admin reject team and project tokens.

Method Path Auth Notes
GET /api/ops/digest platform admin Ops digest (abuse + cheap deliverability snapshot, platform admin)
GET /api/ops/jobs platform admin List background jobs by status and kind (default failed), cursor paginated, no payloads
POST /api/ops/jobs/{id}/retry platform admin Requeue a failed job
POST /api/ops/jobs/{id}/discard platform admin Discard a failed or pending job with a reason
GET /api/ops/vdm platform admin Cheap deliverability snapshot (platform admin). Advisor + ISP metrics. Never subscribes to Global / $1,250 dashboard.
POST /api/practices/wire-event-destinations platform admin Attach delivery-event destinations on every workspace sending profile
GET|PUT /api/admin/user-entitlements platform admin Read a user's workspace entitlement · Set a user's workspace entitlement
GET|POST /api/admin/access-codes platform admin List access codes · Create an access code (plaintext returned once)
POST /api/admin/access-codes/{id}/disable platform admin Disable an access code
POST /api/admin/access-codes/{id}/provision platform admin Bulk provision addresses against an access code
POST /api/admin/prize-grants platform admin Give winners a time-limited plan
GET|POST /api/admin/incidents platform admin List status page incidents · Open a status page incident
POST /api/admin/incidents/{id}/updates platform admin Post an incident update and change its status
GET /api/admin/production-access platform admin List production access requests
POST /api/admin/production-access/{id}/decide platform admin Approve or reject a production access request
POST /api/admin/practices/{id}/approve-production platform admin Move a workspace to production without a request
GET /api/abuse platform admin List abuse-desk reports. Requires platform.admin.
GET|PATCH /api/abuse/{reportID} platform admin Get one abuse report · Update an abuse report
POST /api/abuse/{reportID}/messages platform admin Reply on an abuse report
GET /api/abuse/{reportID}/attachments/{attachmentID} platform admin Download an abuse-report attachment
GET /api/waitlist platform admin List waitlist signups
POST /api/waitlist/{id}/accept platform admin Accept a waitlist signup
POST /api/waitlist/{id}/reject platform admin Reject a waitlist signup
GET|PUT /api/smtp platform admin Read the optional SMTP relay settings — The password is never returned. · Update the optional SMTP relay settings — Omit password to keep the stored secret.
POST /api/smtp/enabled platform admin Enable or disable the SMTP relay — Body field enabled (boolean).
POST /api/smtp/probe platform admin Check SMTP authentication and TLS without sending
POST /api/smtp/test platform admin Send one SMTP test message — Body field to.
POST /api/demo/seed bearer Seed the showcase workspace

View this page as Markdown · llms.txt · full corpus