The MailSignal API allows you to programmatically create and manage email tracking pixels, retrieve analytics, and set up webhooks for real-time notifications.
Download our ready-to-use Postman collection with all API endpoints
Test API endpoints directly from your browser with your API key
All API requests require authentication using an API key. You can create and manage API keys in your dashboard settings.
Include your API key in the Authorization header:
Authorization: Bearer ms_live_xxxxxxxxxxxxxxxxxxxx🔒 Security Note: Never expose your API keys in client-side code. Always make API calls from your backend server.
https://mailsignal.eu/api/v1API requests are rate limited based on your subscription plan:
| Plan | Limit |
|---|---|
| Free | 100 requests/minute |
| Pro | 1,000 requests/minute |
| Team | 10,000 requests/minute |
Rate limit info is included in response headers: X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset
Tracks represent individual email tracking pixels. Each track generates a unique pixel URL that you embed in your emails.
/tracksCreate a new tracking pixel for an email.
| Parameter | Type | Required | Description |
|---|---|---|---|
| recipient | string | Yes | Recipient email address |
| subject | string | No | Email subject line |
| campaign | string | No | Campaign identifier for grouping |
curl -X POST https://mailsignal.eu/api/v1/tracks \
-H "Authorization: Bearer ms_live_xxxx" \
-H "Content-Type: application/json" \
-d '{
"recipient": "john@example.com",
"subject": "Meeting Tomorrow",
"campaign": "sales-outreach"
}'const response = await fetch('https://mailsignal.eu/api/v1/tracks', {
method: 'POST',
headers: {
'Authorization': 'Bearer ms_live_xxxx',
'Content-Type': 'application/json',
},
body: JSON.stringify({
recipient: 'john@example.com',
subject: 'Meeting Tomorrow',
campaign: 'sales-outreach',
}),
});
const track = await response.json();
console.log(track.pixelUrl); // Use this in your emailimport requests
response = requests.post(
'https://mailsignal.eu/api/v1/tracks',
headers={
'Authorization': 'Bearer ms_live_xxxx',
'Content-Type': 'application/json',
},
json={
'recipient': 'john@example.com',
'subject': 'Meeting Tomorrow',
'campaign': 'sales-outreach',
}
)
track = response.json()
print(track['pixelUrl']) # Use this in your email<?php
$ch = curl_init('https://mailsignal.eu/api/v1/tracks');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ms_live_xxxx',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'recipient' => 'john@example.com',
'subject' => 'Meeting Tomorrow',
'campaign' => 'sales-outreach',
]),
]);
$response = curl_exec($ch);
$track = json_decode($response, true);
echo $track['pixelUrl']; // Use this in your email{
"id": "trk_abc123xyz",
"recipient": "john@example.com",
"subject": "Meeting Tomorrow",
"campaign": "sales-outreach",
"pixelUrl": "https://mailsignal.eu/api/t/trk_abc123xyz",
"createdAt": "2025-01-28T07:00:00Z",
"opens": []
}Add the pixel URL as an invisible image in your HTML email:
<img src="https://mailsignal.eu/api/t/trk_abc123xyz"
width="1" height="1" style="display:none" alt="" />/tracksList all tracks with optional filtering.
| limit | Number of tracks to return (default: 50, max: 100) |
| cursor | Pagination cursor from previous response |
| campaign | Filter by campaign name |
| opened | Filter by open status (true/false) |
| from/to | Date range filter (ISO 8601) |
curl "https://mailsignal.eu/api/v1/tracks?limit=20&campaign=sales-outreach&opened=true" \
-H "Authorization: Bearer ms_live_xxxx"/tracks/:idGet detailed information about a specific track including all opens.
curl "https://mailsignal.eu/api/v1/tracks/trk_abc123xyz" \
-H "Authorization: Bearer ms_live_xxxx"{
"id": "trk_abc123xyz",
"recipient": "john@example.com",
"subject": "Meeting Tomorrow",
"campaign": "sales-outreach",
"createdAt": "2025-01-28T07:00:00Z",
"openCount": 3,
"clickCount": 1,
"opens": [
{
"timestamp": "2025-01-28T09:15:00Z",
"emailClient": "Gmail",
"device": "iPhone",
"location": {
"city": "Berlin",
"country": "Germany"
}
},
{
"timestamp": "2025-01-28T14:30:00Z",
"emailClient": "Outlook",
"device": "Desktop",
"location": {
"city": "Berlin",
"country": "Germany"
}
}
]
}/analyticsGet aggregated analytics for your email tracking.
| period | Time period: 7d, 30d, 90d, 1y (default: 30d) |
| campaign | Filter by campaign |
| groupBy | Group results: day, week, month |
curl "https://mailsignal.eu/api/v1/analytics?period=30d&groupBy=day" \
-H "Authorization: Bearer ms_live_xxxx"{
"period": "30d",
"summary": {
"totalTracks": 150,
"totalOpens": 89,
"uniqueOpens": 72,
"openRate": 48.0,
"totalClicks": 23,
"clickRate": 15.3
},
"emailClients": {
"Gmail": 45,
"Outlook": 28,
"Apple Mail": 16
},
"devices": {
"Desktop": 52,
"Mobile": 35,
"Tablet": 2
},
"timeline": [
{ "date": "2025-01-01", "opens": 5, "tracks": 12 },
{ "date": "2025-01-02", "opens": 8, "tracks": 15 }
]
}Receive real-time notifications when emails are opened or links are clicked.
/webhooksCreate a new webhook endpoint.
| url | Your webhook endpoint URL (HTTPS required) |
| events | Array of events: email.opened, link.clicked |
| secret | Optional secret for signature verification |
curl -X POST https://mailsignal.eu/api/v1/webhooks \
-H "Authorization: Bearer ms_live_xxxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yoursite.com/webhooks/mailsignal",
"events": ["email.opened", "link.clicked"],
"secret": "whsec_your_secret_key"
}'When an event occurs, we'll send a POST request to your webhook URL:
{
"event": "email.opened",
"timestamp": "2025-01-28T09:15:00Z",
"data": {
"trackId": "trk_abc123xyz",
"recipient": "john@example.com",
"subject": "Meeting Tomorrow",
"campaign": "sales-outreach",
"openNumber": 1,
"emailClient": "Gmail",
"device": "iPhone",
"location": {
"city": "Berlin",
"country": "Germany"
}
}
}Verify webhooks using the X-MailSignal-Signature header:
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(`sha256=${expectedSignature}`)
);
}| Status | Code | Description |
|---|---|---|
| 200 | OK | Request successful |
| 201 | Created | Resource created successfully |
| 400 | Bad Request | Invalid request parameters |
| 401 | Unauthorized | Invalid or missing API key |
| 403 | Forbidden | Quota exceeded or insufficient permissions |
| 404 | Not Found | Resource not found |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Server Error | Internal server error |
Official SDKs coming soon. In the meantime, use our REST API directly with any HTTP client.
Our team is here to help you integrate MailSignal into your application.
Contact Support