API keys

Reference API key formats, the X-API-Key header, rate limits, and authentication errors for Samva's email API.

Samva authenticates email API requests with an API key sent in the X-API-Key header. This page documents key format, request authentication, rate limiting, and authentication errors. For the model behind keys, how one binds to an organization and scopes every request, see Organizations and tenancy.

API key format

Production keys start with samva_sk_live_; keys minted outside production start with samva_sk_test_. Each key authenticates requests for the organization it belongs to.

Using API keys

Include the key in the X-API-Key header on every request.

The SDK reads the key from the apiKey option and sets the header for you.

import { createClient } from "samva";

const samva = createClient({ apiKey: process.env.SAMVA_API_KEY! });

Store keys in environment variables, never in source. The full key value is shown only once at creation time.

Key handling

PracticeDetail
Use environment variablesRead the key from the environment; never hardcode it in source.
Scope permissionsSet the minimum permissions required when creating a key.
Rotate keysReplace keys periodically and after any suspected exposure.
Monitor usageTrack per-key usage in the Samva Dashboard.

Permissions

Every endpoint declares one resource:action permission, and a key is refused when its grants do not cover it. The required permission is published on each operation in the OpenAPI document as x-samva-scope, so you can read it per endpoint in the API reference.

ResourceActionsCovers
messagescreate, read, update, deleteSends, scheduled sends, campaigns, drafts, media
emailsend, readBlocks, tracking policy, statistics, delivery logs
domainscreate, read, update, deleteSending domains, senders, branded tracking, catch-all, forwarding rules
contactscreate, read, update, deleteContacts, groups, custom fields, unsubscribe groups
conversationscreate, read, update, deleteConversations and their participants
templatescreate, read, update, deleteTemplates, families, presets, fonts, design settings
webhookscreate, read, update, deleteEndpoints, deliveries, secrets
apiKeyscreate, read, update, delete, rotateKeys and their usage records
organizationread, update, deleteWorkspace record, settings, usage
analyticsreadAggregate messaging statistics and exports
billingread, updateOverage settings
memberinvite, remove, updateTeam membership

Sending and provisioning are deliberately separate. email is traffic: it sends mail and reads what happened to it. What the mail is sent from is domains, with its own lifecycle: your sending domains and senders, their DNS and branded tracking, catch-all, and forwarding. A key scoped to send cannot delete the domain it sends from, so a compromised send key cannot take your sending identity with it.

The action follows the method unless the endpoint says otherwise: GET reads, POST creates, PATCH and PUT update, DELETE deletes. A resource that has no such action uses its nearest one, so an email mutation such as adding a block requires email:send. Endpoints that read through a POST body, such as POST /v1/contacts/find, require the read action instead. An endpoint whose method overstates it says so: POST /v1/email/domains/{id}/default requires domains:update, not domains:create, because it changes a domain rather than adding one.

A few endpoints require more than one permission, published space-separated. POST /v1/contacts/bulk-import requires contacts:create contacts:update, because upsertByEmail overwrites contacts that already exist.

Key lifecycle

Keys are created and managed under Developers → API Keys in the Samva Dashboard. Each key carries a set of permissions and an optional expiry, both set at creation. The full key value is returned only at creation time and is not retrievable afterward; a lost key must be replaced. Keys can be revoked at any time, and a revoked key stops authenticating immediately.

Rate limiting

Send throughput is limited per organization at a rate set by your plan. Every API key draws from that same allowance, first-come, so adding keys does not add throughput and a key sending continuously at the limit will throttle your other keys while it does. Each key carries its own burst cap, at half the organization's burst, so no single key can absorb your entire burst in one spike.

Requests authenticated with a session or an OAuth token draw on the organization limit only.

When a limit is exceeded, the request returns 429 Too Many Requests with a RateLimitedError body and a Retry-After header:

{
  "_tag": "RateLimitedError",
  "retryAfterSeconds": 1
}

Back off for at least retryAfterSeconds seconds before sending the request again. For the per-plan rates, the burst allowance, and the response headers, see Rate limiting in the REST API reference.

Authentication errors

Errors are returned as tagged JSON bodies. Each body carries a _tag identifying the error and a message describing it.

Status_tagDescriptionResolution
401UnauthorizedErrorInvalid or missing API keyCheck the X-API-Key header value
403ForbiddenErrorInsufficient permissionsUse a key with the required scope

Invalid or missing API key

Returned when the API key cannot be validated.

{
  "_tag": "UnauthorizedError",
  "message": "Invalid API key"
}

Insufficient permissions

Returned when the key is valid but its grants do not cover the endpoint's permission. The message names the exact resource:action the request needed.

{
  "_tag": "ForbiddenError",
  "message": "Caller requires contacts:create permission"
}

These are the authentication-specific errors. For the full list the API can return, with each error's fields and how to resolve it, see the Error reference.

On this page