Create & Build a Campaign

ReferenceUpdated June 14, 2026

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.missing lists which of company_summary, company_documents, target_audiences are not satisfied. Finish onboarding / POST /api/v1/workspace/regenerate first.
  • 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.id is required unless is_custom_target_audience is true.

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 with GET /api/v1/target-audiences instead — 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 403 above).
  • Async stages are not enqueued workers. The AI chains run far longer than the generic worker budget, so campaign.target_audience, campaign.value_propositions, and campaign.build jobs 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.