What this is for
The complete reference for AcelleMail's REST API. Use this alongside the Getting Started guide — this article is the lookup table.
Base URL: https://mail.example.com/api/v1/
Auth: token (see below) — every authenticated route requires it
Format: request Content-Type: application/json (POST/PATCH/PUT) + Accept: application/json on every request
Authentication
AcelleMail uses Laravel's auth:api driver — a simple bearer-token scheme.
Get a token
Two methods:
- UI: Profile → API Token → Generate / Copy
- API:
POST /api/v1/user/login(unauthenticated):POST /api/v1/user/login email=you@example.com&password=Yours → 200 OK { "api_token": "..." }
Send the token
Either is valid:
| Method | Format | Use when |
|---|---|---|
| Header (preferred) | Authorization: Bearer <token> |
Production. Doesn't leak to access logs. |
| Query param | ?api_token=<token> |
Quick CLI tests. Avoid in production. |
Scoping rules
A token is tied to one user, and inherits their scope:
- Customer user token → can read/write only resources owned by that customer (their lists, campaigns, subscribers, automations)
- Admin user token → can additionally hit admin-only endpoints (
/customers,/subscriptions,/sending_serverscreate/edit)
You cannot impersonate another user. To act as a customer, log in as that customer and use their token.
Conventions
- UIDs vs IDs: every resource has both an integer
id(DB primary key) and a stringuid(URL-safe, opaque). Routes useuid(e.g./lists/{uid}/subscribers). Responses include both. - Pagination: list endpoints return paginated responses with
data,current_page,per_page,total,last_page. Use?page=2&per_page=50to navigate (maxper_pagetypically 100). - Filtering: most list endpoints support
?filter[field]=valuestyle filters; specific allowed filters vary per endpoint. - Errors: standard Laravel error responses —
422for validation,404for missing,401for auth,403for forbidden,500for server error. Body includesmessage+ (on 422)errors[]. - Timestamps: ISO 8601 UTC strings (
2026-05-16T14:32:11.000000Z).
Resources
Public (unauthenticated)
Subscribers — public signup form
POST /api/v1/public/subscribers
Content-Type: application/json
{
"MAIL_LIST_UID": "abc123",
"EMAIL": "alice@example.com",
"FIRST_NAME": "Alice",
"LAST_NAME": "Doe",
...custom fields per the list schema...
}
→ 200 OK
{ "uid": "subUID", "status": "subscribed" }
The only public endpoint. Use it for signup forms on your marketing site — no token needed.
Add rate limiting at the nginx level to defend against spam bots (see post-install hardening).
Authentication + identity
| Endpoint | Method | Description |
|---|---|---|
/me |
GET | Current authenticated user + their customer |
/whoami |
GET | Lighter-weight identity check (id + email only) |
/user/login |
POST | Exchange email+password for an api_token (unauthenticated) |
/user/info |
GET | Same as /me (legacy alias) |
/dashboard |
GET | Customer's dashboard summary stats |
Lists
| Endpoint | Method | Description |
|---|---|---|
/lists |
GET | List all subscriber lists owned by current customer |
/lists |
POST | Create a new subscriber list |
/lists/{uid} |
GET | Get a specific list |
/lists/{uid} |
PUT/PATCH | Update list fields |
/lists/{uid} |
DELETE | Delete a list (with all its subscribers) |
/lists/{uid}/add-field |
POST | Add a custom field to the list |
Create example:
POST /api/v1/lists
{
"name": "Newsletter Q2",
"from_email": "news@example.com",
"from_name": "Example Team",
"default_subject": "Update from Example",
"contact": {
"company": "Example Co",
"address_1": "123 Main St",
"city": "San Francisco",
"country_id": 234,
"url": "https://example.com"
}
}
→ 201 Created
{ "uid": "newListUID", "name": "Newsletter Q2", ... }
Subscribers
| Endpoint | Method | Description |
|---|---|---|
/subscribers |
GET | List subscribers (paginated) — filter via ?list_uid= |
/subscribers |
POST | Add a new subscriber to a list |
/subscribers/{id} |
GET | Get a subscriber by id |
/subscribers/{id} |
PATCH | Update subscriber fields |
/subscribers/{id} |
DELETE | Delete a subscriber |
/subscribers/email/{email} |
GET | Find subscriber by email address |
/lists/{list_uid}/subscribers/{id}/subscribe |
PATCH | Mark subscribed |
/lists/{list_uid}/subscribers/{id}/unsubscribe |
PATCH | Mark unsubscribed |
/lists/{list_uid}/subscribers/email/{email}/unsubscribe |
PATCH | Unsubscribe by email (no id lookup needed) |
/subscribers/{id}/add-tag |
POST | Tag a subscriber |
/subscribers/{id}/remove-tag |
POST | Untag a subscriber |
Add subscriber:
POST /api/v1/subscribers
{
"MAIL_LIST_UID": "abc123",
"EMAIL": "alice@example.com",
"FIRST_NAME": "Alice"
}
→ 201 Created
{ "uid": "subUID", "email": "alice@example.com", "status": "subscribed" }
Campaigns
| Endpoint | Method | Description |
|---|---|---|
/campaigns |
GET | List campaigns (paginated) |
/campaigns |
POST | Create a new campaign |
/campaigns/{uid} |
GET | Get campaign details + stats |
/campaigns/{uid} |
PATCH | Update campaign fields (only allowed before "running") |
/campaigns/{uid} |
DELETE | Delete a campaign |
/campaigns/{uid}/run |
POST | Start sending the campaign |
/campaigns/{uid}/pause |
POST | Pause an in-progress send |
/campaigns/{uid}/resume |
POST | Resume a paused campaign |
/campaigns/{uid}/tracking-log/download |
GET | Download tracking event log (CSV) |
/campaigns/{uid}/open-log/download |
GET | Download open events (CSV) |
/campaigns/{uid}/click-log/download |
GET | Download click events (CSV) |
/campaigns/{uid}/bounce-log/download |
GET | Download bounce events (CSV) |
/campaigns/{uid}/feedback-log/download |
GET | Download spam-complaint events (CSV) |
/campaigns/{uid}/unsubscribe-log/download |
GET | Download unsubscribe events (CSV) |
Automations
| Endpoint | Method | Description |
|---|---|---|
/automations |
GET | List automations |
/automations/{uid}/api/call |
POST | Trigger an "API trigger" inside an automation (start a subscriber down the flow) |
/automations/{uid}/execute |
POST | Manually fire the automation for a given subscriber |
The api/call endpoint is what powers the API trigger feature — your external app POSTs to this URL to begin an automation flow for a specific subscriber.
Sending servers
| Endpoint | Method | Description |
|---|---|---|
/sending_servers |
GET | List sending servers (admin only) |
/sending_servers |
POST | Create sending server (admin only) |
/sending_servers/{uid} |
GET / PATCH / DELETE | Standard resource ops |
Customers (admin only)
| Endpoint | Method | Description |
|---|---|---|
/customers |
GET | List all customers |
/customers |
POST | Create a new customer |
/customers/{uid} |
GET / PATCH / DELETE | Standard resource ops |
/customers/by-email/{email} |
GET | Find customer by email |
/customers/{uid}/disable |
PATCH | Suspend the customer |
/customers/{uid}/enable |
PATCH | Reactivate |
/customers/{uid}/assign-plan/{plan_uid} |
POST | Assign a plan |
/customers/{uid}/change-plan/{plan_uid} |
POST | Change current plan |
/customers/{uid}/subscription/update |
POST | Update subscription metadata |
/login-token |
GET/POST | Generate a temporary login URL for impersonation (admin debugging) |
Subscriptions (admin only)
| Endpoint | Method | Description |
|---|---|---|
/subscriptions |
GET / POST | List / create subscription records |
/subscriptions/{uid} |
GET / PATCH / DELETE | Standard resource ops |
Notifications (sending-provider webhook inbound)
These endpoints receive webhooks from the sending provider (SES SNS, Mailgun, SendGrid event hooks) — you don't typically call them directly:
| Endpoint | Method | Description |
|---|---|---|
/notification/bounce |
POST | Sending provider posts bounce events here |
/notification/feedback |
POST | Sending provider posts complaint events here |
File upload + management
| Endpoint | Method | Description |
|---|---|---|
/file/upload |
POST | Upload a file (for use in email templates / campaigns) |
/filemanager/list |
GET | List uploaded files |
/filemanager/upload |
POST | Upload to file manager |
/filemanager/delete |
DELETE | Delete uploaded file |
/filemanager/rename |
PATCH | Rename |
/filemanager/view |
GET | Read file contents |
System / admin
| Endpoint | Method | Description |
|---|---|---|
/plugins/install |
POST | Install a plugin from zip (admin only) |
/upgrade/run |
POST | Run an upgrade from a URL |
/upgrade/run-file |
POST | Run an upgrade from an uploaded .bin patch file |
/upgrade/finalize |
POST | Run post-upgrade tasks |
/license/refresh |
POST | Re-check the CodeCanyon license |
Common patterns
Paginated list
# Get page 2, 50 per page
curl -H "Authorization: Bearer $TOKEN" \
"https://mail.example.com/api/v1/subscribers?page=2&per_page=50&filter[list_uid]=abc123"
Create then add many subscribers
# 1. Create the list
LIST_UID=$(curl -s -X POST ... /api/v1/lists -d '...' | jq -r .uid)
# 2. Bulk-add subscribers (loop or batch via the import flow for > 1000)
for email in $(cat emails.txt); do
curl -X POST ... /api/v1/subscribers \
-d "MAIL_LIST_UID=$LIST_UID&EMAIL=$email"
done
For > 1000 subscribers, use the list-import flow — much faster than per-subscriber POST.
Send a one-off campaign via API
# 1. Create the campaign
CAMP_UID=$(curl -s -X POST ... /api/v1/campaigns -d '{
"name": "Q2 Newsletter",
"type": "regular",
"subject": "Our June updates",
"from_email": "news@example.com",
"from_name": "Example",
"html_content": "<h1>Hi {FIRST_NAME}</h1>...",
"mail_list_uid": "abc123",
"sign_dkim": true,
"track_open": true,
"track_click": true
}' | jq -r .uid)
# 2. Start sending
curl -X POST -H "Authorization: Bearer $TOKEN" \
"https://mail.example.com/api/v1/campaigns/$CAMP_UID/run"
Trigger an automation
# Customer X just bought a product; start them on the post-purchase flow
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"EMAIL": "buyer@example.com",
"FIRST_NAME": "Buyer",
"product_name": "Widget Pro",
"purchase_amount": 99.00
}' \
https://mail.example.com/api/v1/automations/AUTOMATION_UID/api/call
The custom fields (product_name, purchase_amount) are available as merge tags inside the automation's emails.
Error reference
| HTTP code | Meaning | Common cause |
|---|---|---|
200 |
OK | Success |
201 |
Created | Resource created (POST) |
204 |
No Content | Success with no response body |
400 |
Bad Request | Malformed JSON, missing required header |
401 |
Unauthenticated | Missing/expired token |
403 |
Forbidden | Token valid but lacks permission (e.g. customer trying admin endpoint) |
404 |
Not Found | UID/email not found, or endpoint typo |
415 |
Unsupported Media Type | Missing Accept: application/json header |
422 |
Unprocessable Entity | Validation failed; response includes errors[] per-field |
429 |
Too Many Requests | Rate limit hit (if configured) |
500 |
Internal Server Error | Server bug; check storage/logs/laravel.log |
A typical 422 looks like:
{
"message": "The given data was invalid.",
"errors": {
"EMAIL": ["The EMAIL field is required."],
"MAIL_LIST_UID": ["The selected MAIL_LIST_UID is invalid."]
}
}
Tips for production use
- Log every API call's request id (Laravel emits one per request in the response headers) for traceable debugging
- Set request timeout in your client to ≥ 30 seconds — bulk operations (large list creation, campaign run) can take that long
- Retry on 5xx with exponential backoff; don't retry on 4xx (it'll just fail again)
- Never log the token itself — sanitize before logging headers
- Rotate the token quarterly by regenerating in the UI
FAQ
Is the API stable across Acelle versions? v1 has been stable across multiple major releases. Additive changes (new fields, new endpoints) are common; breaking changes are rare and pre-announced in acellemail-updates.
Is there an OpenAPI / Swagger spec? Not officially shipped. Build by introspecting routes/api.php and generating from controller signatures.
Does the API support GraphQL? No — REST only.
Can the API run a campaign for me without an existing list? No — campaigns must reference a mail_list_uid that already exists. Create the list first.
What's the difference between id and uid? id is the DB primary key (integer); uid is the URL-safe string identifier. Always use uid in routes; you'll see both in responses.
Webhooks? Different system from the API. See Webhook Events Reference for outbound events your app can subscribe to.
Related articles
- Getting Started with the AcelleMail REST API — the 5-minute kickoff (start here if you haven't)
- Webhook Events Reference — outbound events
- Extending AcelleMail Source Code — when the API isn't enough
- Using API Triggers for Custom Automation Workflows — the
/automations/{uid}/api/calluse case - Zapier Integration Guide — no-code API client
- Importing Contacts: CSV Best Practices and Field Mapping — for bulk subscriber adds
- Setting Up AcelleMail as a SaaS Platform — per-customer API tokens
- Post-Install Hardening Checklist — securing the API surface
3 bình luận