Create & Build a Campaign
Create & Build a Campaign (granular HITL)
Build a campaign end-to-end the same way the in-app wizard does: create a shell, submit a target audience, choose your assets, generate value propositions, then kick the build. Each step is its own call so you can keep a human in the loop. The expensive AI stages run asynchronously — you poll a job (or the derived build status) until the campaign is ready for email generation.
All endpoints require an API key with the relevant campaigns:read /
campaigns:write scope. There are no credit charges for building a
campaign; builds are gated by your plan's campaign build limit. Credits are only
charged later, at email generation / preview time.
For the high-level object model and ordering, see Campaigns Overview.
The flow
The build follows a uniform list options → submit choice pattern for every step. The five-step table, the full endpoint sequence, and the reasoning behind each shape live in Campaigns Overview → Build lifecycle (including Why target audience is shaped differently).
In short, the order is create → target-audience → (social_proof, lead_magnet, risk_reversal) → value_proposition/generate → value_proposition/selection → poll build-status. SP/LM/RR can be submitted while target-audience research runs in the background; value-proposition generation requires the SP/LM/RR selections first (409 NOT_READY otherwise). The rest of this page documents the request/response for each step.
Create a campaign shell
POST /api/v1/campaigns · scope campaigns:write
Creates the empty campaign. Fails fast if the workspace isn't ready to build
(mirrors the dashboard gate): you need a completed company summary, completed
company documents, and at least one saved target audience. Enforces your plan's
campaign build limit. Supports Idempotency-Key.
Request
{ "name": "Q3 Outbound — Fintech CFOs" }Response — 201 Created
{ "id": "b3f...", "name": "Q3 Outbound — Fintech CFOs", "status": "draft" }Errors
409 NOT_READY— workspace isn't ready.detail.missinglists which ofcompany_summary,company_documents,target_audiencesare not satisfied. Finish onboarding /POST /api/v1/workspace/regeneratefirst.403 FORBIDDEN— build limit reached.detail = { reason: "campaign_build_limit", limit, used }.
Submit the target audience
POST /api/v1/campaigns/:id/target-audience · scope campaigns:write
This is step 1 of the five-step build. It mirrors the wizard: list segments
with GET /api/v1/target-audiences, then submit your pick here (or define a custom
segment). Unlike asset steps, this uses POST rather than PUT because it
creates or updates a reusable workspace segment and kicks the background
research — not a simple checkbox selection upsert. See
Why target audience is shaped differently.
Links a target audience to the campaign and kicks the background research for
this step. Returns a tracking job (202). Supports Idempotency-Key.
Pick an existing segment (from GET /api/v1/target-audiences) or define a custom one.
Request — existing segment
{ "target_audience": { "id": "ta_123", "segment_name": "Fintech CFOs" } }Request — custom segment
{
"is_custom_target_audience": true,
"target_audience": {
"segment_name": "Fintech CFOs",
"industry_vertical": "Financial Services",
"company_size": "200-1000",
"annual_revenue": "$50M-$250M",
"geographic_location": "North America",
"decision_makers": ["CFO", "VP Finance"],
"additional_details": "Series B+, scaling finance ops"
}
}
target_audience.idis required unlessis_custom_target_audienceistrue.
Response — 202 Accepted
{
"id": "job_...",
"type": "campaign.target_audience",
"status": "processing",
"target_audience_id": "ta_123"
}Poll GET /api/v1/jobs/:id (status becomes completed once the background processing
for this step finishes) or watch build status.
List selectable target audiences
GET /api/v1/target-audiences · scope campaigns:read
Paginated list of the workspace's saved segments (the picker source for the step
above). Supports ?q=, ?limit=, ?offset=.
{
"data": [
{
"id": "ta_123",
"segment_name": "Fintech CFOs",
"industry_vertical": "Financial Services",
"company_size": "200-1000",
"annual_revenue": "$50M-$250M",
"geographic_location": "North America",
"decision_makers": ["CFO", "VP Finance"],
"additional_details": null,
"source": "market_research",
"created_at": "2026-06-14T12:00:00Z"
}
],
"has_more": false,
"total": 1
}Read asset options
GET /api/v1/campaigns/:id/assets/:type/options · scope campaigns:read
Steps 2–5 use this pattern to list generated checkbox options before you
submit a selection. :type is one of social_proof, lead_magnet,
risk_reversal, value_proposition. Returns the generated checkbox options for
the step plus a ready flag. SP/LM/RR options are workspace-level (generated
during onboarding); value_proposition options are campaign-specific and
generated on demand (see below).
Note: Target audience options are not under
/assets/:type/options. List workspace segments withGET /api/v1/target-audiencesinstead — segments are reusable entities, not campaign-scoped checkbox inventories.
{
"asset_type": "social_proof",
"ready": true,
"options": [
{ "id": "sp_001", "name": "200+ fintechs onboarded", "description": "...", "type": "..." }
]
}If ready is false, the options are still generating — poll again.
Submit an asset selection
PUT /api/v1/campaigns/:id/assets/:type/selection · scope campaigns:write
Steps 2–5 use this pattern to submit your pick. Ids are hydrated against
the generated options (with optional name/description edits) and stored as the
final selection, marking the step complete — exactly like the wizard. Uses
PUT because it is an idempotent upsert of the selection for this campaign and
step (safe to retry with Idempotency-Key).
Request
{
"selected_ids": ["sp_001", "sp_004"],
"edited_names": { "sp_001": "200+ fintechs onboarded in 18 months" },
"edited_descriptions": {},
"additional_details": "Lead with the onboarding speed angle"
}Response (social_proof / lead_magnet / risk_reversal) — 200 OK
{ "asset_type": "social_proof", "items_stored": 2 }For value_proposition this call additionally kicks the build chain and
returns 202 + a build job — see below.
Generate value propositions
POST /api/v1/campaigns/:id/assets/value_proposition/generate · scope campaigns:write
Triggers campaign-scoped VP generation (the only asset step generated on demand).
Precondition: the social_proof, lead_magnet, and risk_reversal
selections must already be submitted, otherwise 409 NOT_READY with
detail.missing. Returns a tracking job (202). Supports Idempotency-Key.
{ "id": "job_...", "type": "campaign.value_propositions", "status": "processing" }Poll GET /api/v1/jobs/:id until completed, then read the options via
GET .../assets/value_proposition/options.
Submit value propositions (kick the build)
PUT /api/v1/campaigns/:id/assets/value_proposition/selection · scope campaigns:write
Same body as other asset selections. Requires that VP options have been generated
(409 NOT_READY otherwise). On submit it marks the VP step complete and kicks the
post-wizard build (all background processing — no further input needed),
returning a build job (202). Supports Idempotency-Key (recommended).
{
"asset_type": "value_proposition",
"items_stored": 6,
"job": { "id": "job_...", "type": "campaign.build", "status": "processing" }
}After this, poll build status until overall is ready.
Notes
- No credits are charged for any step here. Builds are limited by your plan's campaign build limit (the
403above). - Async stages are not enqueued workers. The AI chains run far longer than the generic worker budget, so
campaign.target_audience,campaign.value_propositions, andcampaign.buildjobs report derived status computed from live campaign state when you poll them. See Conventions → Async jobs. - Idempotency: every mutating step accepts
Idempotency-Key; replaying a key returns the original outcome and never re-runs the work.