# Campaigns
NOTE
The URI for the API endpoint is often the same for multiple endpoints, the difference being in HTTP methods.
# List Campaigns
GET https://api.wolfeo.me/v1/campaigns
Returns a paginated list of broadcast campaigns, ordered by most recent first.
# Example Request
curl --request GET "https://api.wolfeo.me/v1/campaigns?status=sent&per_page=25" \
--header "Authorization: Bearer YOUR_API_KEY"
# Parameters
| Parameter | Type | Description |
|---|---|---|
| status | string | Filter by status (see possible values below) |
| period | string | Time range to filter by (see possible values below) |
| range | string | Custom date range โ only used when period=between |
| page | integer | Page number (default: 1) |
| per_page | integer | Results per page โ max 100 (default: 50) |
# Possible values for status
| Value | Description |
|---|---|
draft | Not yet sent |
sending | Currently being sent |
sent | Sent successfully |
scheduled | Scheduled for later |
error | Sending failed |
# Sample Return
{
"success": true,
"data": [
{
"id": 42,
"name": "June Newsletter",
"subject": "What's new this month ๐",
"from_name": "John",
"from_email": "john@example.com",
"status": "sent",
"sent_to": 1200,
"recipients_count": 1200,
"sent_at": "2024-06-01T10:00:00.000000Z",
"scheduled_for": null,
"created_at": "2024-05-28T09:00:00.000000Z"
}
],
"meta": {
"current_page": 1,
"last_page": 3,
"per_page": 50,
"total": 142
}
}
# Possible Errors
| Code | HTTP | Description |
|---|---|---|
| INVALID_STATUS | 400 | Invalid status value |
| INVALID_PERIOD | 400 | Invalid period or missing range |
# Retrieve Campaign
GET https://api.wolfeo.me/v1/campaign
# Example Request
curl --request GET "https://api.wolfeo.me/v1/campaign?campaign_id=42" \
--header "Authorization: Bearer YOUR_API_KEY"
# Parameters
| Parameter | Type | Description |
|---|---|---|
| campaign_id* | integer | The campaign ID |
* denotes a required parameter
# Sample Return
{
"success": true,
"data": {
"id": 42,
"name": "June Newsletter",
"subject": "What's new this month ๐",
"from_name": "John",
"from_email": "john@example.com",
"status": "sent",
"sent_to": 1200,
"recipients_count": 1200,
"sent_at": "2024-06-01T10:00:00.000000Z",
"scheduled_for": null,
"created_at": "2024-05-28T09:00:00.000000Z"
}
}
# Possible Errors
| Code | HTTP | Description |
|---|---|---|
| NOT_FOUND | 404 | Campaign not found |
# Retrieve Campaign Stats
GET https://api.wolfeo.me/v1/campaign-stats
Returns send statistics for a campaign. Stats are read from Redis in real time.
# Example Request
curl --request GET "https://api.wolfeo.me/v1/campaign-stats?campaign_id=42" \
--header "Authorization: Bearer YOUR_API_KEY"
# Parameters
| Parameter | Type | Description |
|---|---|---|
| campaign_id* | integer | The campaign ID |
* denotes a required parameter
# Sample Return
{
"success": true,
"data": {
"sent_to": 1200,
"opens": 480,
"clicks": 192,
"unsubscribes": 3,
"open_rate": 40.0,
"click_rate": 16.0,
"unsubscribe_rate": 0.3
}
}
# Possible Errors
| Code | HTTP | Description |
|---|---|---|
| NOT_FOUND | 404 | Campaign not found |
# Create Campaign
POST https://api.wolfeo.me/v1/campaign
Creates a broadcast campaign as a draft. Use Schedule Campaign to send or schedule it.
# Example Request
curl --request POST "https://api.wolfeo.me/v1/campaign" \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"name": "June Newsletter",
"subject": "What'\''s new this month ๐",
"from_name": "John",
"from_email": "john@example.com"
}'
# Parameters
| Parameter | Type | Description |
|---|---|---|
| name* | string | Internal name for the campaign |
| subject | string | Email subject line |
| from_name | string | Sender display name |
| from_email | string | Sender email address |
* denotes a required parameter
# Sample Return
HTTP 201 Created
{
"success": true,
"data": {
"id": 42,
"name": "June Newsletter",
"subject": "What's new this month ๐",
"from_name": "John",
"from_email": "john@example.com",
"status": "draft"
}
}
# Schedule Campaign
POST https://api.wolfeo.me/v1/campaign-schedule
Schedules an existing draft campaign for sending. The campaign will be sent to all contacts matching the specified filters at the given date and time.
# Example Request
curl --request POST "https://api.wolfeo.me/v1/campaign-schedule" \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"campaign_id": 42,
"scheduled_for": "2025-06-15T14:00:00",
"incl_tag_ids": [12, 34],
"excl_tag_ids": [56]
}'
# Parameters
| Parameter | Type | Description |
|---|---|---|
| campaign_id* | integer | ID of the draft campaign to schedule |
| scheduled_for* | string | Send date/time โ ISO 8601 or Y-m-d H:i, must be in future |
| send_to_all | boolean | Send to all contacts, ignoring filters (default: false) |
| incl_tag_ids | array | Only send to contacts with these tags |
| excl_tag_ids | array | Exclude contacts with these tags |
| incl_sequence_ids | array | Only send to contacts in these sequences |
| excl_sequence_ids | array | Exclude contacts in these sequences |
* denotes a required parameter
Timezone
scheduled_for is interpreted in your account's configured timezone (set in Settings โ Email). If no timezone is set, Europe/Paris is used.
# Sample Return
{
"success": true,
"data": {
"id": 42,
"status": "scheduled",
"scheduled_for": "2025-06-15 14:00:00"
}
}
# Possible Errors
| Code | HTTP | Description |
|---|---|---|
| NOT_FOUND | 404 | Campaign not found or already sent |
| INVALID_DATE | 400 | scheduled_for could not be parsed or is in the past |
# Update Campaign
PUT https://api.wolfeo.me/v1/campaign
Updates a draft campaign. Only campaigns with a draft status can be modified.
# Example Request
curl --request PUT "https://api.wolfeo.me/v1/campaign" \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"campaign_id": 42,
"subject": "Updated subject line",
"from_name": "Jane"
}'
# Parameters
| Parameter | Type | Description |
|---|---|---|
| campaign_id* | integer | The campaign ID to update |
| name | string | Internal name for the campaign |
| subject | string | Email subject line |
| from_name | string | Sender display name |
| from_email | string | Sender email address |
* denotes a required parameter
# Sample Return
{
"success": true,
"data": {
"id": 42,
"name": "June Newsletter",
"subject": "Updated subject line",
"from_name": "Jane",
"from_email": "john@example.com",
"status": "draft",
"updated": true
}
}
# Possible Errors
| Code | HTTP | Description |
|---|---|---|
| NOT_FOUND | 404 | Campaign not found or not a draft |
# Delete Campaign
DELETE https://api.wolfeo.me/v1/campaign
Permanently deletes a draft campaign. Scheduled campaigns cannot be deleted โ cancel the schedule first.
# Example Request
curl --request DELETE "https://api.wolfeo.me/v1/campaign" \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{"campaign_id": 42}'
# Parameters
| Parameter | Type | Description |
|---|---|---|
| campaign_id* | integer | The campaign ID to delete |
* denotes a required parameter
# Sample Return
{
"success": true,
"data": {
"deleted": true
}
}
# Possible Errors
| Code | HTTP | Description |
|---|---|---|
| NOT_FOUND | 404 | Campaign not found |
| CAMPAIGN_SCHEDULED | 409 | Campaign is scheduled and cannot be deleted |
# Send Campaign Immediately
POST https://api.wolfeo.me/v1/campaign-send
Sends an existing draft campaign immediately to the specified audience. Use Schedule Campaign to send at a future date instead.
# Example Request
curl --request POST "https://api.wolfeo.me/v1/campaign-send" \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"campaign_id": 42,
"incl_tag_ids": [12, 34],
"excl_tag_ids": [56]
}'
# Parameters
| Parameter | Type | Description |
|---|---|---|
| campaign_id* | integer | ID of the draft campaign to send |
| send_to_all | boolean | Send to all contacts, ignoring filters (default: false) |
| incl_tag_ids | array | Only send to contacts with these tags |
| excl_tag_ids | array | Exclude contacts with these tags |
| incl_sequence_ids | array | Only send to contacts in these sequences |
| excl_sequence_ids | array | Exclude contacts in these sequences |
* denotes a required parameter
# Sample Return
{
"success": true,
"data": {
"id": 42,
"status": "sending"
}
}
# Possible Errors
| Code | HTTP | Description |
|---|---|---|
| NOT_FOUND | 404 | Campaign not found or already sent |
# Preview Audience Size
GET https://api.wolfeo.me/v1/audience-count
Resolves the same audience filters as Send Campaign Immediately and returns how many contacts they match, without sending anything. Use it to check an audience before scheduling.
# Example Request
curl --request GET "https://api.wolfeo.me/v1/audience-count?incl_tag_ids[]=48&excl_tag_ids[]=51" \
--header "Authorization: Bearer YOUR_API_KEY"
# Parameters
All parameters are optional and repeatable arrays of ids. Sending none of them counts every contact in the account.
| Parameter | Type | Description |
|---|---|---|
| incl_tag_ids[] | array<int> | Contacts carrying any of these tags |
| excl_tag_ids[] | array<int> | Contacts carrying none of these tags |
| incl_sequence_ids[] | array<int> | Contacts enrolled in any of these sequences |
| excl_sequence_ids[] | array<int> | Contacts enrolled in none of these sequences |
| incl_opens_email_ids[] | array<int> | Contacts who opened any of these campaigns |
| excl_opens_email_ids[] | array<int> | Contacts who opened none of these campaigns |
| incl_not_opened_email_ids[] | array<int> | Contacts who did not open these campaigns |
| excl_not_opened_email_ids[] | array<int> | Excludes the contacts who did not open them |
| incl_clicks_email_ids[] | array<int> | Contacts who clicked any of these campaigns |
| excl_clicks_email_ids[] | array<int> | Contacts who clicked none of these campaigns |
| incl_not_clicked_email_ids[] | array<int> | Contacts who did not click these campaigns |
| excl_not_clicked_email_ids[] | array<int> | Excludes the contacts who did not click them |
# Sample Return
{
"success": true,
"data": {
"total": 142,
"opt_in": 138,
"filters": {
"filterWay": 1,
"lists": [],
"inclTags": [48],
"exclTags": [51],
"inclSeqs": [],
"exclSeqs": [],
"inclOpens": [],
"exclOpens": [],
"inclNotOpened": [],
"exclNotOpened": [],
"inclClicks": [],
"exclClicks": [],
"inclNotClicked": [],
"exclNotClicked": []
}
}
}
TIP
total is every matching contact, opt_in the subset that is still subscribed. Only
opt_in would actually receive the campaign, so it is the number to compare against
your sending quota. filters echoes the resolved filter set back, which is useful to
confirm that a parameter was understood.
# Possible Errors
| Code | HTTP | Description |
|---|---|---|
| VALIDATION_ERROR | 422 | A filter is not an array of integers |
| UNAUTHORIZED | 401 | Invalid or missing API key |
# Retrieve Deliverability Stats
GET https://api.wolfeo.me/v1/deliverability-stats
Account-wide sending health over a rolling window: everything sent, opened, clicked and unsubscribed across all campaigns, rolled up in one call.
# Example Request
curl --request GET "https://api.wolfeo.me/v1/deliverability-stats?days=30" \
--header "Authorization: Bearer YOUR_API_KEY"
# Parameters
| Parameter | Type | Description |
|---|---|---|
| days | integer | Window length, 1 to 365 (default: 30) |
# Sample Return
{
"success": true,
"data": {
"period_days": 30,
"since": "2026-04-24 00:00:00",
"sent": 21722,
"unique_opens": 3646,
"unique_clicks": 232,
"unsubscribes": 186,
"open_rate": 0.1678,
"click_rate": 0.0107,
"unsubscribe_rate": 0.0086,
"bounce_rate": null,
"complaint_rate": null
}
}
TIP
Rates are ratios, not percentages: 0.1678 is 16.78%. Opens and clicks are counted per
unique contact, so a contact who opens the same campaign five times counts once.
WARNING
bounce_rate and complaint_rate are always null. Wolfeo does not ingest bounce
events yet, and the fields are reserved so they can be populated later without a
breaking change. Treat null as "not measured", never as zero.
# Possible Errors
| Code | HTTP | Description |
|---|---|---|
| VALIDATION_ERROR | 422 | days is below 1 or above 365 |
| UNAUTHORIZED | 401 | Invalid or missing API key |