Authentication
Learn how to authenticate with the Transactional API.
Authentication
The Transactional API uses API keys to authenticate requests. All API requests must include a valid API key.
Getting Your API Key
- Log in to the Transactional Dashboard
- Navigate to Settings > API Keys
- Click Create API Key
- Give your key a name and select the appropriate type
- Copy the key - it will only be shown once!
API Key Types
Transactional provides different API key types for different use cases:
| Type | Prefix | Use Case |
|---|---|---|
| Server | tr_srv_ | Full API access from your backend |
| Sending | tr_snd_ | Send-only access for email/SMS |
| Public | tr_pub_ | Client-side form submissions |
Server Keys
Server keys have full API access and should only be used in secure server environments:
// Server-side only
const client = new Transactional({
apiKey: process.env.TRANSACTIONAL_SERVER_KEY, // tr_srv_...
});
// Full access to all endpoints
await client.emails.send(...);
await client.templates.list();
await client.suppressions.add(...);Sending Keys
Sending keys can only send messages and cannot read data:
const client = new Transactional({
apiKey: process.env.TRANSACTIONAL_SENDING_KEY, // tr_snd_...
});
// Can send
await client.emails.send(...);
await client.sms.send(...);
// Cannot read - will throw error
await client.emails.messages.list(); // 403 ForbiddenPublic Keys
Public keys are safe to use in client-side code for form submissions:
// Safe for client-side use
const client = new Transactional({
apiKey: 'tr_pub_...', // Can be exposed in browser
});
// Only form submission endpoints
await client.forms.submit(formId, data);Using Your API Key
Authorization Header
Include your API key in the Authorization header:
curl https://api.usetransactional.com/v1/emails \
-H "Authorization: Bearer tr_srv_your_api_key"X-API-Key Header
Alternatively, use the X-API-Key header:
curl https://api.usetransactional.com/v1/emails \
-H "X-API-Key: tr_srv_your_api_key"Both methods are equivalent. Choose whichever fits your workflow.
SDK Authentication
TypeScript SDK
import { Transactional } from 'transactional-sdk';
// Basic authentication
const client = new Transactional({
apiKey: process.env.TRANSACTIONAL_API_KEY,
});
// With additional options
const client = new Transactional({
apiKey: process.env.TRANSACTIONAL_API_KEY,
baseUrl: 'https://api.usetransactional.com/v1', // Default
timeout: 30000, // 30 seconds
retries: 3, // Retry failed requests
});Python SDK
from transactional import Transactional
import os
# Basic authentication
client = Transactional(api_key=os.environ["TRANSACTIONAL_API_KEY"])
# With additional options
client = Transactional(
api_key=os.environ["TRANSACTIONAL_API_KEY"],
base_url="https://api.usetransactional.com/v1", # Default
timeout=30.0, # 30 seconds
retries=3, # Retry failed requests
)
# Async client
from transactional import AsyncTransactional
async_client = AsyncTransactional(api_key=os.environ["TRANSACTIONAL_API_KEY"])Environment Variables
We recommend storing API keys in environment variables:
Node.js (.env)
# .env
TRANSACTIONAL_API_KEY=tr_srv_your_api_keyimport { Transactional } from 'transactional-sdk';
import 'dotenv/config';
const client = new Transactional({
apiKey: process.env.TRANSACTIONAL_API_KEY!,
});Python
# .env
TRANSACTIONAL_API_KEY=tr_srv_your_api_keyfrom transactional import Transactional
from dotenv import load_dotenv
import os
load_dotenv()
client = Transactional(api_key=os.environ["TRANSACTIONAL_API_KEY"])Framework-Specific
Next.js:
# .env.local
TRANSACTIONAL_API_KEY=tr_srv_your_api_keyVercel:
vercel env add TRANSACTIONAL_API_KEYDocker:
# docker-compose.yml
services:
app:
environment:
- TRANSACTIONAL_API_KEY=tr_srv_your_api_keyAPI Key Security
Follow these best practices to keep your API keys secure:
Do's
- Store keys in environment variables - Never hardcode keys
- Use separate keys for development and production
- Rotate keys regularly - Especially after team changes
- Limit key permissions - Use sending keys when full access isn't needed
- Monitor key usage - Check for unexpected activity in the dashboard
Don'ts
- Never commit keys to version control - Use .gitignore
- Never expose server keys in client-side code
- Never share keys via email or chat
- Never log keys in application logs
.gitignore Example
# Environment files
.env
.env.local
.env.*.local
# API keys (if accidentally created)
*.key
api_key.txtKey Permissions
API keys can be scoped to specific permissions:
| Permission | Description |
|---|---|
emails:send | Send transactional emails |
emails:read | View email history and analytics |
emails:manage | Manage templates, domains, senders |
sms:send | Send SMS messages |
sms:read | View SMS history |
sms:manage | Manage templates, webhooks |
forms:read | View forms and submissions |
forms:manage | Create and edit forms |
support:read | View conversations |
support:manage | Reply to and manage conversations |
auth:read | View users and settings |
auth:manage | Manage users and authentication |
calendar:read | View bookings |
calendar:manage | Manage event types and schedules |
domains:read | View domains and DNS |
domains:manage | Register and manage domains |
webhooks:manage | Configure webhook endpoints |
billing:read | View billing information |
Creating Scoped Keys
curl -X POST https://api.usetransactional.com/v1/api-keys \
-H "Authorization: Bearer tr_srv_admin_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Email Service",
"type": "SERVER",
"permissions": ["emails:send", "emails:read"]
}'Rotating API Keys
To rotate an API key:
- Create a new API key with the same permissions
- Update your application to use the new key
- Monitor that the new key is working
- Revoke the old key
Rotating via API
// Create new key
const newKey = await client.apiKeys.create({
name: 'Production Server (Rotated)',
type: 'SERVER',
permissions: ['emails:send', 'emails:read'],
});
console.log(`New key: ${newKey.key}`); // Only shown once!
// After updating your application...
// Revoke old key
await client.apiKeys.revoke(oldKeyId);Testing Authentication
Verify Your Key
Test that your key is valid:
curl https://api.usetransactional.com/v1/ping \
-H "Authorization: Bearer YOUR_API_KEY"Success Response:
{
"success": true,
"data": {
"message": "pong",
"organization": "your-org-name",
"keyType": "SERVER",
"permissions": ["emails:send", "emails:read", "..."]
}
}Invalid Key Response:
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid API key"
}
}SDK Verification
try {
const response = await client.ping();
console.log(`Connected as: ${response.organization}`);
console.log(`Key type: ${response.keyType}`);
console.log(`Permissions: ${response.permissions.join(', ')}`);
} catch (error) {
if (error.code === 'UNAUTHORIZED') {
console.error('Invalid API key');
}
}Authentication Errors
| Code | HTTP Status | Description |
|---|---|---|
UNAUTHORIZED | 401 | API key is missing or invalid |
INVALID_API_KEY | 401 | API key format is incorrect |
EXPIRED_API_KEY | 401 | API key has expired |
REVOKED_API_KEY | 401 | API key has been revoked |
FORBIDDEN | 403 | API key lacks required permissions |
Handling Auth Errors
import { Transactional, AuthenticationError } from 'transactional-sdk';
try {
await client.emails.send(...);
} catch (error) {
if (error instanceof AuthenticationError) {
switch (error.code) {
case 'UNAUTHORIZED':
console.error('Check your API key configuration');
break;
case 'FORBIDDEN':
console.error('This key lacks the required permissions');
console.error(`Required: ${error.details?.requiredPermission}`);
break;
case 'REVOKED_API_KEY':
console.error('This key has been revoked. Generate a new one.');
break;
}
}
}Multi-Organization Access
For applications managing multiple Transactional organizations, you can use organization-scoped keys or include the organization ID in requests:
curl https://api.usetransactional.com/v1/emails \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "X-Organization-Id: org_abc123"const client = new Transactional({
apiKey: process.env.TRANSACTIONAL_API_KEY,
organizationId: 'org_abc123', // Override default organization
});Next Steps
- API Overview - Understanding the API
- Error Handling - Handle errors gracefully
- Rate Limiting - Understand rate limits