Self-Hosted vs Commercial

Inboxes runs in one of two modes, determined by a single environment variable at startup.

How mode is determined

  • STRIPE_KEY is set and non-empty — Commercial mode (billing, email verification, open signup)
  • STRIPE_KEY is unset or empty — Self-hosted mode (no billing, no email verification, invite-only after initial setup)

Self-hosted mode

Setup wizard

On first launch with zero users in the database, the setup wizard is available:

  1. GET /api/setup/status — returns needs_setup: true when zero users exist
  2. POST /api/setup/validate-key — validates a Resend API key and returns available domains
  3. POST /api/setup — creates the first org and admin user

After setup, a JWT cookie is set automatically so the admin proceeds directly to onboarding.

Invite-only after setup

After the first user exists, new users can only be added via POST /api/users/invite (requires admin role). Both the setup wizard and the signup endpoint are locked.

No email verification

In self-hosted mode, all users are created with email_verified = true. There is no verification code step.

System email configuration

The instance owner can manage system email settings through owner-only endpoints:

  • GET /api/system/email — returns current from-address and from-name
  • PATCH /api/system/email — updates settings, with optional test email

Auto-poll (inbox poller)

Self-hosted instances that cannot receive webhooks (e.g., behind NAT) can enable automatic polling:

SettingDefaultRange
auto_poll_enabledfalse
auto_poll_interval300 (seconds)120–3600

The inbox poller checks every 30 seconds for orgs due for polling, fetching up to 10 pages (100 emails per page) and stopping when it encounters an already-imported email.


Commercial mode

Open signup with email verification

In commercial mode, signup is open to anyone. New users receive a 6-digit verification code by email and must verify before logging in.

Plan enforcement

Feature endpoints are gated by RequirePlan middleware:

  • pro and past_due plans are allowed through
  • cancelled plans with a future plan_expires_at are allowed (grace period)
  • Returns 402 "subscription_required" otherwise
  • In self-hosted mode, this middleware is a no-op

Feature comparison

BehaviorSelf-HostedCommercial
Mode triggerSTRIPE_KEY absentSTRIPE_KEY present
First-run setupSetup wizard or first-user signupStandard signup
Signup after first userDisabled (403)Open registration
Email verificationSkippedRequired (6-digit code)
Billing / StripeNo plan enforcementActive plan required
System email settingsOwner-configurable via UIManaged via env vars only
Auto-poll settingsAvailable in org settingsHidden

/api/config endpoint

GET /api/config is a public, unauthenticated endpoint that returns runtime configuration for the frontend. Cached for 1 hour.

{
  "api_url": "https://mail.yourdomain.com",
  "ws_url": "wss://mail.yourdomain.com",
  "commercial": false
}

The frontend uses commercial to conditionally show billing UI, signup forms, and verification flows.