AgentPost
Best Practices

Environment Isolation

How to use environments for dev/staging/prod separation, per-customer isolation, and per-agent workflows

Environment Isolation

Environments in AgentPost provide resource isolation within an organization. Every inbox, domain, webhook endpoint, and other resource belongs to exactly one environment. This enables clean separation between development and production, between customers, or between different AI agents.

Why Environments Exist

Without environments, all resources in an organization share a single flat namespace. This creates problems:

  • Testing risk: A test script accidentally sends to real customers
  • Data leakage: Development data appears alongside production data
  • Access control: All team members see all resources regardless of their role
  • Agent isolation: Multiple AI agents interfere with each other's inboxes

Environments solve these problems by creating logical partitions within your organization.

Use Cases

Development / Staging / Production

The most common pattern is separating deployment stages:

import AgentPost from '@agentpost/sdk';

// Development environment
const devClient = new AgentPost({
  apiKey: 'ap_sk_dev_your_dev_key',
  environment: 'env_01JQ_development',
});

// Create test inboxes freely
const testInbox = await devClient.inboxes.create({
  email: 'test-support@dev.agent-post.dev',
  name: 'Test Support Inbox',
});

// Production environment
const prodClient = new AgentPost({
  apiKey: 'ap_sk_live_your_prod_key',
  environment: 'env_01JQ_production',
});

// Production inboxes are isolated from dev
const prodInbox = await prodClient.inboxes.create({
  email: 'support@acmeco.com',
  name: 'Customer Support',
});
from agentpost import AgentPost

# Development environment
dev_client = AgentPost(
    api_key="ap_sk_dev_your_dev_key",
    environment="env_01JQ_development",
)

# Create test inboxes freely
test_inbox = dev_client.inboxes.create(
    email="test-support@dev.agent-post.dev",
    name="Test Support Inbox",
)

# Production environment
prod_client = AgentPost(
    api_key="ap_sk_live_your_prod_key",
    environment="env_01JQ_production",
)

# Production inboxes are isolated from dev
prod_inbox = prod_client.inboxes.create(
    email="support@acmeco.com",
    name="Customer Support",
)
# Development environment -- use the dev environment's API key
curl -X POST https://api.agent-post.dev/api/v1/environments/env_01JQ_development/inboxes \
  -H "Authorization: Bearer ap_sk_dev_your_dev_key" \
  -H "Content-Type: application/json" \
  -d '{"email": "test@dev.agent-post.dev", "name": "Test Inbox"}'

# Production environment -- separate key, separate resources
curl -X POST https://api.agent-post.dev/api/v1/environments/env_01JQ_production/inboxes \
  -H "Authorization: Bearer ap_sk_live_your_prod_key" \
  -H "Content-Type: application/json" \
  -d '{"email": "support@acmeco.com", "name": "Support Inbox"}'

Per-Customer Isolation

If you're building a platform where multiple customers each get their own email infrastructure, create an environment per customer:

// When onboarding a new customer
async function onboardCustomer(customerId: string, customerName: string) {
  const env = await client.environments.create({
    name: `customer-${customerId}`,
    description: `Email environment for ${customerName}`,
  });

  // Create customer-specific inbox
  const inbox = await client.inboxes.create({
    email: `support@${customerId}.agent-post.dev`,
    name: `${customerName} Support`,
    environment_id: env.id,
  });

  // Set up webhooks scoped to this environment
  await client.webhookEndpoints.create({
    url: `https://your-app.com/webhooks/${customerId}`,
    events: ['message.received'],
    environment_id: env.id,
  });

  return { environment: env, inbox };
}

This pattern ensures:

  • Customer A cannot access Customer B's emails
  • Webhook endpoints are scoped to the right customer
  • Each customer's usage can be tracked independently

Per-Agent Isolation

When running multiple AI agents, each with its own purpose, isolate them in separate environments:

// Billing agent environment
const billingEnv = await client.environments.create({
  name: 'agent-billing',
  description: 'Billing inquiry AI agent',
});

// Support agent environment
const supportEnv = await client.environments.create({
  name: 'agent-support',
  description: 'Technical support AI agent',
});

// Sales agent environment
const salesEnv = await client.environments.create({
  name: 'agent-sales',
  description: 'Sales outreach AI agent',
});

Each agent operates in its own sandbox. A bug in the billing agent cannot affect the support agent's inboxes.

Resource Scoping

When an environment is specified, all resource operations are scoped to that environment:

ResourceScoped?Behavior
InboxesYesOnly inboxes in the environment are visible
MessagesYesOnly messages from inboxes in the environment
ThreadsYesOnly threads from inboxes in the environment
DomainsYesOnly domains assigned to the environment
Webhook endpointsYesOnly endpoints scoped to the environment
DraftsYesOnly drafts for inboxes in the environment
LabelsYesOnly labels on messages/threads in the environment
API keysPartialKeys can be scoped to specific environments

Environment Access Control

Control which team members can access each environment:

// Assign a member to the production environment
await client.environments.addMember('env_01JQ_production', {
  member_id: 'mem_01JQ8X5K',
  role: 'admin', // or 'member'
});

// Create an API key scoped to a specific environment
const key = await client.apiKeys.create({
  name: 'Production Agent Key',
  scopes: ['inboxes:read', 'inboxes:write', 'messages:read', 'messages:write'],
  environment_ids: ['env_01JQ_production'],
});
# Assign a member to the production environment
client.environments.add_member(
    "env_01JQ_production",
    member_id="mem_01JQ8X5K",
    role="admin",
)

# Create an API key scoped to a specific environment
key = client.api_keys.create(
    name="Production Agent Key",
    scopes=["inboxes:read", "inboxes:write", "messages:read", "messages:write"],
    environment_ids=["env_01JQ_production"],
)
# Assign a member to the production environment
curl -X POST https://api.agent-post.dev/api/v1/environments/env_01JQ_production/members \
  -H "Authorization: Bearer ap_sk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"member_id": "mem_01JQ8X5K", "role": "admin"}'

# Create an API key scoped to a specific environment
curl -X POST https://api.agent-post.dev/api/v1/api-keys \
  -H "Authorization: Bearer ap_sk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Production Agent Key",
    "scopes": ["inboxes:read", "inboxes:write", "messages:read", "messages:write"],
    "environment_ids": ["env_01JQ_production"]
  }'

Best Practices

Naming Conventions

Use consistent, descriptive names for environments:

PatternExample NamesWhen to Use
Stage-baseddevelopment, staging, productionStandard dev workflow
Customer-basedcustomer-acmeco, customer-globexMulti-tenant platforms
Agent-basedagent-support, agent-billingMulti-agent systems
Combinedprod-support-agent, dev-billingComplex deployments

Default Environment

Every organization has a default environment. Resources created without specifying an environment are placed in the default environment. For simple setups with a single environment, you can use the default without managing environments explicitly.

Environment Structure Guidelines

  • Keep it simple: Start with development and production. Add more only when needed.
  • Don't over-segment: Each environment has its own set of inboxes, domains, and webhooks. Too many environments increase management overhead.
  • Use environment-scoped API keys: Never use an organization-wide API key in production code. Scope keys to the minimum required environments.
  • Match your deployment pipeline: If you have CI/CD stages, create matching environments (dev, staging, production).
  • Document your structure: Maintain a simple map of which environments exist and what they're used for.

On this page