Skip to content

Campaigns

A campaign is a plan: a name, a cadence, a length, and a mix of content types. Creating one does not create posts — content is generated asynchronously by the internal engine once the campaign is launched.

GET /api/v1/campaigns

Query parameters:

NameTypeNotes
limitinteger1 to 100, default 25.
cursorstringSee Pagination.

There is no status filter on this endpoint — filter client-side on the returned status field. Results are newest first by created_at.

GET /api/v1/campaigns/{id}
{
"id": "4b7f2a91-c3d8-4e56-9a07-1f2b3c4d5e6f",
"object": "campaign",
"name": "Product launch week",
"description": "Announce v2 with a mix of feature posts and customer quotes.",
"status": "active",
"content_mix": { "ugc": 25, "talkingHead": 25, "videoHookDemo": 50 },
"posts_per_day": 2,
"campaign_length_days": 5,
"start_date": "2026-08-01T00:00:00Z",
"total_posts": 10,
"generated_posts": 4,
"created_at": "2026-07-19T12:15:00Z",
"updated_at": "2026-07-19T12:20:31Z"
}

Campaign ids are UUIDs, like every other id in the API.

POST /api/v1/campaigns
Terminal window
curl -X POST https://app.nativpost.com/api/v1/campaigns \
-H "Authorization: Bearer $NATIVPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Product launch week",
"description": "Announce v2 with a mix of feature posts and customer quotes.",
"posts_per_day": 2,
"campaign_length_days": 5,
"start_date": "2026-08-01T00:00:00Z",
"content_mix": { "ugc": 25, "talkingHead": 25, "videoHookDemo": 50 }
}'
FieldTypeNotes
namestringRequired. 1 to 160 characters.
descriptionstringUp to 1000 characters.
posts_per_dayinteger1 to 50, default 3.
campaign_length_daysinteger1 to 365, default 7.
start_datestringISO 8601 date-time.
content_mixobjectContent type → percentage weight.

name is the only required field.

There is no platforms field on a campaign. Targeting is set per content item via target_platforms — see Content.

content_mix keys are camelCase engine names, not the snake_case content types: ugc, slideshow, talkingHead, videoHookDemo, greenScreen, videoHook, carousel.

The campaign is created with status: "draft" and generated_posts: 0. total_posts is computed on create as posts_per_day × campaign_length_days and is not recomputed when you later patch either input.

POST /api/v1/campaigns/{id}/launch

Flips the campaign to active, sets start_date to now, and returns 202 Accepted with the serialized campaign:

{
"id": "4b7f2a91-c3d8-4e56-9a07-1f2b3c4d5e6f",
"object": "campaign",
"status": "active",
"start_date": "2026-07-19T12:31:00Z",
"total_posts": 10,
"generated_posts": 0
}

The response carries no scheduled_posts or skipped_posts counts — generation happens asynchronously after the call returns. Poll the campaign and watch generated_posts climb toward total_posts.

Only draft and paused campaigns can be launched. Anything else returns 409 with code invalid_state:

{
"error": {
"code": "invalid_state",
"message": "Cannot launch a campaign in status \"active\". Only draft or paused campaigns can be launched.",
"docs_url": "https://docs.nativpost.com/errors"
}
}

Fires the campaign.launched webhook.

PATCH /api/v1/campaigns/{id}

Editable fields: name, description, status, posts_per_day, campaign_length_days, start_date, content_mix. Send only what changes; a body with no recognised field returns 400 no_updates.

status accepts draft, active, paused, completed, and archived. Setting it here bypasses the launch endpoint’s state check, so prefer /launch for the draft → active transition.

DELETE /api/v1/campaigns/{id}

Hard-deletes the campaign row. Content items generated by it are not deleted — their campaign_id is cleared and the posts remain in the workspace.

{ "id": "4b7f2a91-c3d8-4e56-9a07-1f2b3c4d5e6f", "object": "campaign", "deleted": true }

No webhook fires on campaign deletion.