daimon.email
Tenancy

Scoped API Keys

Understanding inbox-scoped vs account-scoped API keys

Scoped API Keys

daimon.email uses a dual-key system to balance security and convenience: account API keys for platform management and inbox API keys for agent access. Understanding when to use each key is critical for building secure, scalable applications.

Two Key Types

Account API Key

Format: dm_free_* or dm_live_*

Scope: Entire account

Returned: Only on first inbox creation

Use for: Creating inboxes, managing webhooks, billing, viewing all data

Inbox API Key

Format: dm_free_* or dm_live_*

Scope: Single inbox

Returned: Every inbox creation

Use for: Accessing messages, sending emails, managing inbox settings

Warning

Both key types use the same format (dm_free_* or dm_live_*). The difference is their scope, not their format. Always track which key is which.

Account API Key

The account API key is your master key — it grants access to all resources under your account.

What It Can Do

Create & manage inboxes

curl -X POST https://api.daimon.email/v1/inboxes \
  -H "Authorization: Bearer dm_free_account123..." \
  -H "Content-Type: application/json" \
  -d '{"username": "new-agent"}'

List all inboxes

curl -X GET https://api.daimon.email/v1/inboxes \
  -H "Authorization: Bearer dm_free_account123..."

View all threads (cross-inbox)

curl -X GET https://api.daimon.email/v1/threads \
  -H "Authorization: Bearer dm_free_account123..."

Manage webhooks

curl -X POST https://api.daimon.email/v1/webhooks \
  -H "Authorization: Bearer dm_free_account123..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-platform.com/webhook",
    "events": ["message.received"]
  }'

View billing & upgrade

curl -X GET https://api.daimon.email/v1/account \
  -H "Authorization: Bearer dm_free_account123..."

Access any inbox's messages

curl -X GET https://api.daimon.email/v1/inboxes/{inbox_id}/messages \
  -H "Authorization: Bearer dm_free_account123..."

When to Use

Use the account API key in your platform backend for:

  • Provisioning new inboxes for agents/users
  • Monitoring all activity across inboxes
  • Setting up webhooks for multiple inboxes
  • Managing billing and upgrades
  • Administrative operations

Warning

Never expose the account API key to agents or end users. It grants full access to your entire account, including billing and all inboxes.

Inbox API Key

The inbox API key is scoped to a single inbox — it can only access that inbox's messages, threads, and settings.

What It Can Do

List messages in this inbox

curl -X GET https://api.daimon.email/v1/inboxes/{inbox_id}/messages \
  -H "Authorization: Bearer dm_free_inbox456..."

Send emails from this inbox

curl -X POST https://api.daimon.email/v1/inboxes/{inbox_id}/send \
  -H "Authorization: Bearer dm_free_inbox456..." \
  -H "Content-Type: application/json" \
  -d '{
    "to": "recipient@example.com",
    "subject": "Hello",
    "body": "Message from agent"
  }'

Get inbox details

curl -X GET https://api.daimon.email/v1/inboxes/{inbox_id} \
  -H "Authorization: Bearer dm_free_inbox456..."

Update inbox settings

curl -X PATCH https://api.daimon.email/v1/inboxes/{inbox_id} \
  -H "Authorization: Bearer dm_free_inbox456..." \
  -H "Content-Type: application/json" \
  -d '{"display_name": "Research Agent"}'

What It Cannot Do

An inbox API key cannot:

  • Create new inboxes
  • List other inboxes
  • Access messages from other inboxes
  • Manage webhooks
  • View or modify billing
  • Delete the account

Info

If an inbox API key is compromised, only that single inbox is affected. The blast radius is limited to one inbox's data.

When to Use

Use inbox API keys for:

  • Distributing to AI agents via environment variables
  • Granting access to specific inboxes without exposing the whole account
  • Building agent-specific dashboards
  • Limiting permissions for third-party integrations

Key Lifecycle

Getting the Account API Key

The account API key is returned only once when you create your first inbox:

import { DaimonClient } from 'daimon-email';

const client = new DaimonClient();

const result = await client.inboxes.create({
  username: 'platform-admin',
  clientId: 'bootstrap-001'
});

// This is the ONLY time you'll see the account API key
const accountApiKey = result.accountApiKey;

// Store it securely (AWS Secrets Manager, Vault, etc.)
await secretsManager.store('daimon-account-key', accountApiKey);
from daimon_email import DaimonClient

client = DaimonClient()

result = client.inboxes.create(
    username='platform-admin',
    client_id='bootstrap-001'
)

# This is the ONLY time you'll see the account API key
account_api_key = result.account_api_key

# Store it securely (AWS Secrets Manager, Vault, etc.)
secrets_manager.store('daimon-account-key', account_api_key)

Warning

If you lose the account API key, you must contact support@daimon.email for recovery. There is no self-service recovery mechanism.

Getting Inbox API Keys

Every inbox creation returns an inbox API key:

const client = new DaimonClient({
  apiKey: accountApiKey // Use account key to create inboxes
});

const inbox = await client.inboxes.create({
  username: 'research-agent',
  clientId: 'agent-001'
});

// Each inbox gets its own scoped key
const inboxApiKey = inbox.inboxApiKey;

// Distribute to the agent
await agent.configure({
  DAIMON_API_KEY: inboxApiKey,
  DAIMON_INBOX_ID: inbox.id
});
client = DaimonClient(api_key=account_api_key)

inbox = client.inboxes.create(
    username='research-agent',
    client_id='agent-001'
)

# Each inbox gets its own scoped key
inbox_api_key = inbox.inbox_api_key

# Distribute to the agent
agent.configure(
    DAIMON_API_KEY=inbox_api_key,
    DAIMON_INBOX_ID=inbox.id
)

Key Rotation

Rotating an Inbox API Key

If an inbox API key is compromised, rotate it via the account API key:

curl -X POST https://api.daimon.email/v1/inboxes/{inbox_id}/rotate-key \
  -H "Authorization: Bearer dm_free_account123..."

Response

{
  "result": {
    "inbox_id": "inbox_abc123",
    "new_inbox_api_key": "dm_free_newinboxkey789...",
    "old_key_revoked_at": "2026-03-16T10:45:00Z"
  },
  "next_steps": [
    "Update your agent's environment with the new key",
    "Old key is immediately revoked and cannot be used"
  ]
}

Rotating the Account API Key

If the account API key is compromised, contact support@daimon.email immediately. Account key rotation requires manual verification to prevent account takeover.

Best Practices

Store Securely

  • Use secrets manager (AWS, HashiCorp Vault, etc.)
  • Never commit keys to git
  • Never log keys in plaintext
  • Use environment variables for runtime access

Principle of Least Privilege

  • Give agents inbox keys, not account keys
  • Use account key only in backend services
  • Rotate keys regularly (quarterly)
  • Monitor key usage for anomalies

Key Mapping

  • Maintain a mapping: agent_id → inbox_id → inbox_api_key
  • Track which agents use which keys
  • Audit access logs regularly
  • Revoke keys when agents are decommissioned

Incident Response

  • If inbox key compromised: rotate via API
  • If account key compromised: contact support immediately
  • Review audit logs for unauthorized access
  • Update all affected services with new keys

Common Patterns

Pattern: Multi-Agent Platform

class AgentProvisioner {
  constructor(private accountApiKey: string) {}

  async createAgent(agentSlug: string): Promise<AgentConfig> {
    // Use account key to create inbox
    const client = new DaimonClient({ apiKey: this.accountApiKey });

    const inbox = await client.inboxes.create({
      username: agentSlug,
      clientId: `agent-${agentSlug}`
    });

    // Store inbox key in agent's config
    return {
      agentId: agentSlug,
      email: inbox.email,
      apiKey: inbox.inboxApiKey, // Scoped key for this agent
      inboxId: inbox.id
    };
  }

  async rotateAgentKey(inboxId: string): Promise<string> {
    // Use account key to rotate inbox key
    const client = new DaimonClient({ apiKey: this.accountApiKey });

    const result = await client.inboxes.rotateKey(inboxId);

    return result.newInboxApiKey;
  }
}

Pattern: Agent Self-Service

class AgentEmail {
  constructor(
    private inboxId: string,
    private inboxApiKey: string // Agent only has its own inbox key
  ) {}

  async checkMessages(): Promise<Message[]> {
    // Agent uses its scoped key
    const client = new DaimonClient({ apiKey: this.inboxApiKey });

    const messages = await client.inboxes.messages.list(this.inboxId);

    return messages.result;
  }

  async sendEmail(to: string, subject: string, body: string) {
    // Agent uses its scoped key
    const client = new DaimonClient({ apiKey: this.inboxApiKey });

    try {
      await client.inboxes.send(this.inboxId, { to, subject, body });
    } catch (error) {
      if (error.code === 'SEND_REQUIRES_PAID') {
        // Agent can request upgrade from operator
        console.log(error.upgradeContext.agentScript);
      }
    }
  }

  // Agent CANNOT create new inboxes or access other inboxes
}

Debugging Key Issues

Issue: "Unauthorized" Error

{
  "error": "UNAUTHORIZED",
  "message": "Invalid or expired API key"
}

Check:

  1. Is the key format correct? (dm_free_* or dm_live_*)
  2. Is the key in the Authorization: Bearer {key} header?
  3. Has the key been revoked or rotated?
  4. Are you using the right key type (account vs inbox)?

Issue: "Forbidden" Error

{
  "error": "FORBIDDEN",
  "message": "This API key cannot perform this action"
}

Check:

  1. Are you using an inbox key for account-level operations?
  2. Are you trying to access a different inbox with an inbox-scoped key?
  3. Is your account tier too low for this feature?

Issue: Lost Account API Key

If you lost the account API key:

  1. Email support@daimon.email with:
    • Your account email
    • One of your inbox IDs
    • Proof of ownership (domain verification, webhook callback, etc.)
  2. Support will verify your identity and issue a new account API key
  3. Old account key is immediately revoked

Warning

Account key recovery requires manual verification. This process can take 1-2 business days. Store your account key securely to avoid downtime.

Next Steps