403 on everything else and cannot manage pods or mint keys.
This guide walks the full onboarding flow — pod, domain (optional), inbox, scoped key — then inbound routing and offboarding.
Prerequisites
- An OpenMail account with your account-wide API key. You use it to provision tenants; it never leaves your side.
- A stable tenant identifier from your own system (a user ID, org ID, or workspace ID) to use as the pod’s
clientId.
Use this pre-built prompt to get started faster.
Step 1: Create a pod per tenant
When a tenant signs up, create a pod and pass your own tenant ID asclientId. From then on you can address the pod by that ID everywhere — no mapping table on your side.
Step 2: Add a tenant domain (optional)
For white-label setups, scope a custom domain to the pod so the tenant’s inboxes live on their own domain (e.g.support@meridian.io). Add and verify the domain in the dashboard under Settings → Domains, then scope it to the pod — or use the pod’s Domains tab. A pod-scoped domain can only be used by inboxes in that same pod.
Skip this step to put the tenant’s inboxes on your account default domain, or on an account-wide domain every pod shares.
Step 3: Create the tenant’s inboxes
Create inboxes directly in the pod by passingpodId (the pod ID or your clientId). An inbox belongs to exactly one pod and cannot be moved later, so pick the pod at creation.
Step 4: Mint a pod-scoped API key
Mint a key scoped to the tenant’s pod. This is the key the tenant’s integration will use. It can read and send only from this pod’s inboxes.api_key_limit_reached (422) — list the pod’s keys with GET /v1/pods/{id}/api-keys and revoke an unused one first. Listing returns only a masked tokenPrefix and last4, never the token.
Step 5: Hand the scoped key to the tenant’s integration
Give the scoped token to whatever runs on the tenant’s behalf — a per-tenant worker, an agent container, or the tenant’s own environment. The key cannot cross pods or manage pods, so it safely confines the tenant to their own inboxes:Handle inbound email
Every inbound event carries theinbox_id it arrived on. Map that to the tenant and deliver — the same routing you’d use for any per-inbox integration. See Handle inbound email in the API integration guide for the full WebSocket and webhook handlers.
Subscribe with your account-wide key to receive events across every pod, then fan out by
inbox_id. A pod-scoped key’s subscription is filtered to its own pod, so a per-tenant worker only sees its tenant’s events. One caveat: a pod-scoped subscribe-all covers the pod’s inboxes at subscribe time — re-subscribe after creating an inbox to stream its events.Full onboarding flow
Putting the steps together — one function that provisions a tenant from scratch and returns the scoped key to store:Offboarding a tenant
Revoke the tenant’s key first, then clean up their pod. Revocation is immediate — the key returns401 on its next request.
Reference
| What | Endpoint | Key required |
|---|---|---|
| Create a tenant’s pod | POST /v1/pods | Account-wide |
| Create inboxes in the pod | POST /v1/inboxes (with podId) | Account-wide |
| Mint the tenant’s scoped key | POST /v1/pods/{id}/api-keys | Account-wide |
| List a pod’s keys (masked) | GET /v1/pods/{id}/api-keys | Account-wide |
| Revoke a key | DELETE /v1/pods/{id}/api-keys/{keyId} | Account-wide |
| Send / receive within a pod | POST /v1/inboxes/{id}/send, etc. | Pod-scoped or account-wide |
Pods
The full pods model: isolation,
clientId, patterns, and lifecycle.Authentication
Account-wide vs. pod-scoped keys and the token-once rule.
Custom domains
Scope a domain to one pod for white-label tenant addresses.
API integration
Per-inbox provisioning, skill files, and inbound routing.