DeckleDocs
Dashboard

API reference

Campaigns

Create, target, and send broadcast campaigns to your whole list or a segment.

A campaign is a one-off broadcast built from a template. Create it as a draft, then send it. Campaign sends require a live key.

The campaign object#

json
{
  "id": "camp_x1y2z3",
  "name": "March newsletter",
  "subject": "What's new this month",
  "preview_text": "A quick roundup",
  "from_name": "Acme",
  "from_email": "news@acme.com",
  "target": "all",
  "template": "tmpl_123",
  "segment": null,
  "status": "draft",
  "stats": null,
  "variants": [{ "id": "B", "subject": "You missed a lot" }],
  "scheduled_at": null,
  "sent_at": null,
  "created_at": "2026-07-10T10:30:00.000Z",
  "updated_at": "2026-07-10T10:30:00.000Z"
}

status moves through draftqueued sendingsent. target is all or segment.

Create a campaign#

POST/v1/campaigns

Creates a draft. The from_email domain must be verified.

Body parameters

namestringRequired
Internal name for the campaign.
subjectstringRequired
Subject line (variant A).
from_namestringRequired
Sender display name.
from_emailstringRequired
Sender address on a verified domain.
preview_textstringOptional
Inbox preview / preheader text.
templatestringOptional
The template id to send. Required before the campaign can be sent.
target"all" | "segment"Optional
Who to send to. Defaults to all.
segmentstringOptional
Segment id — required when target is segment.
variantsstring[]Optional
Up to three alternate subject lines for A/B testing. The base subject is variant A; extras become B, C, and D.
const campaign = await deckle.campaigns.create({
  name: "March newsletter",
  subject: "What's new this month",
  from_name: "Acme",
  from_email: "news@acme.com",
  template: "tmpl_123",
  target: "all",
  variants: ["You missed a lot"],
});

List campaigns#

GET/v1/campaigns

Query parameters

limitintegerOptional
Items per page. Default 50, max 100.
cursorstringOptional
Pagination cursor.
statusstringOptional
Filter by status, e.g. draft or sent.
ts
const { data } = await deckle.campaigns.list({ status: "sent" });

Retrieve a campaign#

GET/v1/campaigns/:id
ts
const campaign = await deckle.campaigns.get("camp_x1y2z3");

Update a campaign#

PATCH/v1/campaigns/:id

Only a draft campaign can be edited — updating one that’s already sending or sent returns 409. Send any of name, subject, from_name, from_email, preview_text, template, target, or segment.

bash
curl -X PATCH https://app.getdeckle.com/api/v1/campaigns/camp_x1y2z3 \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "subject": "A better subject" }'

Send a campaign#

POST/v1/campaigns/:id/send

Sends the campaign now. The campaign must have a template. When the background worker is configured the send is queued and returns 202 with queued: true; otherwise it runs inline (capped at 200 recipients) and returns the counts.

const result = await deckle.campaigns.send("camp_x1y2z3");
// queued: { ...campaign, queued: true }
// sync:   { ...campaign, sent: 184, failed: 0 }

Live key required

A test key can’t send campaigns and returns 403. Sending a campaign with no template returns 422; re-sending one that’s already sending returns 409.