BuildBaseBuildBase

Overview

Author campaigns in the console, send to an audience, and track delivery through the REST API.

Campaigns are authored in the BuildBase console: pick a template, pick an audience, send or schedule. The API is for driving and observing that pipeline from your backend, not for composing mail in code.

Note

There is no bb.email.send(). The server SDK has no email namespace. To send one transactional message to one user, use bb.notification.send() — it renders the event's email template and respects the user's preferences. Campaigns are for audience-scale sends.

// Send a campaign that was prepared in the console
const response = await fetch(
  `https://api.console.buildbase.app/api/emails/campaigns/${campaignId}/send`,
  {
    method: 'POST',
    headers: { Authorization: process.env.BUILDBASE_API_TOKEN! },
  }
);

Before you start

Before a campaign can send, you need a verified sending domain, a sender address on that domain, and a template. The console blocks the send until all three exist.

The pipeline

  1. Template — the reusable body, with merge tags. See templates and merge tags.
  2. Sender and domain — who it comes from, on a verified domain.
  3. Campaign — a template plus an audience plus a schedule.
  4. Drafts — one queued message per recipient, materialized from the campaign.
  5. Send — the queue delivers, and history records the outcome per recipient.

Drafts are the step that surprises people. A campaign does not send directly to an audience: it first expands into per-recipient drafts, and the send walks those. That is what makes partial retry possible.

Campaign endpoints

All require an Authorization header — see the admin API for the token format and list-query parameters.

MethodPathPurpose
GET/api/emails/campaignsList campaigns, paginated
GET/api/emails/campaigns/:idOne campaign
POST/api/emails/campaignsCreate
PATCH/api/emails/campaigns/:idUpdate
POST/api/emails/campaigns/:id/create-draftsExpand the audience into per-recipient drafts
POST/api/emails/campaigns/:id/sendSend the campaign
POST/api/emails/campaigns/:id/retry-failedRe-queue only the recipients that failed
DELETE/api/emails/campaigns/:idDelete

retry-failed re-queues failures without touching recipients who already received the message, so it is safe to call more than once after a partial delivery failure. It returns the counts it acted on:

{
  "message": "Retried 12 failed emails, 3 skipped",
  "retried": 12,
  "skipped": 3
}

Campaign status

A campaign is always in one of five states, and the action endpoints are guarded by it:

StatusMeaning
draftEditable, not yet dispatched
sendingDispatch in progress
sentDispatch finished
failedDispatch failed
archivedRetired
EndpointAllowed fromRejected with
/create-draftsdraft only400Cannot create drafts for campaign in "X" state
/senddraft or failed400Cannot send campaign in "X" state

/send accepting failed is what makes a whole-campaign retry possible after a dispatch collapses. Use /retry-failed instead when the campaign partly succeeded — re-sending from failed state is coarser.

Both rejections use the { error: true, message, path: "status" } shape.

Delivery history

Every send writes a history row per recipient with a status, and tracking records opens and clicks when the template includes the tracking pixel. Both are exposed as chart endpoints the console renders, and as ordinary list endpoints you can page through.

Delivery is asynchronous. /send returns { "message": "Campaign dispatch started" } as soon as the work is queued — that is not a delivery confirmation. Poll the history rows for per-recipient outcomes.

Recipients are resolved from the campaign's audience list and expanded in batches of 500, so a large list produces drafts progressively rather than in one pass.

Unsubscribes

Two merge tags render opt-out links. Both resolve at send time to a page on your application URL — not the API — carrying a per-recipient token, so the link identifies the recipient without a login:

Merge tagResolves to
{{unsubscribe}}<your-app>/unsubscribe-email-group?token=…
{{manage-preference}}<your-app>/manage-email-preference?token=…

The preference center is backed by its own token-validated API under /api/manage-email-preference, which is what the page calls to read and update preferences. You do not call it directly.

Every audience campaign should carry at least one of these tags.

Providers

BuildBase sends through Google, Mailgun, and custom SMTP. Domain verification is Mailgun-backed, so a verified sending domain requires Mailgun regardless of which provider delivers a given sender.

Next Steps