# 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

# What's next

  • Contacts โ€” manage contacts and their email stats
  • Sequences โ€” create and manage automated sequences