Billing limits, AI credit top-ups, accessibility pass
Plan-limit enforcement lands end-to-end. Every route now gate-checks send counts, member seats, domain quotas, and API key limits against the active plan before writing to the database. AI credits can be topped up from the billing page without changing plan.
- NewAI credit top-ups purchasable via Stripe Checkout without a plan change
- NewReal-time plan-limit enforcement on every write path (sends, domains, members, keys, webhooks)
- NewMonthly included AI credits reset automatically at billing cycle start
- ImprovedLimit-exceeded errors return the exact limit, current usage, and upgrade path in the response body
- ImprovedFull keyboard-navigation audit — every interactive element is reachable by Tab with visible focus rings
- ImprovedARIA labels, landmark roles, and screen-reader announcements across dashboard and marketing site
- ImprovedCore Web Vitals pass — LCP, CLS, and INP all green on PageSpeed Insights
- FixedStripe webhook handler now correctly processes invoice.payment_failed and emails all owners
API keys v2 — scopes, channels, expiry, IP allowlists
API keys grew up. Every key now carries a fine-grained scope set, a per-channel restriction mask, an optional expiry date, and an IP allowlist. The key detail page shows per-key usage stats and a request history timeline.
- NewKey scopes: send, read, webhooks, team, billing, settings — grant exactly what is needed
- NewChannel restrictions — lock a key to email-only, SMS-only, or any subset of channels
- NewKey expiry — set a hard expiry date; the key is rejected after midnight UTC on that date
- NewIP allowlist — restrict a key to one or more CIDR ranges; all other origins get 403
- NewAPI key detail page with 30-day request count, error rate, and last-used timestamp
- NewKey usage sparkline on the keys list for quick health overview
- ImprovedKey creation drawer shows the plaintext key in a one-time reveal with copy button
- SecurityKeys are now validated against scope and channel restrictions on every request before org lookup
Insights — feed, anomaly detection, digest emails
The Insights page is now the AI nerve centre for your messaging. A live feed of AI-generated observations, a detail drawer with recommendations, a 30-day history timeline, and a weekly digest email sent every Monday morning.
- NewAI insights feed — hourly anomaly detection surfaces unusual patterns in send rates, bounce rates, and open rates
- NewInsight detail drawer — each insight includes a summary, severity level, affected metric chart, and one recommended action
- NewInsight history — 30-day timeline of all past insights with status (open, resolved, dismissed)
- NewWeekly digest email — Monday morning summary of the past week's insights and delivery stats
- NewInsight lifecycle — mark an insight as resolved or snooze it for 7 days
- ImprovedOverview page shows the three most recent open insights in a compact card strip
Passkeys, GitHub OAuth, inbound messages
Login got a major upgrade. Passkeys (WebAuthn) replace TOTP as the second factor — faster, phishing-resistant, and no codes to copy. GitHub OAuth joins Google as a one-click sign-in option. Inbound email and Telegram messages are now captured, threaded, and surfaced in the Logs inbox.
- NewPasskey registration and authentication via WebAuthn (Face ID, Touch ID, hardware keys)
- NewBackup codes — 8 single-use recovery codes generated at passkey setup
- NewContinue with GitHub — OAuth via arctic, same flow as Google
- NewInbound message capture — replies to email addresses and Telegram bots are threaded in Logs inbox
- NewConversation transcript drawer — interleaved view of outbound and inbound messages per thread
- ImprovedLogin page shows passkey prompt before password field on devices with a registered credential
- ImprovedSettings › Security panel shows all registered passkeys with device name, creation date, and last used
Webhooks, agent API, platform accounts
Outbound webhooks now ship with HMAC-SHA256 signatures, a 5-attempt retry schedule, and a delivery log. The agent endpoint (/v1/agent) lets AI agents send messages with automatic agent labelling in logs. Platform accounts can provision and manage sub-organisations.
- NewOutbound webhooks with Senddio-Signature HMAC-SHA256 signing on every delivery
- NewWebhook retry schedule: immediate, 1 min, 5 min, 30 min, 2 h — with per-delivery log
- NewAfter 5 failures the endpoint is marked degraded and owners are emailed
- New/v1/agent endpoint — structured tool for AI agents (Claude MCP, OpenAI tool)
- NewsentByAgent field on messages — dashboard renders an AI badge instead of a user avatar
- NewPlatform accounts — organisations with isPlatform=true can create and manage sub-organisations
- New/v1/platform/sub-accounts for sub-org provisioning via the internal SDK
Domains, DNS verification, scheduled sends
Custom sending domains can now be added, verified via DNS, and set as the default sender for an organisation. Scheduled messages let you queue a send for a future timestamp — up to 90 days ahead on PRO.
- NewCustom domain management — add a domain, get SPF/DKIM/DMARC DNS records, verify with one click
- NewDomain detail page shows DNS record status, last-checked timestamp, and verification history
- NewDefault domain per organisation — all sends use this domain unless overridden in the API call
- NewScheduled sends — set scheduledAt on any /v1/send request; the message is queued in BullMQ and sent at the specified time
- ImprovedDomain list redesigned per prototype — status badges, one-click re-verify, remove with confirmation
Team management, roles, and seat limits
Invite teammates by email, assign roles (Owner, Admin, Member, Viewer), and manage seats. Seat limits are enforced per plan. Invitations expire after 7 days and are revokable.
- NewTeam page — invite members by email, set role, view pending invitations
- NewRole hierarchy: Owner > Admin > Member > Viewer with a full permission matrix
- NewSeat enforcement — invitation blocked when the plan seat limit is reached
- NewInvitation email with 7-day expiry and a one-click accept link
- NewResend invitation with fresh token; old token is invalidated
- NewMember removal with confirmation — removes OrganizationMember row and writes audit event
- ImprovedWorkspace switcher in sidebar shows member count and current role badge
Billing — Stripe subscriptions and plan management
Stripe integration is live. Upgrade from FREE to STARTER or PRO via the billing page. Plan changes are processed through Stripe webhooks and reflected in the account instantly.
- NewBilling page showing current plan, next renewal date, and payment method
- NewUpgrade and downgrade via Stripe Checkout
- NewStripe webhook handler for checkout.session.completed, subscription.updated, subscription.deleted
- NewPlan-change transactional email sent to all owners on every upgrade, downgrade, and cancellation
- NewPayment-failed transactional email with invoice link and next retry date
- NewBilling audit events for every plan change
Logs — message history, filtering, and search
The Logs page is the primary debugging surface. Instant client-side status filtering, 150ms debounced full-text search, and a detail drawer that shows every delivery event without a page navigation.
- NewLogs page with all-channel message history
- NewClient-side status filter (queued, delivered, failed, bounced) — instant, no server round-trip
- NewFull-text search debounced at 150ms
- NewRow click opens a detail drawer with status timeline, headers, and raw payload
- NewCSV export of the current filtered set
- NewTest-mode badge — sdo_test_* key sends appear with a distinct label in logs
Core sending API — /v1/send, /v1/emails, test mode
The primary send endpoint is live. POST /v1/send routes a message to any of the six channels based on the channel field in the request. Test-mode keys (sdo_test_*) return a synthetic delivered response without touching any channel provider.
- NewPOST /v1/send — universal send endpoint for all six channels
- NewPOST /v1/emails — email-only alias for backward compatibility
- NewTest mode — sdo_test_* keys create Message rows with status DELIVERED and synthetic events
- NewRate-limit headers (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) on every response
- NewSuppression list check before every send
- NewBounce classification — SMTP 5xx → hard bounce → suppression; 4xx → soft → retry 3×
Authentication — email/password, Google OAuth, email verification
Full authentication stack. Sign up with email and password or Continue with Google. Email verification is required before live sends. Password reset invalidates all sessions.
- NewEmail + password signup and login with argon2id hashing
- NewContinue with Google — OAuth via arctic with PKCE
- NewEmail verification — 24-hour token, welcome email on first verify
- NewPassword reset with 1-hour token; resets all sessions on use
- Newiron-session v8 — httpOnly, Secure, SameSite=Lax, 30-day sliding expiry
- NewOnboarding flow — new users without an organisation are routed to workspace setup before the dashboard
- SecurityHIBP k-anonymity breach check on every new password
Foundation — multi-tenant organisations, API keys, email infrastructure
The core data model and infrastructure are in place. Every resource is scoped to an Organisation. Email delivery is running on dedicated infrastructure.
- NewMulti-tenant organisation model — plan, billing, members, and messages scoped per org
- NewAPI key generation — sdo_live_* and sdo_test_* prefixes, SHA-256 hash stored
- NewEmail infrastructure — dedicated sending IPs, DKIM signing
- NewPrisma schema — Organisation, User, ApiKey, Message, MessageEvent, Domain, AuditEvent
- NewBullMQ job queue for async message delivery
- NewwithOrg middleware — enforces org-scope on every route that touches user data