Skip to main content

Authentication

Test keys are being retired

zy_test_* keys are no longer issued, and existing ones stop working on 21 October 2026. They never delivered mail — sends were mocked and marked sent without reaching a provider, so they could not verify domain authentication, template rendering, or deliverability.

To test your integration, use a zy_live_* key against a verified domain and send to an address you control. That exercises the real delivery path.

All Zyphr API requests require authentication using an API key. You can create and manage API keys through the Dashboard or the API. This guide covers how to create and use API keys securely.

API Key Types​

Zyphr supports two types of API keys:

Key TypePrefixPurpose
Livezy_live_*Production use - messages are delivered
Testzy_test_*Development/testing - messages are stored but not delivered

Creating API Keys​

Via Dashboard​

  1. Navigate to API Keys in the sidebar
  2. Click Create API Key
  3. Enter a descriptive name (e.g., "Backend Server", "Development")
  4. Choose the mode (Live or Test)
  5. Select permission scopes (e.g., email:send, push:send, sms:send), or leave Full Access checked
  6. Optionally set an expiration date
  7. Click Create
  8. Copy your API key — you won't be able to see it again

Via API​

Create new API keys programmatically using an existing key or JWT session:

curl -X POST https://api.zyphr.dev/v1/api-keys \
-H "Authorization: Bearer YOUR_EXISTING_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "CI/CD Pipeline",
"mode": "live",
"scopes": ["email:send", "push:send"],
"expires_at": "2027-01-01T00:00:00Z"
}'
warning

Copy your API key immediately — the full key is only returned once at creation. If you lose it, you'll need to create a new one.

Using API Keys​

Include your API key in the X-API-Key header with every request:

curl -X POST https://api.zyphr.dev/v1/emails \
-H "X-API-Key: zy_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"to": "user@example.com", "subject": "Hello", "html": "<p>Hi!</p>"}'

With SDKs​

Node.js
import { Zyphr } from '@zyphr-dev/node-sdk';

const zyphr = new Zyphr({
apiKey: process.env.ZYPHR_API_KEY,
});
Python
from zyphr import Zyphr

zyphr = Zyphr(api_key=os.environ["ZYPHR_API_KEY"])

Managing API Keys​

Via Dashboard​

  1. Navigate to API Keys in the sidebar
  2. View all keys with their mode (Live/Test), status, scopes, and last used timestamp
  3. Revoke a key by clicking the Revoke button

Via API​

# List all API keys
curl https://api.zyphr.dev/v1/api-keys \
-H "Authorization: Bearer YOUR_API_KEY"

# Get a specific API key
curl https://api.zyphr.dev/v1/api-keys/KEY_ID \
-H "Authorization: Bearer YOUR_API_KEY"

# Revoke an API key
curl -X DELETE https://api.zyphr.dev/v1/api-keys/KEY_ID \
-H "Authorization: Bearer YOUR_API_KEY"

Key Scopes​

API keys can be scoped to limit their permissions:

ScopeDescription
email:sendSend emails
email:readRead email messages and events
push:sendSend push notifications
push:readRead push messages
push:writeManage push configuration
sms:sendSend SMS messages
sms:readRead SMS messages
inbox:sendSend in-app notifications
inbox:readRead inbox data
domains:readRead domain configuration
domains:writeManage domains
api_keys:readList API keys
api_keys:writeCreate/revoke API keys
*Wildcard — all permissions

An endpoint accepts a key that holds any one of the scopes it requires. Endpoints with no dedicated scope (SMS provider configuration, subscribers, digests, Slack, Discord, Teams, scheduled messages, search, cohorts and bulk or failed-message replay) require *. Replaying a single message needs that channel's send scope (email:send, push:send or sms:send). A key created with no scopes selected is saved with *, so it has full access. Marking inbox notifications read, archiving or deleting them needs inbox:send. A key that does not hold * can only create keys with scopes it holds itself, and only a * key can change a key's IP allowlist. A key that has an IP allowlist can only set allowlists inside its own: it can't clear one or add an address outside it. A key created with another API key inherits that key's IP allowlist, and it can't expire later than that key: if you don't set expires_at, it gets the creating key's expiry. SMTP submission needs email:send or *.

IP Whitelisting​

Restrict API key usage to specific IP addresses or CIDR ranges:

Via Dashboard​

On the API Keys page, click on a key to view its details and configure IP restrictions.

Via API​

curl -X PUT https://api.zyphr.dev/v1/api-keys/KEY_ID/ip-whitelist \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ip_whitelist": ["203.0.113.0/24", "198.51.100.42"]
}'

Security Best Practices​

Store Keys Securely​

Never commit API keys to version control. Use environment variables:

# .env (never commit this file!)
ZYPHR_API_KEY=zy_live_xxxxxxxxxxxx
// Access via environment variable
const apiKey = process.env.ZYPHR_API_KEY;

Use Test Keys in Development​

Test keys are retired (see the notice above). Send to an address you control instead of relying on a key that never delivered:

# Development
ZYPHR_API_KEY=zy_test_dev_key_here

# Production
ZYPHR_API_KEY=zy_live_prod_key_here

Rotate Keys Regularly​

Rotate your API keys periodically:

  1. Create a new API key (Dashboard or API)
  2. Update your application to use the new key
  3. Verify everything works
  4. Revoke the old key (Dashboard or API)

Use Scoped Keys​

Create keys with only the permissions they need. A backend service that only sends emails should use a key scoped to email:send, not *.

Rate Limiting​

API keys are subject to rate limits based on your plan:

PlanRequests/minute
Free60
Starter300
Pro600
Scale1,200
EnterpriseUnlimited

Rate limit headers are included in every response:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1705312800

Revoking Keys​

Via Dashboard​

  1. Go to API Keys in the sidebar
  2. Find the key you want to revoke
  3. Click the Revoke button
  4. Confirm the action

Via API​

curl -X DELETE https://api.zyphr.dev/v1/api-keys/KEY_ID \
-H "Authorization: Bearer YOUR_API_KEY"
caution

Revoking a key is immediate and permanent. Any applications using the key will stop working.

Troubleshooting​

401 Unauthorized​

{
"error": {
"code": "unauthorized",
"message": "Invalid or missing API key"
}
}

Common causes:

  • Missing X-API-Key header
  • Typo in the API key
  • Key has been revoked
  • Key has expired

403 Forbidden​

{
"error": {
"code": "forbidden",
"message": "API key does not have permission"
}
}

Common causes:

  • Using a test key for a production-only endpoint
  • Key doesn't have the required scope
  • IP address not in the key's whitelist