API dokumentácia
Kompletná referencia REST API – endpointy, autentifikácia, webhooky a chybové kódy.
Authentication
All API requests require authentication using an API key. Include your API key in the X-API-Key header:
X-API-Key: your-api-key-here
Obtaining an API Key
API keys can be generated through the admin dashboard or via the admin API endpoints (requires Sanctum authentication).
API Key Properties
| Property | Description |
|---|---|
name |
A descriptive name for the key |
permissions |
Array of allowed operations (or ["*"] for full access) |
expires_at |
Optional expiration date |
rate_limit |
Custom rate limit per minute (default: 60) |
Example Request
curl -X GET "https://mail.example.com/api/v1/subscribers" \
-H "X-API-Key: your-api-key-here" \
-H "Content-Type: application/json" \
-H "Accept: application/json"
Rate Limiting
API requests are rate-limited to prevent abuse. The default limit is 60 requests per minute per API key.
Rate Limit Headers
Every response includes rate limit information:
| Header | Description |
|---|---|
X-RateLimit-Limit |
Maximum requests per window |
X-RateLimit-Remaining |
Remaining requests in current window |
X-RateLimit-Reset |
Unix timestamp when the window resets |
Rate Limit Exceeded
When the rate limit is exceeded, you'll receive a 429 Too Many Requests response:
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please slow down and try again later.",
"status": 429,
"rate_limit": 60,
"retry_after": 45
}
}
The Retry-After header indicates how many seconds to wait before making another request.
Error Handling
All API responses follow a consistent format:
Success Response
{
"success": true,
"data": { ... },
"message": "Operation completed successfully."
}
Error Response
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message.",
"status": 400,
"details": { ... }
}
}
Error Codes
| Code | HTTP Status | Description |
|---|---|---|
API_KEY_MISSING |
401 | No API key provided in request |
INVALID_API_KEY |
401 | API key is invalid or revoked |
API_KEY_EXPIRED |
403 | API key has expired |
UNAUTHORIZED |
401 | Authentication required |
FORBIDDEN |
403 | Permission denied for this operation |
NOT_FOUND |
404 | Resource not found |
VALIDATION_ERROR |
422 | Request validation failed |
CONFLICT |
409 | Resource conflict (e.g., duplicate) |
RATE_LIMIT_EXCEEDED |
429 | Too many requests |
SERVER_ERROR |
500 | Internal server error |
Validation Error Details
When validation fails, the details field contains field-specific errors:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The given data was invalid.",
"status": 422,
"details": {
"email": ["The email field is required."],
"name": ["The name must be at least 2 characters."]
}
}
}
Endpoints
Subscribers
Manage email subscribers in your mailing lists.
Create Subscriber
POST /api/v1/subscribers
Request Body:
{
"email": "john@example.com",
"first_name": "John",
"last_name": "Doe",
"lists": ["01HN...ULID1", "01HN...ULID2"],
"tags": ["01HN...ULID3"],
"custom_fields": {
"company": "Acme Inc",
"role": "Developer"
}
}
Response (201 Created):
{
"success": true,
"data": {
"id": "01HN...ULID",
"email": "john@example.com",
"first_name": "John",
"last_name": "Doe",
"status": "active",
"confirmed_at": null,
"lists": [...],
"tags": [...],
"custom_fields": {...},
"created_at": "2024-01-15T10:30:00Z"
}
}
Get Subscriber
GET /api/v1/subscribers/{email_or_ulid}
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
include |
string | Comma-separated relations: lists,tags |
Response:
{
"data": {
"id": "01HN...ULID",
"email": "john@example.com",
"first_name": "John",
"last_name": "Doe",
"status": "active",
"confirmed_at": "2024-01-15T11:00:00Z",
"lists": [
{"id": "01HN...ULID", "name": "Newsletter"}
],
"tags": [
{"id": "01HN...ULID", "name": "VIP"}
],
"created_at": "2024-01-15T10:30:00Z"
}
}
Update Subscriber
PUT /api/v1/subscribers/{email_or_ulid}
Request Body:
{
"first_name": "Jane",
"custom_fields": {
"company": "New Company"
}
}
Delete Subscriber
DELETE /api/v1/subscribers/{email_or_ulid}
Marks the subscriber as unsubscribed. Does not permanently delete the record.
Add Tags to Subscriber
POST /api/v1/subscribers/{email_or_ulid}/tags
Request Body:
{
"tags": ["01HN...ULID1", "01HN...ULID2"]
}
Response:
{
"success": true,
"message": "Tags processed successfully.",
"data": {
"subscriber": "01HN...ULID",
"attached": ["01HN...ULID1"],
"skipped": ["01HN...ULID2"]
}
}
Remove Tag from Subscriber
DELETE /api/v1/subscribers/{email_or_ulid}/tags/{tag_ulid}
Add Subscriber to Lists
POST /api/v1/subscribers/{email_or_ulid}/lists
Request Body:
{
"lists": ["01HN...ULID1", "01HN...ULID2"]
}
Remove Subscriber from List
DELETE /api/v1/subscribers/{email_or_ulid}/lists/{list_ulid}
Lists
Manage mailing lists.
List All Mailing Lists
GET /api/v1/lists
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
search |
string | Search by name |
double_optin |
boolean | Filter by opt-in type |
with_count |
boolean | Include subscriber counts |
per_page |
integer | Items per page (max: 100) |
sort |
string | Sort field: name, created_at |
direction |
string | Sort direction: asc, desc |
Create List
POST /api/v1/lists
Request Body:
{
"name": "Weekly Newsletter",
"description": "Our weekly updates and tips",
"double_optin": true,
"welcome_email_template_id": "01HN...ULID"
}
Get List
GET /api/v1/lists/{ulid}
Update List
PUT /api/v1/lists/{ulid}
Delete List
DELETE /api/v1/lists/{ulid}
Get List Subscribers
GET /api/v1/lists/{ulid}/subscribers
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by status: active, unsubscribed, bounced |
confirmed |
boolean | Filter by confirmation status |
email |
string | Search by email |
per_page |
integer | Items per page (max: 100) |
Tags
Manage subscriber tags for segmentation.
List All Tags
GET /api/v1/tags
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
search |
string | Search by name or slug |
with_count |
boolean | Include subscriber counts |
per_page |
integer | Items per page (max: 100) |
Create Tag
POST /api/v1/tags
Request Body:
{
"name": "VIP Customer",
"color": "#FF5733"
}
Get Tag
GET /api/v1/tags/{ulid}
Update Tag
PUT /api/v1/tags/{ulid}
Delete Tag
DELETE /api/v1/tags/{ulid}
Campaigns
Manage and send email campaigns.
List Campaigns
GET /api/v1/campaigns
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter: draft, scheduled, sending, sent, cancelled |
list |
string | Filter by list ULID |
search |
string | Search by name or subject |
from |
datetime | Created after date |
to |
datetime | Created before date |
per_page |
integer | Items per page (max: 100) |
Create Campaign
POST /api/v1/campaigns
Request Body:
{
"name": "January Newsletter",
"subject": "New Year, New Features!",
"from_name": "Your Company",
"from_email": "news@example.com",
"reply_to": "support@example.com",
"list_id": "01HN...ULID",
"template_id": "01HN...ULID",
"content": {
"html": "<html>...</html>",
"text": "Plain text version..."
}
}
Get Campaign
GET /api/v1/campaigns/{ulid}
Get Campaign Statistics
GET /api/v1/campaigns/{ulid}/stats
Response:
{
"data": {
"campaign_id": "01HN...ULID",
"sent": 10000,
"delivered": 9850,
"bounced": 150,
"opened": 4500,
"clicked": 1200,
"unsubscribed": 25,
"complained": 2,
"open_rate": 45.69,
"click_rate": 12.18,
"bounce_rate": 1.5,
"unsubscribe_rate": 0.25
}
}
Trigger Campaign Send
POST /api/v1/campaigns/{ulid}/send
Immediately queues the campaign for sending. Only works for draft or scheduled campaigns.
Response:
{
"success": true,
"message": "Campaign has been queued for sending.",
"data": {
"id": "01HN...ULID",
"status": "sending",
"sent_at": "2024-01-15T14:30:00Z"
}
}
Sequences
Manage automated email sequences (drip campaigns).
List Sequences
GET /api/v1/sequences
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
active |
boolean | Filter by active status |
trigger_type |
string | Filter by trigger type |
list |
string | Filter by list ULID |
search |
string | Search by name |
with_count |
boolean | Include subscriber/step counts |
per_page |
integer | Items per page (max: 100) |
Get Sequence
GET /api/v1/sequences/{ulid}
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
include |
string | Include relations: steps,list,subscribers |
with_count |
boolean | Include counts |
Enroll Subscriber in Sequence
POST /api/v1/sequences/{ulid}/subscribers
Request Body:
{
"subscriber": "01HN...SUBSCRIBER_ULID"
}
or
{
"email": "john@example.com"
}
Response:
{
"success": true,
"message": "Subscriber has been enrolled in the sequence.",
"data": {
"sequence": "01HN...ULID",
"subscriber": "01HN...ULID"
}
}
Remove Subscriber from Sequence
DELETE /api/v1/sequences/{ulid}/subscribers/{subscriber_email_or_ulid}
Events
Record custom events to trigger automations.
Record Custom Event
POST /api/v1/events
This endpoint allows you to track custom events that can trigger automations, sequences, or be used for segmentation.
Request Body:
{
"subscriber_email": "john@example.com",
"event_name": "purchase_completed",
"properties": {
"product_id": "SKU-12345",
"product_name": "Premium Plan",
"amount": 99.99,
"currency": "USD"
}
}
Event Name Format:
- Must be in
snake_caseformat - Only lowercase letters, numbers, and underscores allowed
- Maximum 100 characters
Response (201 Created):
{
"success": true,
"message": "Event recorded successfully.",
"data": {
"id": "01HN...ULID",
"event_name": "purchase_completed",
"properties": {
"product_id": "SKU-12345",
"product_name": "Premium Plan",
"amount": 99.99,
"currency": "USD"
},
"source": "api",
"occurred_at": "2024-01-15T14:30:00Z",
"created_at": "2024-01-15T14:30:00Z"
}
}
Common Event Examples:
| Event Name | Description |
|---|---|
purchase_completed |
Customer completed a purchase |
trial_started |
User started a free trial |
trial_ended |
Trial period ended |
subscription_upgraded |
Customer upgraded their plan |
subscription_cancelled |
Customer cancelled subscription |
webinar_registered |
User registered for webinar |
webinar_attended |
User attended webinar |
form_submitted |
User submitted a form |
product_viewed |
User viewed a product |
cart_abandoned |
User abandoned their cart |
Webhook Events
The mailing system sends webhooks for various events. Configure webhook endpoints in the admin dashboard.
Webhook Payload Structure
{
"event": "subscriber.created",
"timestamp": "2024-01-15T14:30:00Z",
"data": {
// Event-specific data
},
"signature": "sha256=..."
}
Verifying Webhook Signatures
Webhooks are signed using HMAC-SHA256. Verify the signature by:
- Get the
X-Webhook-Signatureheader - Compute HMAC-SHA256 of the raw body using your webhook secret
- Compare with the signature header
$signature = hash_hmac('sha256', $rawBody, $webhookSecret);
$isValid = hash_equals($signature, $headerSignature);
Available Webhook Events
| Event | Description |
|---|---|
subscriber.created |
New subscriber added |
subscriber.updated |
Subscriber data updated |
subscriber.unsubscribed |
Subscriber unsubscribed |
subscriber.confirmed |
Subscriber confirmed (double opt-in) |
campaign.sent |
Campaign finished sending |
campaign.opened |
Email opened |
campaign.clicked |
Link clicked |
bounce.received |
Email bounced |
complaint.received |
Spam complaint received |
sequence.completed |
Subscriber completed sequence |
event.recorded |
Custom event recorded |
Webhook Retry Policy
Failed webhook deliveries are retried with exponential backoff:
- Attempt 1: Immediate
- Attempt 2: 5 minutes
- Attempt 3: 30 minutes
- Attempt 4: 2 hours
- Attempt 5: 24 hours
After 5 failed attempts, the webhook is marked as failed and no further retries are made.
Pagination
List endpoints support pagination using the following query parameters:
| Parameter | Description | Default |
|---|---|---|
page |
Page number | 1 |
per_page |
Items per page | 15 (max: 100) |
Pagination Response
{
"data": [...],
"links": {
"first": "https://mail.example.com/api/v1/subscribers?page=1",
"last": "https://mail.example.com/api/v1/subscribers?page=10",
"prev": null,
"next": "https://mail.example.com/api/v1/subscribers?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 10,
"per_page": 15,
"to": 15,
"total": 150
}
}
Filtering and Sorting
Most list endpoints support filtering and sorting:
Common Filter Parameters
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by status |
search |
string | Search by name/email |
created_from |
datetime | Created after date |
created_to |
datetime | Created before date |
Sorting
| Parameter | Type | Description |
|---|---|---|
sort |
string | Field to sort by |
direction |
string | asc or desc |
Example
GET /api/v1/subscribers?status=active&sort=created_at&direction=desc&per_page=25
SDKs and Libraries
Official SDKs are available for popular programming languages:
- PHP:
composer require expirator/mailing-php - JavaScript/Node.js:
npm install @expirator/mailing-js - Python:
pip install expirator-mailing
Support
For API support, contact us at:
- Email: api-support@example.com
- Documentation: https://docs.example.com
- Status Page: https://status.example.com