Authentication
Learn how to authenticate your API requests to Forma Mail.
Overview
Forma Mail API supports two authentication methods:
- API Keys (Recommended for production) - Long-lived credentials for server-to-server communication
- JWT Bearer Tokens - Short-lived tokens for dashboard and web applications
For most API integrations, you should use API Keys as they are designed for programmatic access.
API Key Authentication
How It Works
API Keys are long-lived credentials that allow your application to make authenticated requests to the Forma Mail API. Each request must include your API key in the Authorization header.
Creating an API Key
Step 1: Log in to Your Account
Visit the Forma Mail Dashboard and sign in to your account.
Step 2: Navigate to API Keys
- Click on Settings in the sidebar
- Select API Keys from the settings menu
- Click the Create API Key button
Step 3: Configure Your API Key
Fill in the following details:
- Name: A descriptive name (e.g., “Production Server”, “Staging Environment”)
- Description (optional): Additional notes about this key’s usage
- Permissions: Select the permissions this key should have
emails:send- Send emailsemails:read- Read email logstemplates:read- Read templates- (Choose only the permissions you need)
- Expiration (optional): Set an expiration date for added security
- Rate Limit (optional): Limit requests per minute for this key
Step 4: Save Your API Key
Click Create API Key. You’ll see your new API key only once:
fm_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0⚠️ Important: Copy and save this key immediately. For security reasons, we cannot show it to you again.
Using Your API Key
Include your API key in the Authorization header of every API request:
curl https://api.formamail.com/api/emails/send \
-H "Authorization: Bearer fm_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0" \
-H "Content-Type: application/json" \
-d '{...}'API Key Format
API keys follow this format:
fm_sk_{random_string}fm_- Forma Mail prefixsk_- Secret key identifier{random_string}- Cryptographically secure random string
Example: fm_sk_a1b2c3d4e5f6g7h8i9j0...
Authentication Examples
Node.js / JavaScript
const axios = require('axios');
const API_KEY = 'fm_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0';
const API_URL = 'https://api.formamail.com/api';
// Configure axios with API key
const formaMailClient = axios.create({
baseURL: API_URL,
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
});
// Send an email
async function sendEmail() {
try {
const response = await formaMailClient.post('/emails/send', {
templateId: 'your-template-id',
to: [{ email: 'user@example.com', name: 'John Doe' }],
variables: {
firstName: 'John',
orderNumber: 'ORD-12345',
},
});
console.log('Email sent:', response.data);
} catch (error) {
console.error('Error:', error.response.data);
}
}
sendEmail();Python
import requests
import json
API_KEY = 'fm_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0'
API_URL = 'https://api.formamail.com/api'
# Configure headers
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
# Send an email
def send_email():
payload = {
'templateId': 'your-template-id',
'to': [{'email': 'user@example.com', 'name': 'John Doe'}],
'variables': {
'firstName': 'John',
'orderNumber': 'ORD-12345'
}
}
response = requests.post(
f'{API_URL}/emails/send',
headers=headers,
data=json.dumps(payload)
)
if response.status_code == 201:
print('Email sent:', response.json())
else:
print('Error:', response.json())
send_email()PHP
<?php
$apiKey = 'fm_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0';
$apiUrl = 'https://api.formamail.com/api';
// Prepare request
$ch = curl_init($apiUrl . '/emails/send');
$payload = json_encode([
'templateId' => 'your-template-id',
'to' => [
['email' => 'user@example.com', 'name' => 'John Doe']
],
'variables' => [
'firstName' => 'John',
'orderNumber' => 'ORD-12345'
]
]);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json'
]
]);
// Execute request
$response = curl_exec($ch);
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($statusCode === 201) {
echo 'Email sent: ' . $response;
} else {
echo 'Error: ' . $response;
}Ruby
require 'net/http'
require 'json'
API_KEY = 'fm_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0'
API_URL = 'https://api.formamail.com/api'
# Send an email
def send_email
uri = URI("#{API_URL}/emails/send")
request = Net::HTTP::Post.new(uri)
request['Authorization'] = "Bearer #{API_KEY}"
request['Content-Type'] = 'application/json'
request.body = {
templateId: 'your-template-id',
to: [{ email: 'user@example.com', name: 'John Doe' }],
variables: {
firstName: 'John',
orderNumber: 'ORD-12345'
}
}.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
if response.code == '201'
puts "Email sent: #{response.body}"
else
puts "Error: #{response.body}"
end
end
send_emailcURL
curl -X POST https://api.formamail.com/api/emails/send \
-H "Authorization: Bearer fm_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0" \
-H "Content-Type: application/json" \
-d '{
"templateId": "your-template-id",
"to": [
{
"email": "user@example.com",
"name": "John Doe"
}
],
"variables": {
"firstName": "John",
"orderNumber": "ORD-12345"
}
}'API Key Management
Viewing API Keys
Navigate to Settings → API Keys to see all your API keys. You’ll see:
- Key name and description
- Creation date
- Last used date
- Expiration date (if set)
- Permissions
- Status (active/expired/revoked)
Rotating API Keys
For security, we recommend rotating your API keys periodically:
- Create a new API key with the same permissions
- Update your application to use the new key
- Test that the new key works
- Revoke the old API key
Revoking API Keys
If a key is compromised or no longer needed:
- Go to Settings → API Keys
- Find the key to revoke
- Click Revoke and confirm
Once revoked, the key immediately stops working. This action cannot be undone.
Security Best Practices
âś… DO
- Store API keys securely - Use environment variables or secret managers
- Create separate keys for different applications or services
- Limit permissions - Only grant the permissions each key needs
- Set expiration dates for added security
- Rotate keys regularly - At least every 90 days
- Revoke unused keys - Remove keys that are no longer needed
- Monitor usage - Check the “Last Used” date regularly
❌ DON’T
- Never commit API keys to version control (Git, SVN, etc.)
- Don’t share API keys via email, Slack, or other communication channels
- Don’t hardcode keys in your application source code
- Don’t expose keys in client-side code (JavaScript, mobile apps)
Environment Variables
Store your API key in environment variables:
Linux/macOS (.env file):
FORMA_MAIL_API_KEY=fm_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0
FORMA_MAIL_API_URL=https://api.formamail.com/apiNode.js (using dotenv):
require('dotenv').config();
const API_KEY = process.env.FORMA_MAIL_API_KEY;
const API_URL = process.env.FORMA_MAIL_API_URL;Python:
import os
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.getenv('FORMA_MAIL_API_KEY')
API_URL = os.getenv('FORMA_MAIL_API_URL')Rate Limits
API keys are subject to rate limiting to ensure fair usage:
- Default: 100 requests per minute
- Burst: Up to 200 requests in a 10-second window
- Custom limits: Contact us for high-volume requirements
Rate Limit Headers
Each API response includes rate limit headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640995200X-RateLimit-Limit- Total requests allowed per minuteX-RateLimit-Remaining- Requests remaining in current windowX-RateLimit-Reset- Unix timestamp when the limit resets
Handling Rate Limits
When you exceed the rate limit, you’ll receive a 429 Too Many Requests response:
{
"statusCode": 429,
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Please try again in 30 seconds.",
"timestamp": "2024-11-19T12:00:00.000Z",
"path": "/api/emails/send"
}Recommended approach:
async function sendWithRetry(payload, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await formaMailClient.post('/emails/send', payload);
return response.data;
} catch (error) {
if (error.response?.status === 429) {
const retryAfter = error.response.headers['retry-after'] || 30;
console.log(`Rate limited. Retrying in ${retryAfter} seconds...`);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
} else {
throw error;
}
}
}
throw new Error('Max retries exceeded');
}Error Responses
All authentication errors return a structured response:
{
"statusCode": 401,
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key",
"timestamp": "2024-11-19T12:00:00.000Z",
"path": "/api/emails/send"
}Common Authentication Errors
| Status | Code | Message | Solution |
|---|---|---|---|
| 401 | UNAUTHORIZED | Missing Authorization header | Include Authorization header |
| 401 | INVALID_API_KEY | Invalid API key format | Check API key format |
| 401 | API_KEY_NOT_FOUND | API key not found | Verify the key exists |
| 401 | API_KEY_REVOKED | API key has been revoked | Create a new API key |
| 401 | API_KEY_EXPIRED | API key has expired | Create a new API key |
| 403 | FORBIDDEN | Insufficient permissions | Check API key permissions |
Testing Your API Key
Use this endpoint to verify your API key is working:
curl -X GET https://api.formamail.com/api/emails/usage/stats \
-H "Authorization: Bearer YOUR_API_KEY"Success response (200 OK):
{
"email": {
"used": 150,
"limit": 1000,
"remaining": 850,
"percentUsed": 15
},
"attachment": {
"used": 50,
"limit": 500,
"remaining": 450,
"percentUsed": 10
},
"billingPeriod": "2024-11-01"
}Next Steps
Back to API Reference