Overview
This issue tracks the creation of rich, developer-first documentation for the Mail Platform feature shipped in #172. The docs should be detailed enough for a developer to pick up the feature cold and get fully productive, covering conceptual explanations, setup guides, and a complete API reference.
Context
PR #172 expanded urBackend's Mail API into a full Mail Platform. Key capabilities added:
- Asynchronous batch sending (up to 100 recipients per call)
- Bring Your Own Key (BYOK) — project owners can supply their own Resend API key
- Audiences & Contacts CRUD (BYOK-gated)
- Marketing Broadcasts (BYOK + Pro-plan gated)
- MailLog — persistent delivery log per project
- Webhook handler with Svix signature verification
- Dashboard UI — MailPlatform page with Delivery Logs, Audiences & Contacts, and Marketing Broadcasts tabs
Documentation Requirements
1. Feature Overview
- What is the Mail Platform?
- How does it fit into urBackend's broader API ecosystem?
- High-level architecture diagram (queue → Resend → webhook → MailLog)
- Plan-based feature gating table (Free vs Pro, BYOK vs shared key)
2. Getting Started / Setup Guide
- Prerequisites (Resend account, API key format
re_...)
- How to configure a project's Resend API key (BYOK) via the Dashboard
- Environment variables required on the server side (
RESEND_API_KEY, RESEND_API_KEY_2, RESEND_WEBHOOK_SECRET, EMAIL_FROM)
- Registering the Resend webhook URL in the Resend dashboard and pointing it at
POST /api/mail/webhook
3. Sending Emails
Single Email — POST /api/mail/send
- Request schema (to, subject, html, from, templateId, templateData)
- Quota enforcement and rate limiting behaviour
- Response envelope (
{ success, data, message })
- Error codes
Batch Email — POST /api/mail/send-batch
- Request schema (array of email objects, max 100)
- Per-recipient quota reservation and refund on failure
- Partial success behaviour (some recipients succeed, others fail)
- Response envelope with per-recipient results
4. Mail Logs
Listing Logs — GET /api/mail/logs (public API) / GET /:projectId/mail/logs (dashboard API)
- Response schema (
MailLog fields: resendEmailId, to, subject, status, usingByok, templateUsed, sentAt)
- Status enum:
queued | sent | delivered | bounced | complained | failed
- Sorting and pagination behaviour
Live Status — GET /api/mail/logs/:resendId / GET /:projectId/mail/logs/:resendId/live
- How it queries Resend in real time vs the cached DB status
- When to use live status vs the stored log
- 404 handling
5. Audiences & Contacts (BYOK-gated)
Audiences
GET /api/mail/audiences — list all audiences
POST /api/mail/audiences — create an audience ({ name })
DELETE /api/mail/audiences/:audienceId — delete an audience
Contacts
GET /api/mail/audiences/:audienceId/contacts — list contacts
POST /api/mail/audiences/:audienceId/contacts — add a contact ({ email, firstName, lastName, unsubscribed })
PATCH /api/mail/audiences/:audienceId/contacts/:contactId — update a contact
DELETE /api/mail/audiences/:audienceId/contacts/:contactId — remove a contact
Include a note explaining that these endpoints proxy directly to Resend and require a valid BYOK key. Error responses mirror Resend's error shape.
6. Marketing Broadcasts (BYOK + Pro plan required)
POST /api/mail/broadcasts — create a broadcast ({ audienceId, subject, html, from, scheduledAt? })
POST /api/mail/broadcasts/:id/send — trigger send
GET /api/mail/broadcasts — list broadcasts
GET /api/mail/broadcasts/:id — get broadcast detail
DELETE /api/mail/broadcasts/:id — delete a broadcast
- Explain the two-step create → send flow
- Document
from resolution order: request body → project.resendFromEmail → env fallback
- Quota check on create and send
7. Webhook Integration
- Why raw-body parsing is required for
POST /api/mail/webhook (Svix signature over raw buffer)
- How to configure
RESEND_WEBHOOK_SECRET
- Supported event types and how they map to
MailLog.status (email.delivered, email.bounced, email.complained, email.failed)
- What happens if the secret is not set (returns 500 — fail closed)
- Retry behaviour from Resend's side
8. Dashboard UI Guide
- How to navigate to the Mail Platform page (
/project/:projectId/mail)
- Delivery Logs tab — columns, live status modal, how to interpret status badges
- Audiences & Contacts tab — creating/deleting audiences, adding/removing contacts; locked when BYOK is not configured
- Marketing Broadcasts tab — composing and sending a broadcast; locked without BYOK + Pro plan
- Screenshots / annotated UI walkthroughs (if documentation is hosted somewhere that supports images)
9. Security Notes
- BYOK key format validation (
re_[A-Za-z0-9_]+)
- How the key is encrypted at rest (AES encryption via
encrypt/decrypt helpers)
- How to clear/rotate a BYOK key (send
resendApiKey: null in a project update)
- Cross-project access prevention on live status lookups
- Webhook signature verification flow (Svix)
10. Error Reference
- Complete table of error codes and messages returned by all new endpoints
- How upstream Resend errors are surfaced vs internal errors
11. Changelog / Migration Notes
- What changed from the previous single-send
/api/mail/send endpoint
- Any breaking changes (raw-body middleware placement, new required env vars)
Definition of Done
References
/cc @yash-pouranik
Overview
This issue tracks the creation of rich, developer-first documentation for the Mail Platform feature shipped in #172. The docs should be detailed enough for a developer to pick up the feature cold and get fully productive, covering conceptual explanations, setup guides, and a complete API reference.
Context
PR #172 expanded urBackend's Mail API into a full Mail Platform. Key capabilities added:
Documentation Requirements
1. Feature Overview
2. Getting Started / Setup Guide
re_...)RESEND_API_KEY,RESEND_API_KEY_2,RESEND_WEBHOOK_SECRET,EMAIL_FROM)POST /api/mail/webhook3. Sending Emails
Single Email —
POST /api/mail/send{ success, data, message })Batch Email —
POST /api/mail/send-batch4. Mail Logs
Listing Logs —
GET /api/mail/logs(public API) /GET /:projectId/mail/logs(dashboard API)MailLogfields: resendEmailId, to, subject, status, usingByok, templateUsed, sentAt)queued | sent | delivered | bounced | complained | failedLive Status —
GET /api/mail/logs/:resendId/GET /:projectId/mail/logs/:resendId/live5. Audiences & Contacts (BYOK-gated)
Audiences
GET /api/mail/audiences— list all audiencesPOST /api/mail/audiences— create an audience ({ name })DELETE /api/mail/audiences/:audienceId— delete an audienceContacts
GET /api/mail/audiences/:audienceId/contacts— list contactsPOST /api/mail/audiences/:audienceId/contacts— add a contact ({ email, firstName, lastName, unsubscribed })PATCH /api/mail/audiences/:audienceId/contacts/:contactId— update a contactDELETE /api/mail/audiences/:audienceId/contacts/:contactId— remove a contactInclude a note explaining that these endpoints proxy directly to Resend and require a valid BYOK key. Error responses mirror Resend's error shape.
6. Marketing Broadcasts (BYOK + Pro plan required)
POST /api/mail/broadcasts— create a broadcast ({ audienceId, subject, html, from, scheduledAt? })POST /api/mail/broadcasts/:id/send— trigger sendGET /api/mail/broadcasts— list broadcastsGET /api/mail/broadcasts/:id— get broadcast detailDELETE /api/mail/broadcasts/:id— delete a broadcastfromresolution order: request body → project.resendFromEmail → env fallback7. Webhook Integration
POST /api/mail/webhook(Svix signature over raw buffer)RESEND_WEBHOOK_SECRETMailLog.status(email.delivered,email.bounced,email.complained,email.failed)8. Dashboard UI Guide
/project/:projectId/mail)9. Security Notes
re_[A-Za-z0-9_]+)encrypt/decrypthelpers)resendApiKey: nullin a project update)10. Error Reference
11. Changelog / Migration Notes
/api/mail/sendendpointDefinition of Done
References
apps/public-api/src/controllers/mail.controller.js,apps/dashboard-api/src/controllers/project.controller.js,packages/common/src/models/MailLog.js,apps/web-dashboard/src/pages/MailPlatform.jsx/cc @yash-pouranik