Authentication
Every request carries one header:
Authorization: Bearer tix_live_...
There is no other authentication mechanism on the API. Keys are created in the dashboard
under API Keys & SMTP, or through the API itself with a key holding api-keys:manage.
Reading a key
The prefix tells you which environment a key belongs to.
| Prefix | Meaning |
|---|---|
tix_live_ | Sends real mail and consumes quota |
tix_test_ | Simulated only, see Test mode |
The prefix is checked against the key, so a live secret presented with a test prefix is
rejected with authentication_failed. You cannot make a key
behave differently by editing its prefix.
Scopes
A key grants only what it was created with. A request to a route the key does not cover
returns insufficient_scope naming the scope it needed.
| Scope | Grants |
|---|---|
sending | Submit, cancel, resend and pre-flight messages, and upload attachments |
emails:read | Read messages and their events |
domains:manage | Add, verify, configure and remove sending domains |
contacts:manage | Read and write contacts and tags |
webhooks:manage | Create and edit webhook endpoints, read and replay deliveries |
suppressions:read | Read the suppression list |
suppressions:manage | Add and remove suppressions, and read them |
analytics:read | Read aggregate reporting |
* | Everything, including scopes added later |
*:manage includes the matching *:read, so a key with suppressions:manage can also list
suppressions.
api-keys:manage is the one to think twice about. A key holding it can mint further keys, so
it is not a limited key at all. Give it only to something that genuinely provisions
credentials.
Domain scoping
Three scopes can be narrowed to particular domains: sending, emails:read and
domains:manage. A key scoped that way can send from those domains and no others, which is
how you give a subsystem the ability to send transactional mail without also letting it send
as your marketing domain.
A request outside the allowed set returns
domain_scope_restricted.
IP allow-lists
A key can be limited to a set of CIDR ranges. Requests from anywhere else are rejected with
api_key_ip_restricted, which turns a stolen token into a
much smaller problem.
Leave the list empty and the key works from anywhere. Only set it when your sender's egress address is genuinely stable, because a cloud provider rotating your NAT address will take your sending down.
Expiry
Every key has an expiry date and there is no way to create one without. This is deliberate: a credential nobody ever rotates is one nobody ever notices has leaked.
An expired key returns api_key_expired rather than a generic
authentication failure, so it is obvious from the response what happened.
Rotate in this order: create the replacement, deploy it, confirm it is being used from its request count, then delete the old one. Deleting first means an outage that lasts as long as your deploy.
If a key leaks
Delete it. There is no rotation and no grace period, because a leaked key is valid until it stops existing. A key that has ever been in a repository, a build log or a support ticket should be treated as public.