Test Mode
Test mode lets you develop and test your Zyphr integration safely. Both notifications and Auth-as-a-Service support test mode with isolated data and restricted behavior.
Test Mode by Product
Zyphr has two test mode systems, each with its own key prefix:
| Product | Test Key Prefix | What Test Mode Does |
|---|---|---|
| Notifications | zy_test_* | Messages are stored but never delivered |
| Auth-as-a-Service | za_test_* | Users are isolated from production, limited to 10 |
Auth-as-a-Service Test Mode
When you create an Application, you receive both test and live key pairs:
za_test_pub_xxxx / za_test_sec_xxxx ← Test keys
za_live_pub_xxxx / za_live_sec_xxxx ← Live keys
Isolated User Pools
Test and live keys operate on completely separate user pools, similar to Stripe's test/live modes:
- A user registered with
za_test_*keys does not exist in the live environment - The same email can be registered independently in both test and live
- Login with test keys only finds test users; login with live keys only finds live users
- JWTs include an
environment_idclaim so your backend can verify which environment a token came from
za_test_* keys → Test user pool (isolated, max 10 users)
za_live_* keys → Live user pool (production)
Test Environment Limits
The test environment is limited to 10 users per application. This is intentional — test mode is for integration development, not load testing. If you need more users for testing, use a separate application.
If you exceed the limit, registration returns:
{
"error": {
"code": "test_environment_limit",
"message": "Test environment is limited to 10 users. Current: 10. Use live keys for production.",
"limit": 10,
"current": 10
}
}
Using Test Keys
Set up your development environment to use test keys:
ZYPHR_APP_PUBLIC_KEY=za_test_pub_xxxx
ZYPHR_APP_SECRET_KEY=za_test_sec_xxxx
ZYPHR_APP_PUBLIC_KEY=za_live_pub_xxxx
ZYPHR_APP_SECRET_KEY=za_live_sec_xxxx
Register and login calls work identically with both key types:
# Register a test user — this user only exists in the test environment
curl -X POST https://api.zyphr.dev/v1/auth/users/register \
-H "X-Application-Key: za_test_pub_xxxx" \
-H "X-Application-Secret: za_test_sec_xxxx" \
-H "Content-Type: application/json" \
-d '{"email": "dev@example.com", "password": "SecurePass123!"}'
What Carries Over
All application-level configuration is shared between test and live environments:
- Password policy
- Session duration and refresh token settings
- OAuth provider configuration
- Lockout settings
- Allowed origins and redirect URIs
Only the user data (registrations, sessions, OAuth connections, magic links) is isolated per environment.
Dashboard Visibility
In the dashboard's Users tab for an application:
- Each user shows a Test (yellow) or Live (green) badge
- Use the All / Live / Test filter to view users by environment
- The test filter shows a reminder of the 10-user limit
Notifications Test Mode
When you use a zy_test_* API key for notifications:
- Messages are stored - All messages are saved to the database
- No delivery - Messages skip the actual delivery providers (SES, FCM, Twilio)
- Mock responses - You receive realistic API responses
- Events are tracked - Status changes and events are recorded
- Dashboard visibility - View test messages in the dashboard
Using Notification Test Mode
Create a Test API Key
- Go to Settings → API Keys
- Click Create API Key
- Select Test as the key type
- Copy your
zy_test_*key
Send Test Messages
Use your test key in API requests:
curl -X POST https://api.zyphr.dev/v1/emails \
-H "X-API-Key: zy_test_your_key" \
-H "Content-Type: application/json" \
-d '{
"to": "anyone@example.com",
"subject": "Test Email",
"html": "<p>This won'\''t actually be delivered!</p>"
}'
Response includes is_test: true:
{
"data": {
"id": "msg_test123",
"to": "anyone@example.com",
"status": "sent",
"is_test": true,
"created_at": "2024-01-15T10:30:00Z"
}
}
What Happens to Test Messages
Email
- Stored in database with
is_test = true - Status progresses:
queued→sending→sent - No email is sent via SES
- Mock message ID:
test_mock_<message_id>
Push Notifications
- Stored with
is_test = true - Status:
queued→sending→sent - No push sent via FCM/APNs
- Mock message ID generated
SMS
- Stored with
is_test = true - Status:
queued→sending→sent - No SMS sent via Twilio
- Mock segment count: 1
In-App Notifications
- Created normally in the inbox
- Visible to subscribers if they exist
- Marked with
is_test = true
Identifying Test Messages
In API Responses
All responses include the is_test flag:
{
"data": {
"id": "msg_123",
"is_test": true
}
}
In the Dashboard
Test messages are clearly labeled in the dashboard with a "Test" badge. You can filter to show only test or only live messages.
In the Database
Query test messages:
SELECT * FROM messages WHERE is_test = true;
Best Practices
Use Test Keys in Development
Set up your development environment to always use test keys:
ZYPHR_API_KEY=zy_test_development_key
ZYPHR_API_KEY=zy_live_production_key
Test All Channels
Verify your integration works for all channels you plan to use:
// Test email
await zyphr.emails.send({
to: 'test@example.com',
subject: 'Test',
html: '<p>Test</p>'
});
// Test push
await zyphr.push.send({
userId: 'test_user',
title: 'Test Push',
body: 'Test notification'
});
// Test SMS
await zyphr.sms.send({
to: '+14155551234',
body: 'Test SMS'
});
Verify Webhook Handling
Test webhooks work the same in test mode. Configure a webhook endpoint and verify you receive events:
{
"event": "message.sent",
"data": {
"message_id": "msg_test123",
"is_test": true
}
}
Automatic Cleanup
Test data is automatically cleaned up after 30 days to keep your account tidy. If you need longer retention for testing, contact support.
Switching to Production
When you're ready to go live:
Notifications
- Verify your domain (required for email)
- Configure push credentials (FCM, APNs)
- Configure SMS credentials (Twilio)
- Swap your test key for a live key
- Test with a single real recipient first
- ZYPHR_API_KEY=zy_test_your_key
+ ZYPHR_API_KEY=zy_live_your_key
Auth-as-a-Service
- Verify your integration works with test keys
- Swap to live application keys
- Your first live user registration creates the production user pool
- ZYPHR_APP_PUBLIC_KEY=za_test_pub_xxxx
- ZYPHR_APP_SECRET_KEY=za_test_sec_xxxx
+ ZYPHR_APP_PUBLIC_KEY=za_live_pub_xxxx
+ ZYPHR_APP_SECRET_KEY=za_live_sec_xxxx
Test users are not migrated to the live environment. Your live user pool starts empty — this is by design. Users must register fresh with the live keys.
FAQ
Can I mix test and live keys?
Each API request uses exactly one key. You cannot mix test and live operations in a single request. For Auth-as-a-Service, test and live keys access completely separate user pools.
Do test messages count against my quota?
Test messages do not count against your monthly message quota.
Do test auth users count against my MAU quota?
No. Test environment activity (registrations, logins, token refreshes, OAuth, magic links) does not count toward your auth request quota or MAU tracking. Test mode is completely free to use.
Can I test webhooks?
Yes! Webhooks fire for test messages just like live messages. The webhook payload includes is_test: true. Auth webhooks (user.created, user.login, etc.) fire for both test and live environments.
Are test and live auth users completely separate?
Yes. A user registered with za_test_* keys cannot log in with za_live_* keys and vice versa. The same email can be registered independently in both environments. This mirrors Stripe's test/live isolation model.
Why is the test environment limited to 10 users?
The test environment is designed for integration development and verification, not for staging or load testing. If you need a larger user pool for QA, create a separate Application dedicated to that purpose.
How do I clean up old test data?
Test notification data older than 30 days is automatically deleted. For Auth-as-a-Service test users, you can delete them individually via the dashboard or API. For immediate cleanup, contact support.