Organizations and tenancy
Understand how a Samva credential binds to an organization, why every record is tenant-scoped, and how teams and usage share that boundary.
Every request to Samva's email API answers two questions before anything else happens: who is asking, and whose data are they allowed to touch. A credential answers the first. Tenancy answers the second. This page explains how the two meet in the organization. For key formats, headers, permissions, and OAuth sign-in, see the Authentication reference.
The organization is the unit of tenancy
Samva's tenant is the organization. An organization owns everything: verified domains, senders, contacts, conversations, messages, templates, webhooks, and the API keys themselves. When you sign up, you get an organization; when you invite teammates, they join your organization; when you send an email, it is recorded against your organization.
Every record belongs to one organization, and every read is limited to it. There is no request shape that crosses the boundary. A key issued to one organization cannot list another organization's contacts, fetch its messages, or send from its domain. The organization comes from your credential rather than from anything in the request body, so there is no field in which to ask for the wrong tenant's data.
A verified domain is an organization-level asset for the same reason. Authenticating a sending domain, covered in Verify your domain, is done once per organization, and from then on every key in that organization can send from it. The trust you build attaches to the tenant, not to an individual credential.
The organization avatar
An organization has one avatar. It is the image the organization switcher shows next to the
organization's name, and a generated glyph stands in until you set one. Owners and admins set it in
the dashboard under Settings → Organization → Basic information: choose Upload avatar,
frame the square crop, and save. Remove returns the switcher to the glyph. Samva stores a square
copy of the image you upload. The upload target below reports the size
limit as maxBytes and the accepted types as contentTypes.
The avatar belongs to the organization itself. The logo and icon your emails carry belong to a brand, and changing one never changes the other.
From the CLI, samva org avatar set <file> uploads a PNG, JPEG, or WebP image and saves it, and
samva org avatar clear removes it:
samva org avatar set avatar.pngA key with permission to update the organization sets it through the API in three calls. The first returns where to upload, the second sends the image bytes there, and the third saves the address that comes back:
import { readFile } from "node:fs/promises";
import { createClient } from "samva";
const apiKey = process.env.SAMVA_API_KEY!;
const samva = createClient({ apiKey });
const { uploadUrl } = await samva.organizations.createAvatarUpload();
const upload = await fetch(uploadUrl, {
method: "PUT",
headers: { "X-API-Key": apiKey, "Content-Type": "image/png" },
body: await readFile("avatar.png"),
});
const { src } = (await upload.json()) as { src: string };
await samva.organizations.update({ avatarUrl: src });The same three calls with curl:
UPLOAD_URL=$(curl -s -X POST https://api.samva.dev/v1/organizations/current/avatar-upload \
-H "X-API-Key: $SAMVA_API_KEY" | jq -r .uploadUrl)
SRC=$(curl -s -X PUT "$UPLOAD_URL" \
-H "X-API-Key: $SAMVA_API_KEY" \
-H "Content-Type: image/png" \
--data-binary @avatar.png | jq -r .src)
curl -X PATCH https://api.samva.dev/v1/organizations/current \
-H "X-API-Key: $SAMVA_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"avatarUrl\": \"$SRC\"}"PATCH /v1/organizations/current accepts only an address returned by an avatar upload, and answers
422 with a ValidationError on avatarUrl for any other value. Send { "avatarUrl": null } to
remove the avatar. See Get the organization avatar upload URL and
Update the current organization for the full shapes.
How a credential finds its organization
Samva's credentials differ in who is acting, and that decides how the organization is chosen.
An API key belongs to exactly one organization. Presenting it tells Samva both that the request is legitimate and whose data it may read or write, so key-authenticated calls never name an organization. That is what makes a key the right credential for a server: nothing about the request can point it somewhere else.
A CLI OAuth session belongs to your user, and a user can be a member of several organizations. The session therefore names its organization on every request, and Samva checks your membership before acting. Switching organizations is a local choice in the CLI, not a new login.
An MCP OAuth token belongs to your user but is bound, when you approve the connection, to one organization. An agent holding it cannot switch organizations, which keeps a connected agent inside the tenant you granted.
Teams and roles
Because the organization owns the data and the credentials, it is also where collaboration lives. You invite teammates into an organization by email address and assign each one a role. Each person then authenticates as themselves rather than borrowing anyone else's credential.
Roles exist for least privilege: a teammate who only needs to read delivery activity should not also be able to rotate the API keys production depends on. The same instinct applies to keys: a key never holds more than its owner's current role, and a restricted key holds only the resources you grant it. Roles and their capabilities are managed in the dashboard.
Usage is organization-scoped
Usage follows the same boundary. Every send your organization makes counts against the organization's allowance, not against the key that made it, so adding keys neither adds capacity nor fragments spend. When an organization reaches a limit, the API refuses the request rather than silently sending; Sending limits states the limits.
Where to go next
Related resources
- Build with the Samva API
See the developer overview, SDK, and path from credentials to a first email.
Related documentation
Email and the messages API
Understand why Samva exposes both an email send facade and a messages API, and how each fits your integration.
Namespaces
Give each of your customers a namespace with its own domains, contacts, and templates, a key that reaches only that namespace, and usage readback to bill from.