Skip to content

API Authentication

Learn how to authenticate with the mailiam API, manage API keys, and implement secure authentication in your applications.

mailiam uses an adaptive authentication system that provides the right level of security for each use case. Unlike traditional APIs that require keys for everything, mailiam intelligently adapts based on your needs.

mailiam provides three types of API keys, each designed for specific scenarios:

Full account access - Complete control over your mailiam account.

  • ✅ CLI operations
  • ✅ Domain management
  • ✅ API key management
  • ✅ Billing and settings
  • 🔴 Critical security - Never expose client-side

Limited operational access - Form submissions and email sending only.

  • ✅ Form submissions
  • ✅ Email sending
  • ❌ Cannot manage domains
  • ❌ Cannot create API keys
  • 🟡 Moderate security - Safe in server environments only

Domain-specific, client-side safe - Limited to one domain.

  • ✅ Form submissions for scoped domain
  • ✅ Safe for static sites
  • ✅ Can be exposed in JavaScript
  • ❌ Cannot access other domains
  • 🟢 Safe for client-side - Domain-scoped protection
FeatureAdmin KeysUsage KeysPublic Tokens
Manage domains
Send emails✅ (scoped)
Create API keys
Client-side safe
Rate limit1000/hr1000/hr100/hr
Need admin operations? → Admin Key (server-only)
↓ No
Building backend API? → Usage Key (server-only)
↓ No
Static site, simple forms? → No key needed! (origin validation)
↓ No
Static site, need JS features? → Public Token (client-safe)
Admin Keys: mlm_sk_admin_{64_hex_characters}
Usage Keys: mlm_sk_usage_{64_hex_characters}
Public Keys: mlm_pk_{domain_hash}_{64_hex_characters}
Terminal window
# Admin Key (full access)
mlm_sk_admin_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6...
# Usage Key (forms and email only)
mlm_sk_usage_x9y8z7w6v5u4t3s2r1q0p9o8n7m6l5k4j3i2h1g0f9e8d7c6b5a4...
# Public Token (domain-scoped)
mlm_pk_a7f8b3e1_j4k5l6m7n8o9p0q1r2s3t4u5v6w7x8y9z0a1b2c3d4e5f6g7...
^^^^^^^^^
Domain hash - identifies the scoped domain
Terminal window
# Create admin key (default - full access)
mailiam auth create-key --name "Production Admin"
# Create usage key (forms and email only)
mailiam auth create-key \
--name "Vercel API Route" \
--type usage
# Create public token (domain-scoped, client-safe)
mailiam auth create-key \
--name "Public Token for mysite.com" \
--type public \
--domain mysite.com
# List all keys
mailiam auth list-keys
# List keys by type
mailiam auth list-keys --type public
Terminal window
# Create admin key
curl -X POST https://api.mailiam.dev/api-keys \
-H "Authorization: Bearer $MAILIAM_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Production Admin Key",
"keyType": "admin"
}'
# Create usage key
curl -X POST https://api.mailiam.dev/api-keys \
-H "Authorization: Bearer $MAILIAM_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Vercel API Routes",
"keyType": "usage",
"rateLimit": 1000
}'
# Create public token (domain-scoped)
curl -X POST https://api.mailiam.dev/api-keys \
-H "Authorization: Bearer $MAILIAM_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Public Token for mysite.com",
"keyType": "public",
"domainScope": "mysite.com"
}'
{
"success": true,
"apiKey": {
"keyId": "key_abc123",
"name": "Public Token for mysite.com",
"keyType": "public",
"domainScope": "mysite.com",
"permissions": ["forms:send"],
"rateLimit": 100,
"key": "mlm_pk_a7f8b3e1_j4k5l6m7...",
"createdAt": "2024-01-15T10:30:00Z"
},
"message": "Public key created successfully. Save the key securely - it will not be shown again.",
"securityNote": "This public key is safe for client-side use but is scoped to the specified domain only."
}
  1. Log into mailiam dashboard at https://mailiam.dev
  2. Navigate to API Keys section
  3. Click Create New Key
  4. Select key type (Admin, Usage, or Public)
  5. For public tokens, select the domain
  6. Click Generate Key
  7. Copy and save the key immediately (shown only once!)

For backend applications, include the API key in the request header:

Terminal window
curl -X POST https://api.mailiam.dev/projects \
-H "Authorization: Bearer mlm_sk_live_abc123..." \
-H "Content-Type: application/json" \
-d '{"name": "My Project"}'

Alternative header formats:

Terminal window
# X-Api-Key header
curl -H "X-Api-Key: mlm_sk_live_abc123..." \
https://api.mailiam.dev/projects
# mailiam-Api-Key header
curl -H "mailiam-Api-Key: mlm_sk_live_abc123..." \
https://api.mailiam.dev/projects

For browser form submissions to verified domains, no API key is required:

<!-- Direct form submission (no API key needed) -->
<form action="https://api.mailiam.dev/yourdomain.com/contact" method="POST">
<input name="name" placeholder="Name" required>
<input name="email" type="email" placeholder="Email" required>
<textarea name="message" placeholder="Message" required></textarea>
<button type="submit">Send</button>
</form>

Public tokens are designed for client-side use and are completely safe to expose:

// Safe for static sites! Token is domain-scoped
const PUBLIC_TOKEN = 'mlm_pk_a7f8b3e1_j4k5l6m7n8o9p0q1...';
const response = await fetch('https://api.mailiam.dev/v1/mysite.com/send', {
method: 'POST',
headers: {
'X-Public-Token': PUBLIC_TOKEN,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'John Doe',
email: 'john@example.com',
message: 'Hello from my static site!'
})
});
if (response.ok) {
console.log('Message sent successfully!');
}

Why it’s safe:

  • ✅ Only works for the specified domain (mysite.com)
  • ✅ Cannot access other domains or admin functions
  • ✅ Limited to 100 requests/hour
  • ✅ Can only submit forms, nothing else

For API routes and backend services, use usage keys:

// Never expose this in client code!
const USAGE_KEY = process.env.MAILIAM_USAGE_KEY;
const response = await fetch('https://api.mailiam.dev/v1/mysite.com/send', {
method: 'POST',
headers: {
'X-Api-Key': USAGE_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: req.body.name,
email: req.body.email,
message: req.body.message
})
});

For CLI and administrative tasks, use admin keys:

// Only use in trusted server environments
const ADMIN_KEY = process.env.MAILIAM_ADMIN_KEY;
// Create a new domain
const response = await fetch('https://api.mailiam.dev/domains', {
method: 'POST',
headers: {
'Authorization': `Bearer ${ADMIN_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
domain: 'newdomain.com'
})
});
EndpointMethodAdmin KeyUsage KeyPublic TokenNo Auth
Form Submissions
/v1/{domain}/sendPOST✅ (scoped)✅ (origin)
/f/{formId}POST
/c/{collection}/{form}POST
Domain Management
/domainsGET
/domainsPOST
/domains/{domain}PUT, DELETE
API Key Management
/api-keysGET, POST
/api-keys/{keyId}DELETE
Projects & Collections
/projectsGET, POST
/collectionsGET, POST
Analytics
/analyticsGET
Admin Operations
/admin/*ALL
  • Admin Key: Full access to everything
  • Usage Key: Limited to sending emails and forms
  • Public Token: Only works for the scoped domain’s form submissions
  • No Auth: Works with origin validation for browser requests

Use Admin Keys for:

  • CLI operations (mailiam push, mailiam domains)
  • Creating/managing API keys
  • Domain configuration
  • Billing management

Use Usage Keys for:

  • Vercel/Netlify API routes
  • Backend services sending emails
  • Programmatic form submissions
  • Integration with your application

Use Public Tokens for:

  • Static websites with JavaScript
  • Client-side form enhancements
  • Public-facing integrations
  • When you need a key but can’t hide it

Use No Authentication for:

  • Simple HTML forms
  • Static sites without JavaScript
  • Quick prototypes
  • Forms that “just work”
Terminal window
# Via CLI
mailiam auth create-key --name "Production API" --permissions "forms,domains"
# Via API
curl -X POST https://api.mailiam.dev/api-keys \
-H "Authorization: Bearer mlm_sk_live_existing_key..." \
-H "Content-Type: application/json" \
-d '{
"name": "Production API",
"permissions": ["forms", "domains", "analytics"],
"restrictions": {
"ip_whitelist": ["203.0.113.0/24"],
"rate_limit": 1000
}
}'

Configure granular permissions for API keys:

{
"permissions": [
"forms.read",
"forms.write",
"domains.read",
"domains.write",
"collections.read",
"collections.write",
"analytics.read",
"projects.read",
"projects.write"
],
"restrictions": {
"ip_whitelist": ["192.168.1.0/24", "203.0.113.10"],
"domain_restrictions": ["example.com", "api.example.com"],
"rate_limit": 5000,
"expires_at": "2024-12-31T23:59:59Z"
}
}

Regularly rotate API keys for security:

Terminal window
# Create new key
mailiam auth create-key --name "Production API v2"
# Test new key
export MAILIAM_API_KEY="mlm_sk_live_new_key..."
mailiam test config
# Update applications with new key
# Then revoke old key
mailiam auth revoke-key "old_key_id"

Store API keys as environment variables:

Terminal window
# Development
export MAILIAM_API_KEY="mlm_sk_test_abc123..."
# Production
export MAILIAM_API_KEY="mlm_sk_live_xyz789..."

Add to .gitignore:

# Environment files
.env
.env.local
.env.production
# Configuration files with secrets
mailiam.prod.yaml
config/production.yaml

Create keys with minimal required permissions:

Terminal window
# Key only for form submissions
mailiam auth create-key \
--name "Forms Only" \
--permissions "forms.write" \
--rate-limit 100
# Key only for reading analytics
mailiam auth create-key \
--name "Analytics Read" \
--permissions "analytics.read" \
--rate-limit 50

Limit API key usage to specific IP addresses:

{
"name": "Production API",
"restrictions": {
"ip_whitelist": [
"203.0.113.10", // Production server
"192.168.1.0/24", // Internal network
"2001:db8::/32" // IPv6 range
]
}
}

Set appropriate rate limits for each key:

{
"name": "High Volume API",
"restrictions": {
"rate_limit": 10000, // 10k requests per hour
"burst_limit": 100 // 100 requests per minute
}
}
pages/api/contact.js
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ message: 'Method not allowed' });
}
try {
const formData = new FormData();
Object.entries(req.body).forEach(([key, value]) => {
formData.append(key, value);
});
const response = await fetch('https://api.mailiam.dev/yourdomain.com/contact', {
method: 'POST',
headers: {
'X-Api-Key': process.env.MAILIAM_API_KEY
},
body: formData
});
if (response.ok) {
res.status(200).json({ message: 'Message sent successfully' });
} else {
const error = await response.json();
res.status(400).json({ error: error.message });
}
} catch (error) {
res.status(500).json({ error: 'Internal server error' });
}
}
const express = require('express');
const app = express();
// Middleware to add mailiam API key
app.use('/api/mailiam', (req, res, next) => {
req.headers['x-api-key'] = process.env.MAILIAM_API_KEY;
next();
});
// Contact form endpoint
app.post('/api/contact', async (req, res) => {
const formData = new FormData();
Object.entries(req.body).forEach(([key, value]) => {
formData.append(key, value);
});
try {
const response = await fetch('https://api.mailiam.dev/yourdomain.com/contact', {
method: 'POST',
headers: {
'X-Api-Key': process.env.MAILIAM_API_KEY
},
body: formData
});
const result = await response.json();
res.json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
config/services.php
'mailiam' => [
'api_key' => env('MAILIAM_API_KEY'),
'base_url' => 'https://api.mailiam.dev',
],
// app/Services/mailiamService.php
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
class mailiamService
{
protected $apiKey;
protected $baseUrl;
public function __construct()
{
$this->apiKey = config('services.mailiam.api_key');
$this->baseUrl = config('services.mailiam.base_url');
}
public function submitForm($domain, $form, $data)
{
$response = Http::withHeaders([
'X-Api-Key' => $this->apiKey,
])->post("{$this->baseUrl}/{$domain}/{$form}", $data);
return $response->json();
}
}

Handle authentication errors gracefully:

const submitForm = async (formData) => {
try {
const response = await fetch('https://api.mailiam.dev/yourdomain.com/contact', {
method: 'POST',
headers: {
'X-Api-Key': process.env.MAILIAM_API_KEY
},
body: formData
});
if (response.status === 401) {
throw new Error('Invalid API key');
}
if (response.status === 403) {
throw new Error('Insufficient permissions');
}
if (response.status === 429) {
throw new Error('Rate limit exceeded');
}
if (!response.ok) {
throw new Error('Request failed');
}
return await response.json();
} catch (error) {
console.error('Form submission error:', error);
throw error;
}
};
CodeMeaningResolution
200SuccessRequest processed successfully
400Bad RequestCheck request format and required fields
401UnauthorizedVerify API key is correct and active
403ForbiddenCheck API key permissions
404Not FoundVerify endpoint URL and domain
429Too Many RequestsImplement rate limiting and backoff
500Server ErrorContact support if persistent
Terminal window
# Test API key
curl -H "Authorization: Bearer mlm_sk_live_your_key..." \
https://api.mailiam.dev/projects
# Expected response for valid key:
{
"projects": [...],
"count": 5
}
# Expected response for invalid key:
{
"error": "Invalid API key",
"code": "AUTH_INVALID_KEY"
}
Terminal window
# Test specific permission
curl -H "Authorization: Bearer mlm_sk_live_your_key..." \
https://api.mailiam.dev/analytics
# Test form submission
curl -X POST https://api.mailiam.dev/yourdomain.com/contact \
-H "X-Api-Key: mlm_sk_live_your_key..." \
-F "name=Test User" \
-F "email=test@example.com" \
-F "message=Test message"
Terminal window
# Check API key status
mailiam auth status --debug
# Test API connectivity
mailiam test config --check-api
# Validate permissions
mailiam auth permissions --key-id "key_abc123"

Monitor API key usage:

Terminal window
# View API usage
mailiam analytics api-usage --last-30d
# View by API key
mailiam analytics api-usage --key "mlm_sk_live_abc123" --last-7d
# Export usage data
mailiam analytics export --type api-usage --format csv

Track rate limit usage:

Terminal window
# Check current rate limits
curl -H "Authorization: Bearer mlm_sk_live_your_key..." \
https://api.mailiam.dev/rate-limits
# Response includes current usage
{
"rate_limits": {
"requests_per_hour": {
"limit": 5000,
"remaining": 4847,
"reset_time": "2024-01-01T15:00:00Z"
},
"requests_per_minute": {
"limit": 100,
"remaining": 92,
"reset_time": "2024-01-01T14:31:00Z"
}
}
}

Q: Can I use API keys in frontend JavaScript? A: Only for trusted environments. Use domain-based authentication for public websites.

Q: How do I rotate API keys without downtime? A: Create a new key, test it, update your applications, then revoke the old key.

Q: What happens if I exceed rate limits? A: You’ll receive a 429 Too Many Requests response. Implement exponential backoff.

Q: Can I restrict API keys to specific domains? A: Yes, use domain restrictions when creating keys.

Proper API authentication ensures secure access to mailiam’s services while maintaining the flexibility needed for various application architectures.