A namespace is a named container for inboxes. It lets you group and isolate inboxes by any boundary that makes sense for your application: a customer account, a customer organization, a project, a team, a workspace or an AI agent.
Without namespaces, all inboxes share the same flat list. For simple setups, a few inboxes for one team, that is fine. Once you have multiple customers, tenants, or agents each needing their own inboxes, namespaces become the organizing layer that keeps everything separated and queryable.
When to use namespaces
Use namespaces when you need to:
- Isolate inboxes by tenant. Each customer or account gets their own namespace, so queries are naturally scoped and there is no risk of data leaking between tenants.
- Group inboxes by team or function. A sales namespace, a support namespace, an operations namespace, each with its own set of addresses.
- Manage AI agent inboxes independently. An agent with multiple inboxes (for example, one per customer it serves) benefits from a dedicated namespace to track and query its state.
You do not need namespaces for a single-team setup with a small number of inboxes.
The externalId field
Every namespace has an optional externalId field. Use it to store your own internal identifier, a tenant ID, an account UUID, a customer slug, directly on the namespace.
This eliminates the need for a separate mapping table. When a webhook event arrives or when you need to scope a query to a specific tenant, look up the namespace by externalId and filter from there.
Common patterns
Per-customer inboxes in a SaaS product
Each account in your product gets a namespace. Within that namespace, you create whatever inboxes that account needs: support@, billing@, notifications@. When a customer is deleted or suspended, you can disable the entire namespace in one call.
Because namespaces carry your externalId, a single API call is all it takes to go from “I have a tenant ID” to “here are all the inboxes and messages for that tenant”.
Per-client inboxes in an agency
An agency managing email for multiple clients creates one namespace per client. Each namespace gets a set of inboxes matched to that client’s domain and workflow. The agency’s internal system maps client IDs to namespace IDs via externalId and scopes all queries accordingly.
AI agent namespaces
An AI agent platform can give each agent, or each agent instance, its own namespace. The agent’s inboxes live inside that namespace, keeping its activity isolated from other agents. The agent state API can then be queried scoped to specific inboxes and threads within the namespace.
Create a namespace
import { Nuntly } from '@nuntly/sdk';
const nuntly = new Nuntly({
apiKey: process.env.NUNTLY_API_KEY,
});
const namespace = await nuntly.namespaces.create({
name: 'Acme Corp',
externalId: 'tenant_12345',
});
console.log('Namespace ID:', namespace.data.id);
Create request fields
| Field | Required | Description |
|---|
name | Yes | The display name of the namespace. Maximum 255 characters. |
externalId | No | An external identifier for mapping to your internal systems. Maximum 255 characters. |
List namespaces
// List all namespaces
const namespaces = await nuntly.namespaces.list();
// Filter by status
const activeNamespaces = await nuntly.namespaces.list({
status: 'active',
});
Retrieve a namespace
Retrieve a single namespace with inbox statistics.
const namespace = await nuntly.namespaces.retrieve('ns_01kabn43yqyxn2bx4ve84mczd3');
console.log('Name:', namespace.data.name);
console.log('External ID:', namespace.data.externalId);
console.log('Total inboxes:', namespace.data.totalInboxes);
console.log('Active inboxes:', namespace.data.activeInboxes);
Update a namespace
await nuntly.namespaces.update('ns_01kabn43yqyxn2bx4ve84mczd3', {
name: 'Acme Corp (Updated)',
externalId: 'tenant_67890',
status: 'active',
});
Update request fields
| Field | Description |
|---|
name | The display name. Maximum 255 characters. |
externalId | The external identifier. Set to null to clear. |
status | Set to active or disabled. |
Delete a namespace
Deleting a namespace is a soft delete. You cannot delete a namespace that still has active inboxes. Move or delete the inboxes first.
await nuntly.namespaces.delete('ns_01kabn43yqyxn2bx4ve84mczd3');
Deleting a namespace with active inboxes will fail. Remove or reassign all inboxes in the namespace before deleting it.
List inboxes in a namespace
Retrieve the inboxes that belong to a specific namespace.
const inboxes = await nuntly.namespaces.listInboxes('ns_01kabn43yqyxn2bx4ve84mczd3');
for (const inbox of inboxes.data) {
console.log(`${inbox.address}@${inbox.domainName}`);
}
Multi-tenant provisioning example
A common pattern is to create a namespace when a new tenant signs up, using externalId to map between your tenant IDs and Nuntly namespaces.
import { Nuntly } from '@nuntly/sdk';
const nuntly = new Nuntly({
apiKey: process.env.NUNTLY_API_KEY,
});
// When a new tenant signs up, provision their namespace and inboxes
async function provisionTenant(tenant: { id: string; companyName: string }) {
const namespace = await nuntly.namespaces.create({
name: tenant.companyName,
externalId: tenant.id,
});
// Create standard inboxes for this tenant
await Promise.all([
nuntly.inboxes.create({
domainId: process.env.DOMAIN_ID,
address: `support-${tenant.id}`,
name: `${tenant.companyName} Support`,
namespaceId: namespace.data.id,
}),
nuntly.inboxes.create({
domainId: process.env.DOMAIN_ID,
address: `billing-${tenant.id}`,
name: `${tenant.companyName} Billing`,
namespaceId: namespace.data.id,
}),
]);
return namespace.data.id;
}
// Later, look up inboxes for a tenant using only your internal ID
async function getInboxesForTenant(tenantId: string) {
const namespaces = await nuntly.namespaces.list();
const namespace = namespaces.data.find((ns) => ns.externalId === tenantId);
if (!namespace) return [];
return nuntly.namespaces.listInboxes(namespace.id);
}
Next steps