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.
Native (recommended)
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" }.
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.