Werkmail Docs
Contents

API

Drop-in send APIs

Keep your existing client. Change the base URL (and put a Werkmail bearer in the token field). Bodies and success envelopes match the foreign SDK. Gates do not change — content score, consent, suppressions, and stream split still apply. Failures return that vendor’s error shape plus our hint in the message text.

Set BASE=https://werkmail.eu. Authenticate with Authorization: Bearer $TOKEN (wm_team_… or wm_proj_…). A project token already knows the workspace. A session bearer must pass practice_id (query, body, or X-Werkmail-Practice).

Postmark clients may send X-Postmark-Server-Token instead of Authorization — use the same Werkmail token value.

POST /api/practices/{id}/send and POST /api/emails (workspace from the token).

Flexible JSON: text/html or text_body/html_body; to as string, array, or comma-separated list; PascalCase Postmark fields; Resend-style tags: [{name, value}].

Success is 202 with { "id", "message_id", "status", "code", "hint" }code/hint appear when something is blocked.

Resend SDK

Base URL: https://werkmail.eu/api/compat/resend

SDK call Werkmail path
emails.send POST /emails
emails.send batch POST /emails/batch (max 100)
retrieve GET /emails/{id}

Success is 200 { "id": "…" } (batch: { "data": [{ "id" }] }). Errors use { "statusCode", "name", "message" }.

bash
curl -sS -X POST "$BASE/api/compat/resend/emails" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: order-123" \
  -d '{
    "from": "Praxis <noreply@your-domain.example>",
    "to": ["you@example.com"],
    "subject": "Terminbestätigung",
    "html": "<p>Ihr Termin ist bestätigt.</p>",
    "tags": [{"name": "kind", "value": "termin"}]
  }'

scheduled_at is not delayed — you get a validation error with a hint. Use a campaign schedule instead.

Postmark SDK

Base URL: https://werkmail.eu/api/compat/postmark

SDK call Werkmail path
send POST /email
send batch POST /email/batch

Success is 200 { "ErrorCode": 0, "Message": "OK", "MessageID", "To", "SubmittedAt" }. Errors use { "ErrorCode", "Message" }.

MessageStream outbound maps to outgoing; broadcast stays broadcast. To may be a comma-separated string. Headers may be [{ "Name", "Value" }]. Attachments accept Name / Content / ContentType.

EU transactional clients

Base URL: https://werkmail.eu/api/compat/eu

Call Path
send POST /send
batch POST /send/batch

Same flexible body as native send. Response is the native envelope (id, status, code, hint). Existing Letterwerk-style bulk remains at POST /api/emails/send-bulk.

We do not publish a brand-vs-brand base URL for every EU send API. If your client posts JSON from / to / subject / html to /send or /emails, point it here.

What is never a silent drop-in

Foreign feature Werkmail behaviour
React Email / server-side JSX Render HTML in your app, send html
Dedicated IP / stream product names Use outgoing vs broadcast
Skipping unsubscribe or DOI Broadcast still requires Impressum + DOI
Provider-account suppression as the only list Our Postgres suppressions still apply

See Errors, Send, and Regulated transactional.

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