Skip to main content
The Campaigns API lets you programmatically manage the audience and message delivery of evergreen (continuous) campaigns in your BluBash workspace. You can add contacts individually or in bulk with per-contact scheduling, cancel queued messages before they are sent, and inspect message status at any point in the delivery lifecycle.
The Campaigns feature must be enabled on your workspace subscription to use the write endpoints. Read endpoints (list and get messages) may work even without the feature enabled. If you attempt a write operation without the feature, you will receive a 403 Forbidden response.

Base URL

https://api.blubash.io/api/v1/campaigns

Authentication

All requests require your Workspace API Key in the X-API-Key header.
X-API-Key: your_workspace_api_key
Content-Type: application/json
To obtain your API key, go to Settings → API Keys in your workspace admin panel.

Prerequisites

Evergreen campaigns must be created and configured in the BluBash platform before you can use this API. The API covers audience ingestion and message dispatch only.
1

Create an evergreen campaign in the platform

In the BluBash admin panel, create a new campaign with kind = EVERGREEN.
2

Configure channel, message, and rate limits

Set up the channel, message template, and rate limit rules for the campaign.
3

Copy the campaignId

Save the campaign and copy the campaignId shown in the platform. You will use this ID in every API call below.

Add contacts to audience

POST /api/v1/campaigns/:campaignId/audience
Adds one or more contacts to a campaign and defines the send schedule per contact. Each entry in the items array represents one contact and its scheduling configuration.
To add a single contact, send the items array with one element — the endpoint is the same for both single and batch operations.

Request body

default_schedule_timezone
string
An IANA timezone name (e.g. America/New_York) applied to all items whose datetime has no UTC offset and no schedule.timezone specified.
items
array
required
An array of contact + schedule objects. At least one item is required.

Contact resolution

When you provide identifier instead of contact_id, the platform resolves the contact in this order:
  1. Looks up the contact by the channel identifier (e.g. normalized WhatsApp number).
  2. If not found and email is provided, searches by email (case-insensitive).
    • If found without a channel identifier, links the identifier to the contact.
    • If found with a different channel identifier, returns a 400 error to prevent silent identity merging.
  3. If still not found, creates a new contact using name, email, and identifier.

Scheduling rules

datetime formatBehavior
With Z or numeric offset (e.g. +03:00, -0500)Treated as an absolute instant; timezone is ignored
Without offset (e.g. 2026-03-11T09:00:00)Requires schedule.timezone or default_schedule_timezone for UTC conversion
If datetime has no UTC offset and no timezone is provided (either in schedule.timezone or default_schedule_timezone), the request returns a 400 error.

Example request

{
  "default_schedule_timezone": "America/New_York",
  "items": [
    {
      "contact_id": "<CONTACT_ID_1>",
      "schedule": {
        "type": "immediate"
      }
    },
    {
      "identifier": "5511999999999",
      "name": "Jane Smith",
      "email": "jane@example.com",
      "custom_fields": {
        "cf_plan": "pro",
        "cf_source": "api"
      },
      "tags": ["Hot Lead", "VIP Customer"],
      "schedule": {
        "type": "absolute",
        "datetime": "2026-03-10T14:30:00.000Z"
      }
    },
    {
      "contact_id": "<CONTACT_ID_3>",
      "schedule": {
        "type": "absolute",
        "datetime": "2026-03-11T09:00:00",
        "timezone": "America/New_York"
      }
    }
  ]
}

Response fields

items
array
required
One entry per input item, in the same order as the request.

Example response

{
  "items": [
    {
      "messageId": "<MESSAGE_ID>",
      "contactId": "<CONTACT_ID_1>",
      "scheduled_at": null,
      "scheduled_at_utc": null,
      "timezone": null
    },
    {
      "messageId": "<MESSAGE_ID>",
      "contactId": "<CONTACT_ID_2>",
      "scheduled_at": "2026-03-10T14:30:00.000Z",
      "scheduled_at_utc": "2026-03-10T14:30:00.000Z",
      "timezone": null
    },
    {
      "messageId": "<MESSAGE_ID>",
      "contactId": "<CONTACT_ID_3>",
      "scheduled_at": "2026-03-11T09:00:00.000-05:00",
      "scheduled_at_utc": "2026-03-11T14:00:00.000Z",
      "timezone": "America/New_York"
    }
  ]
}

Cancel a queued message

POST /api/v1/campaigns/:campaignId/messages/:messageId/cancel
Cancels the delivery of a specific campaign message that is still in the queue. Cancelling one message does not affect any other messages in the campaign.
Only messages with status QUEUED can be cancelled. Messages that are already SENDING, SENT, or FAILED cannot be cancelled.

Response

{
  "id": "<MESSAGE_ID>",
  "status": "CANCELLED"
}

List campaign messages

GET /api/v1/campaigns/:campaignId/messages?limit=50&offset=0
Returns a paginated list of messages for the campaign, each with its current status.

Query parameters

limit
number
default:"50"
Number of results to return per page.
offset
number
default:"0"
Number of results to skip for pagination.

Get a specific message

GET /api/v1/campaigns/:campaignId/messages/:messageId
Returns the details and current status of a single campaign message.

Message statuses

StatusDescription
PENDINGAwaiting processing
QUEUEDQueued for delivery — can be cancelled
SENDINGCurrently being sent
SENTDelivered successfully
FAILEDDelivery failed
CANCELLEDCancelled via API

1

Configure the campaign in the platform

Create an evergreen campaign in the BluBash admin panel and copy the campaignId.
2

Add contacts to the audience

Call POST /api/v1/campaigns/:campaignId/audience with your items array.
3

Choose a schedule per contact

Use schedule.type = immediate for instant delivery, or schedule.type = absolute with a datetime for scheduled delivery.
4

Cancel if needed

If you need to stop a queued message, call POST /api/v1/campaigns/:campaignId/messages/:messageId/cancel.
5

Monitor message status

Use GET /api/v1/campaigns/:campaignId/messages to inspect delivery status across the campaign.

Code examples

curl -X POST https://api.blubash.io/api/v1/campaigns/{campaignId}/audience \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {
        "identifier": "5511999999999",
        "name": "Jane Smith",
        "tags": ["Hot Lead"],
        "schedule": {
          "type": "immediate"
        }
      }
    ]
  }'

Error reference

StatusMessageCause
400Each item must provide contact_id or identifierAn item has neither contact_id nor identifier
400Identifier is invalididentifier is empty or invalid after normalization
400schedule.timezone (IANA) is required when datetime has no UTC offsetdatetime has no offset and no timezone was provided
400Campaign is not an evergreen campaignThe campaignId belongs to a non-evergreen campaign
400Cannot add contacts to cancelled or failed campaignsCampaign status is CANCELLED or FAILED
400Cannot add contacts while the campaign is paused. Resume the campaign first.Campaign status is PAUSED
400Contact found by email already has a different identifier for this campaign channelEmail lookup found a contact with a conflicting channel identifier
400Contact does not have a valid channel identifier for this campaign channelThe resolved contact has no valid identifier for the campaign’s channel
401Missing or invalid API key
403Campaigns feature is not available in your current planThe Campaigns feature is not enabled on your subscription
404Campaign not foundThe campaignId does not exist in your workspace