Agents, people, and keys
Decide who can read, send, and administer a mailbox, and confine agents with mailbox-scoped keys and namespaces.
Every action on a mailbox is taken by a principal, and Samva records which one. A principal is a person with a grant, a mailbox-scoped key, or an installed extension. Each principal reaches only the mailboxes you give it, and none can do more than the person behind it.
People and grants
A grant shares one mailbox with one organization member. It carries a role and a send mode. The
person who creates a mailbox receives an admin grant.
| Role | Reads the mailbox | Edits threads, labels, drafts, and notes | Sends and replies | Approves sends, reads and releases quarantine, configures the mailbox |
|---|---|---|---|---|
viewer | Yes | No | No | No |
collaborator | Yes | Yes | Yes | No |
admin | Yes | Yes | Yes | Yes |
The send mode is send or approval; it defaults to send. With approval, each of the person's
sends waits for a different person. See Approve sends.
Managing grants needs admin. Grant a member access with POST /v1/mailboxes/{id}/grants:
import { createClient } from "samva";
const samva = createClient({ apiKey: process.env.SAMVA_API_KEY! });
const grant = await samva.mailboxes.createGrant({
id: "mbx_...",
userId: "user_...",
role: "collaborator",
sendMode: "approval",
});curl -X POST https://api.samva.dev/v1/mailboxes/$MAILBOX_ID/grants \
-H "X-API-Key: $SAMVA_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "userId": "user_...", "role": "collaborator", "sendMode": "approval" }'The member must already belong to the organization; anyone else is a validation error. Granting
someone who already holds a grant is a 409, so granting never widens access by accident. Change an
existing grant instead:
await samva.mailboxes.updateGrant({
id: "mbx_...",
grantId: grant.id,
role: "admin",
sendMode: "send",
});PATCH /v1/mailboxes/{id}/grants/{grantId} takes role, sendMode, or both, and keeps any
field you leave out. Naming neither is a validation error. The change applies to the person's next
request on every surface. DELETE on the same path revokes the grant.
A mailbox always keeps at least one admin. Revoking the last one, or changing its role, is a 409:
hand the mailbox to a teammate first.
Mailbox-scoped keys
An agent should not hold a key that reaches your whole organization. Create a restricted key with
mailboxes access instead. The key acts as itself, named by the key's name, so every message it
sends and every thread it changes is attributed to that key. A full-access key has no identity of its
own: it acts as its owner.
const key = await samva.apiKeys.create({
name: "Support agent",
access: {
mode: "restricted",
resources: {},
mailboxes: {
permissions: ["read", "send"],
mailboxIds: ["mbx_..."],
sendMode: "send",
},
},
});| Field | Meaning |
|---|---|
permissions | One or more of read, update, send, quarantine.read. |
mailboxIds | The mailboxes the key may act on. Omit it to reach every mailbox its owner reaches. |
sendMode | send (the default) or approval. |
namespaceId | On access, confines the key to one namespace. |
| Permission | Lets the key |
|---|---|
read | Read mailboxes, threads, messages, attachments, and the mailbox's actions, events, and policies. |
update | Change thread state, labels, drafts, and notes. |
send | Send, reply, reply to all, forward, and send drafts. |
quarantine.read | List held messages as metadata. |
A key is capped by the member who owns it. It reaches only mailboxes that member reaches, with at most
that member's current role, and it stops working if the member leaves the organization. A restricted
key with mailboxes access cannot create, configure, pause, or delete a mailbox or manage grants;
a full-access key acts as its owner and can, which is why setup uses one. No key, full-access or
restricted, can approve or deny a send or release or discard held mail: those need a person signed
in. A key scoped to listed mailboxes or a namespace holds mailbox access only.
Revoke a key with DELETE /v1/api-keys/{id}. It stops authenticating at once, on every surface, and
the mail it handled keeps its attribution. Deleting a mailbox removes it from every key scope and
webhook filter that named it, and a key or endpoint left with no mailbox is disabled.
Change a key's send mode
Switching an agent between sending directly and sending for approval does not need a new key. A person
sets the key's mailboxes.sendMode with PATCH /v1/api-keys/{id}:
await samva.apiKeys.update({
id: "key_...",
mailboxes: { sendMode: "approval" },
});Only a person can change it, and only on a key that holds mailbox access. The change applies to the key's next request.
Namespaces
A namespace is a sub-tenant inside your organization. Use one per customer when you resell mailboxes
or run agents on behalf of customers. A mailbox belongs to a namespace when you create it with
namespaceId, and a key created with access.namespaceId reaches only that namespace's mailboxes, so
one customer's agent can never read another's mail. Webhook endpoints take the same namespaceId
filter.
curl -X POST https://api.samva.dev/v1/namespaces \
-H "X-API-Key: $SAMVA_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Acme Corp", "metadata": { "customerId": "cus_123" } }'Names are unique within the organization. metadata is yours: Samva stores it and never reads it. A
namespace that still holds mailboxes or keys cannot be deleted; remove or move them first.