Skip to main content

Generate a campaign draft from a brief

Authoring a multi-channel campaign means filling a dozen slots by hand: an SMS body under 160 characters, an email subject, preview text and body, a WhatsApp category, a fallback order, a send time. The from-brief composer collapses that into one plain-English sentence or two. You type what the campaign should do, POST /campaigns/from-brief returns a typed campaign draft, and the dashboard composer renders it into editable fields. Nothing is persisted and nothing is sent until you review the draft and commit it through the regular campaign creation flow. This guide covers the request surface, the typed draft shape and why it is typed, the grounding pass that strips claims your brief never made, the limits and failure modes you can hit, and how this surface differs from the other AI authoring entry points.

1. What the from-brief composer does

Send a short natural-language brief, for example:
Win back customers who have not ordered in 90 days. SMS first with email fallback, friendly tone, mention the 15% returning-customer discount.
The endpoint reads it and returns a structured draft carrying:
  • name, description, goal: a short title, a one-to-two sentence summary for review, and the primary KPI the brief aims at (“reactivation”, “CTR”, “conversion”).
  • audience: a natural-language audience description plus the rationale for it. The description is written to feed POST /contacts/segments/from-prompt, which materialises the actual segment.
  • channels: per-channel copy for sms, rcs, whatsapp, email, and push. Channels the brief does not need, or that you did not list as available, come back null.
  • recommended_send_time and scheduled_at_iso: immediate, optimal_per_recipient, or scheduled with an RFC 3339 timestamp.
  • fallback_chain: the failover sequence across channels, for example ["sms", "email"].
  • ab_test: present only when your brief asks for an A/B test, with the two variants and the winner metric.
  • warnings: anything you should know before launch, such as compliance notes, missing brand information, or a send time the composer could not resolve.
The response is a draft, not a campaign. The endpoint persists nothing: the dashboard composer renders every slot as an editable field, and you commit with POST /campaigns after review. Review-then-send is the contract on every AI authoring surface; generated output is a starting point, never a one-click launch.

2. Endpoint surface

The response envelope is data.draft (the typed shape from section 1) plus data.model, the model that served the request, and data.usage, the token accounting for the call, attributed to your tenant like any other AI spend.

3. Why the draft is a typed shape

The draft is a fixed JSON shape on purpose. Asked to “write a campaign”, an open-ended model drifts into free-form prose that no form can render. A narrow, typed contract forces the output into exactly the slots the composer draws: a title, per-channel copy, a send time, a fallback order. Each slot has a type and a bound, so a well-formed response loads into the draft form with no re-typing, and a missing or off-shape slot shows up as a flagged field you edit, not as broken prose:
  • SMS body is at most 160 characters, with no link tokens unless your brief asked for a link.
  • RCS carries a body plus up to four quick-reply suggestions.
  • WhatsApp carries a template_intent, a body, and a category restricted to Meta’s vocabulary: MARKETING, UTILITY, or AUTHENTICATION.
  • Email carries subject, preview_text, and a GitHub-flavored markdown body_markdown.
  • Push carries a title of at most 50 characters and a body of at most 120.
Read warnings as part of the contract, not as noise: it is where the composer reports what it could not resolve, from an unresolvable send time to a compliance caveat for your region.

4. Grounding: what the composer refuses to invent

When the model writes copy it can tack on promotional claims your brief never made: urgency (“Limited time offer”, “act now”), scarcity (“last chance”, “while supplies last”), a discount you did not author (“50% off”), or a guarantee (“risk-free”). Unauthored claims are a carrier and consumer-protection liability you never signed off on, so before the draft reaches you the endpoint runs a deterministic grounding pass over every generated copy field, checked against your own brief:
  • Any sentence that introduces a claim class your brief does not support is removed; the rest of the copy is kept. “Your order history qualifies you for the returning-customer rate. Limited time offer!” keeps the first sentence and loses the second when the brief never said “limited time”.
  • An RCS quick-reply label that is entirely an ungrounded claim is dropped from suggestions rather than rendered as an empty chip.
  • A copy field that collapses to empty was entirely fabricated; the composer shows it as an empty, editable slot instead.
Reading a partially-grounded response:
  • A body minus one sentence carried a fabricated claim. What remains is yours to edit, and if you genuinely want that claim, add it to the brief and regenerate: a claim present in the brief is grounded by definition and survives the pass.
  • An empty slot means every sentence the model wrote for it was ungrounded. Treat it as “the model had nothing authorised to say here” and write the slot yourself.
  • Grounding checks claim classes, not facts. It will strip “act now” but it cannot verify a statistic or a price. The review pass before launch is still yours.

5. Limits and failure modes

  • Draft-only output. The endpoint never persists a campaign and never sends anything. A draft becomes a send only after you commit it with POST /campaigns and launch it through the normal lifecycle. The draft also makes no promise about deliverability pre-checks: run it through the same pre-launch checks as any authored content.
  • Send times are guarded. A scheduled_at_iso in the past (or unparseable) is downgraded to recommended_send_time: "immediate", the timestamp is dropped, and a warning is appended telling you to set the send time in the schedule step. Relative expressions (“tomorrow at 10:00”, “next Monday”) resolve against your workspace timezone when timezone is present, and against UTC when it is not, so direct API callers with local-time briefs should always pass it.
  • Brief too short. Fewer than 8 characters is rejected with a 422 validation error before any generation runs.
  • Parse failure. If the model returns something that is not the typed shape, you get 422 AI_PARSE_FAILED with a preview of the raw output. Re-run with a clearer brief, or fall back to POST /campaigns with explicit fields.
  • Timeout and provider failure. Generation runs under a time budget: a slow provider returns 504 LLM_TIMEOUT, a transient upstream failure returns 502 LLM_UPSTREAM_ERROR. Both are retryable; budget your retries rather than looping.
  • Spend and rate gates. The endpoint sits on the same AI budget and rate limiting as the other generation surfaces. A spend cap, rate limit, or insufficient balance returns the same structured 402 / 429 / 403 / 503 envelope those surfaces return, with the reason and any retry window, and a 503 also covers a workspace with no AI provider configured.
  • Model routing. Requests are served by your platform’s configured model bucket; no model name is fixed in this flow, and data.model on the response names the model that served each request.

6. Worked briefs

Three briefs of increasing specificity, each with the draft shape they produce. Field values are illustrative of the shape; your copy will differ.

Product launch, minimal brief

Win-back with an authored offer and a send time

The 15% discount survives grounding because the brief authored it. Add “ends tonight” to neither and the composer will strip it from the copy if the model invents it.

Nurture series with an A/B test

Note the honest split of labour: from-brief drafts copy, while multi-step pacing (day 0 / 3 / 7 waits) is journey territory, and the draft says so in warnings rather than silently flattening the series into one blast.

7. How this differs from the adjacent surfaces

The boundaries in one line: from-brief drafts copy for one campaign, journey-from-prompt drafts the orchestration a series of sends runs on, and agents-from-prompt drafts a conversational agent. A journey whose steps need copy can take a from-brief draft’s channel content into each step after review.

See also