Authentication

API keys, permission scopes, and domain-scoped keys for the emitd API.

Every route in the emitd API except GET /health authenticates with an API key passed as a Bearer token:

Authorization: Bearer esk_live_...

Create keys in the console under API keys. A key is shown in full exactly once at creation — emitd only ever stores a SHA-256 hash of it, so a leaked database never exposes a usable key.

Permission levels

Every key carries one of two scopes (email_core::KeyPermission):

  • full_access — read, send, and manage every resource: contacts, audiences, segments, broadcasts, automations, templates, webhooks, suppressions, messages, inbound.
  • sending_access — send email only (POST /v1/email, POST /v1/email/batch). Every other route responds 403 insufficient_scope.

Domain-scoped keys

A sending_access key may additionally be scoped to a single verified sending domain. Sends from any other domain fail with from_domain_not_verified. Domain-scoped keys are the right shape for a single service that should never be able to send as another brand:

Authorization: Bearer esk_live_...   # scoped to mail.acme.com only

Good practice

  • Keep keys in environment variables or a secrets manager, never in source control.
  • Use a separate key per service, so you can revoke one without downtime.
  • Revoking a key takes effect immediately — the next request with it gets 401 unauthorized.
  • Prefer sending_access for anything that only delivers mail.

A missing, malformed, or unknown key returns 401:

{ "error": "unauthorized" }

Never ship a key in client-side code

API keys are server-side credentials. A key in a browser bundle is a key in the wild — call emitd from your backend or a serverless function.

On this page