← All API sections

Sub-Accounts

Create and manage multi-tenant sub-accounts with isolated quotas

Overview

Sub-accounts let you create isolated child accounts under your parent account. Each sub-account gets its own API keys, domains, and email sending quota drawn from a shared pool. This is useful for SaaS platforms that send email on behalf of their customers, agencies managing multiple clients, or any multi-tenant setup where you need separation between senders.

Sub-accounts inherit the parent's plan tier and cannot create their own sub-accounts (maximum depth is one level).

Requirements

  • Plan: Business or Enterprise (sub-accounts are not available on the Free plan)
  • API key scope: sub_accounts:manage
  • Limits: Business plan allows up to 5 sub-accounts. Enterprise plan has no limit.

API Reference

All sub-account endpoints require authentication via the X-EuroMail-Api-Key header with the sub_accounts:manage scope.

Create Sub-Account

curl -X POST https://api.euromail.dev/v1/accounts \
  -H "X-EuroMail-Api-Key: em_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Client A",
    "email": "[email protected]",
    "password": "securepassword123",
    "monthly_quota": 5000
  }'
FieldRequiredDescription
nameYesDisplay name, 1-255 characters
emailYesUnique email address for the sub-account
passwordYesMinimum 8 characters
monthly_quotaYesMonthly sending quota, must be > 0

Response (201 Created):

{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Client A",
    "email": "[email protected]",
    "plan": "business",
    "monthly_quota": 5000,
    "emails_sent_this_month": 0,
    "is_active": true,
    "parent_account_id": "123e4567-e89b-12d3-a456-426614174000",
    "created_at": "2026-03-21T10:00:00Z"
  }
}

List Sub-Accounts

curl https://api.euromail.dev/v1/accounts?page=1&per_page=25 \
  -H "X-EuroMail-Api-Key: em_live_..."
ParameterDefaultDescription
page1Page number (minimum 1)
per_page25Results per page (1-100)

Response (200 OK):

{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Client A",
      "email": "[email protected]",
      "plan": "business",
      "monthly_quota": 5000,
      "emails_sent_this_month": 1243,
      "is_active": true,
      "parent_account_id": "123e4567-e89b-12d3-a456-426614174000",
      "created_at": "2026-03-21T10:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 25,
    "total": 3,
    "total_pages": 1
  }
}

Results are ordered by created_at descending. Parent accounts can only see their own sub-accounts.

Get Sub-Account

curl https://api.euromail.dev/v1/accounts/{id} \
  -H "X-EuroMail-Api-Key: em_live_..."

Returns the full sub-account details including updated_at. Returns 404 if the sub-account does not exist or belongs to a different parent.

Update Sub-Account

curl -X PATCH https://api.euromail.dev/v1/accounts/{id} \
  -H "X-EuroMail-Api-Key: em_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Client A (Updated)",
    "monthly_quota": 10000,
    "is_active": false
  }'
FieldDescription
nameNew display name (1-255 characters)
monthly_quotaNew quota (must be > 0, validated against available pool)
is_activeEnable or disable the sub-account

All fields are optional. Email and plan cannot be changed.

Delete Sub-Account

curl -X DELETE https://api.euromail.dev/v1/accounts/{id} \
  -H "X-EuroMail-Api-Key: em_live_..."

Returns 204 No Content. Deleting a sub-account cascades to its API keys, domains, and emails. The sub-account's allocated quota is returned to the parent's pool.

Sub-Account Analytics

curl "https://api.euromail.dev/v1/accounts/{id}/analytics?period=30d" \
  -H "X-EuroMail-Api-Key: em_live_..."
ParameterValuesDefaultDescription
period7d, 30d, 90d30dTime window

Response (200 OK):

{
  "data": {
    "total_sent": 4521,
    "total_delivered": 4480,
    "total_bounced": 41,
    "total_opens": 2105,
    "total_clicks": 312,
    "total_unsubscribes": 8,
    "delivery_rate_pct": 99.09,
    "bounce_rate_pct": 0.91,
    "open_rate_pct": 46.56,
    "click_rate_pct": 6.9
  },
  "period": {
    "days": 30
  }
}

Create API Key for Sub-Account

curl -X POST https://api.euromail.dev/v1/accounts/{id}/api-keys \
  -H "X-EuroMail-Api-Key: em_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Client A Production Key",
    "scopes": ["emails:send", "emails:read"]
  }'
FieldRequiredDescription
nameYesKey name, 1-255 characters
scopesNoArray of scopes (empty = full access)

Available scopes: emails:send, emails:read, emails:validate, domains:manage, templates:manage, webhooks:manage, contacts:manage, account:admin, sub_accounts:manage.

Response (201 Created):

{
  "data": {
    "id": "660e8400-e29b-41d4-a716-446655440000",
    "name": "Client A Production Key",
    "key": "em_prod_abc123...",
    "key_prefix": "em_prod_abc1",
    "scopes": ["emails:send", "emails:read"],
    "is_active": true,
    "created_at": "2026-03-21T10:05:00Z"
  }
}

The full key value is only returned once at creation time. Store it securely.

Aggregate Analytics

View combined analytics across the parent account and all sub-accounts:

curl "https://api.euromail.dev/v1/analytics/aggregate?period=30d" \
  -H "X-EuroMail-Api-Key: em_live_..."

Only root accounts can access this endpoint. Sub-accounts receive 403 Forbidden.

Quota Management

Sub-accounts draw from a shared quota pool. The pool is the parent account's monthly_quota minus the total allocated to all sub-accounts.

Example: If your account has a monthly quota of 50,000 and you create two sub-accounts with 10,000 each, you have 30,000 remaining in the pool for new sub-accounts or your own sending.

When you create or update a sub-account, EuroMail validates that the requested quota does not exceed the available pool. Quota changes use row-level locking to prevent race conditions during concurrent updates.

When a sub-account is deleted, its allocated quota is automatically returned to the pool.

Error Responses

StatusCause
400 Bad RequestInvalid name, email, password, or quota value
403 ForbiddenPlan does not support sub-accounts, or a sub-account is trying to manage other sub-accounts
404 Not FoundSub-account does not exist or belongs to a different parent
409 ConflictEmail address already in use
422 Unprocessable EntityInsufficient quota pool