Skip to navigation

Руководство: мультитенантность

Поды, ограниченные ключи и маршрутизация событий для ваших клиентов.

Если вы строите платформу, где у каждого клиента должна быть своя почтовая инфраструктура, схема такая: один Pod на клиента, выданный ему ограниченный API-ключ и вебхуки, направленные в нужный endpoint.

Pod = изоляция тенанта

У каждого тенанта свой Pod. Все ресурсы (ящики, домены, цепочки, черновики) живут внутри него и изолированы от других подов. Подробности — на странице Поды.

from agentinbox import Agentinbox
client = Agentinbox()
# Use client_id to map to your internal tenant ID so
# you don't need to maintain a separate mapping table
pod = client.pods.create(client_id="tenant-acme-123")

Дальше создаёте ресурсы клиента:

inbox = client.pods.inboxes.create(
pod.pod_id,
username="support",
display_name="Acme Support"
)
domain = client.pods.domains.create(pod.pod_id, domain="acme.com")

API-ключи с областью действия

По умолчанию ключи на уровне организации видят всё во всех подах. Ограниченные (scoped) ключи привязаны к одному поду или одному ящику: ключ для пода Acme трогает только ресурсы Acme.

Так можно выдать ключ сервису или агенту клиента, не открывая всю организацию.

Ключи на уровне пода

Доступ ко всем ресурсам пода (ящики, цепочки, черновики, домены).

# Create a key that can only access Acme's pod
scoped_key = client.pods.api_keys.create(
pod.pod_id,
name="acme-service-key"
)
# This is the only time you'll see the full key, so store it
print(scoped_key.api_key)

Ключи на уровне ящика

Ещё уже: только один ящик и связанные с ним цепочки, сообщения и черновики. Подходит, когда агенту или интеграции нужен один адрес.

# Create a key that can only access the support inbox
inbox_key = client.inboxes.api_keys.create(
inbox.inbox_id,
name="support-inbox-key"
)
print(inbox_key.api_key)

Полный ключ возвращается один раз при создании. Потеряли — удалите ключ и создайте новый.

Список и удаление ограниченных ключей для пода или ящика:

# Pod-scoped keys
keys = client.pods.api_keys.list(pod.pod_id)
client.pods.api_keys.delete(pod.pod_id, scoped_key.api_key_id)
# Inbox-scoped keys
inbox_keys = client.inboxes.api_keys.list(inbox.inbox_id)
client.inboxes.api_keys.delete(inbox.inbox_id, inbox_key.api_key_id)

Маршрутизация вебхуков

Один endpoint на всех клиентов обычно не нужен. При создании Webhook можно ограничить область списком pod_ids или inbox_ids, чтобы события приходили только по нужным ресурсам.

# Only fires for events in Acme's pod
webhook = client.webhooks.create(
url="https://your-server.com/webhooks/acme",
event_types=["message.received", "message.sent"],
pod_ids=[pod.pod_id]
)
# Or narrow it down to specific inboxes
webhook = client.webhooks.create(
url="https://your-server.com/webhooks/acme-support",
event_types=["message.received"],
inbox_ids=[inbox.inbox_id]
)

Полный сценарий онбординга

Как выглядит подключение нового клиента от начала до конца:

from agentinbox import Agentinbox
client = Agentinbox()
def onboard_tenant(tenant_id: str, domain_name: str):
# Create isolated pod
pod = client.pods.create(client_id=tenant_id)
# Provision inbox + domain
inbox = client.pods.inboxes.create(
pod.pod_id,
username="support",
display_name=f"{tenant_id} Support"
)
domain = client.pods.domains.create(pod.pod_id, domain=domain_name)
# Pod-scoped key for the tenant
key = client.pods.api_keys.create(pod.pod_id, name=f"{tenant_id}-key")
# Inbox-scoped key for the support inbox
inbox_key = client.inboxes.api_keys.create(
inbox.inbox_id, name=f"{tenant_id}-support-key"
)
# Webhook for their events
webhook = client.webhooks.create(
url=f"https://your-server.com/webhooks/{tenant_id}",
event_types=["message.received"],
pod_ids=[pod.pod_id]
)
return {
"pod_id": pod.pod_id,
"inbox_id": inbox.inbox_id,
"pod_api_key": key.api_key, # deliver securely to tenant
"inbox_api_key": inbox_key.api_key,
"webhook_id": webhook.webhook_id,
}