Authentication
4 min read
All API requests require authentication using an API key. This page explains how to create, use, and manage your API keys.
API Key Format
Outboxa API keys look like this:
ob_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
ob_test_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
| Prefix | Type | Behaviour |
|---|---|---|
ob_live_ |
Live | Emails are sent for real |
ob_test_ |
Test (sandbox) | Nothing is sent — use it to test your integration |
Test keys (sandbox)
A test key goes through exactly the same API path as a live key — authentication, validation, field limits, idempotency, rate limiting, response shapes and webhooks — but no email ever leaves our servers.
Create one in the dashboard (API Keys → New key → Test) or via the API:
curl -X POST https://api.mailingapi.com/v1/api-keys \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Integration tests", "domain_id": "...", "permissions": ["send", "read"], "mode": "test"}'
How test keys differ:
-
Messages are marked
"sandbox": truein every response and webhook payload. - The simulated result depends on the recipient:
| Recipient | Result | Webhook |
|---|---|---|
bounce@simulator.mailingapi.com |
bounced (hard bounce, error_code: "hard_bounce") |
message.bounced |
| an address on your suppression list |
rejected |
— |
| any other address |
delivered with smtp_response: "250 sandbox: not sent" |
message.delivered |
-
The sender domain does not have to be verified yet, but the
fromaddress must still be from the key’s domain. - Sandbox messages don’t count towards your plan’s monthly or daily limits, the domain’s daily limit, the per-recipient limit, statistics or reputation. API rate limits (per second / per minute) still apply.
- Test keys don’t count towards the plan’s API key limit.
-
A test key only sees sandbox messages in
GET /v1/messages, and a live key only sees live ones. - Sandbox messages are deleted after 7 days.
Using Your API Key
Include your API key in the Authorization header with the Bearer scheme:
curl -X POST https://api.mailingapi.com/v1/messages/send \
-H "Authorization: Bearer ob_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"from": "...", "to": "...", "subject": "...", "html": "..."}'
Python
import requests
headers = {
"Authorization": "Bearer ob_live_your_key_here",
"Content-Type": "application/json"
}
response = requests.post(
"https://api.mailingapi.com/v1/messages/send",
headers=headers,
json={...}
)
JavaScript
const response = await fetch('https://api.mailingapi.com/v1/messages/send', {
method: 'POST',
headers: {
'Authorization': 'Bearer ob_live_your_key_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({...})
});
API Key Permissions
Each API key has a permission level that controls what operations it can perform:
| Permission | Can do |
|---|---|
send |
Send emails, analyze content |
read |
Read messages, events, statistics |
manage |
Manage domains, templates, webhooks, API keys |
admin |
Full access including billing |
When creating an API key, choose the minimum permissions needed. For example, if your backend only sends emails, use a send key.
Domain Binding
Each API key is bound to a specific domain. The from address in your emails must match the key’s domain:
Key domain: notifications.example.com
✓ from: "alerts@notifications.example.com"
✓ from: "no-reply@notifications.example.com"
✗ from: "hello@other-domain.com" — will fail
This prevents unauthorized sending from domains you don’t control.
Creating API Keys
Via Dashboard
- Go to Settings → API Keys
- Click Create new key
- Select the domain and permissions
- Copy and securely store the key
The full key is only shown once. Store it in your secrets manager or environment variables.
Via API
curl -X POST https://api.mailingapi.com/v1/api-keys \
-H "Authorization: Bearer ob_live_admin_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Backend Production",
"domain_id": "dom_123abc",
"permissions": ["send", "read"]
}'
Key Rotation
To rotate a key without downtime:
- Create a new key with the same permissions
- Update your application to use the new key
- Delete or revoke the old key
Or use our built-in rotation with grace period:
curl -X POST https://api.mailingapi.com/v1/api-keys/key_123/rotate \
-H "Authorization: Bearer ob_live_admin_key" \
-H "Content-Type: application/json" \
-d '{"grace_period_minutes": 60}'
Both keys work during the grace period, giving you time to deploy updates.
Security Best Practices
Do
- Store keys in environment variables or a secrets manager
- Use separate keys for different environments (staging, production)
- Use minimum required permissions
- Rotate keys regularly (every 90 days recommended)
- Monitor key usage in the dashboard
Don’t
- Commit keys to version control
- Share keys between applications
- Use admin keys when send-only is sufficient
- Log API keys in your application
Handling Authentication Errors
If authentication fails, you’ll receive a 401 Unauthorized response:
{
"error": {
"message": "Invalid or missing API key"
}
}
Common causes:
-
Missing
Authorizationheader -
Invalid key format (not starting with
ob_) - Revoked or deleted key
- Key doesn’t have required permissions
-
fromaddress doesn’t match key’s domain
Rate Limiting
API requests are rate limited per key. Successful responses include X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix epoch seconds). When you exceed the limit, you’ll receive 429 Too Many Requests:
{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded",
"retry_after": 5
}
}
Every 429 includes the standard Retry-After header (integer seconds) and the same value as retry_after in the body. Wait that many seconds before retrying; reading the Retry-After header is recommended. See API Overview → Rate limiting for all headers.
Rate limits per API key action:
| Action | Default limit |
|---|---|
| Send email | 100/minute |
| Read endpoints | 1000/minute |
| Management | 100/minute |
Next steps
Now that you understand authentication, learn how to handle errors gracefully.