Overview ​
Campaign endpoints manage marketing initiatives and their linked content.
Authentication ​
All endpoints require Bearer token authentication:
Authorization: Bearer <token>Endpoints ​
List Campaigns ​
GET /api/campaigns
Returns paginated list of campaigns for the authenticated company.
Query Parameters ​
| Parameter | Type | Default | Description |
|---|---|---|---|
status | string or string[] | — | Filter by status(es) |
type | string or string[] | — | Filter by type(s) |
search | string | — | Search by name (case-insensitive) |
includeArchived | boolean | false | Include archived campaigns in results |
limit | number | 20 | Max results (1-100) |
offset | number | 0 | Skip N results |
Response 200 OK ​
{
"items": [
{
"id": "uuid",
"name": "Q1 Product Launch",
"brief": "Campaign description...",
"goal": "Increase awareness",
"type": "ONE_TIME",
"status": "ACTIVE",
"startsAt": "2025-01-01T00:00:00Z",
"endsAt": "2025-03-31T00:00:00Z",
"pausedAt": null,
"resumedAt": null,
"completedAt": null,
"lastStatusChangedAt": "2025-01-01T00:00:00Z",
"isArchived": false,
"context": {
"keyMessages": ["Message 1", "Message 2"],
"targetAudience": "Tech professionals",
"tone": "Professional",
"channels": ["linkedin", "twitter"]
},
"createdAt": "2025-01-01T00:00:00Z",
"updatedAt": "2025-01-15T00:00:00Z"
}
],
"total": 45
}Create Campaign ​
POST /api/campaigns
Request Body ​
{
"name": "Spring Sale 2025",
"brief": "Promotional campaign for spring collection",
"goal": "Drive 20% increase in sales",
"type": "ONE_TIME",
"startsAt": "2025-03-01T00:00:00Z",
"endsAt": "2025-03-31T00:00:00Z",
"context": {
"keyMessages": ["Limited time offer", "Free shipping"],
"channels": ["instagram", "facebook"]
}
}| Field | Type | Required | Description |
|---|---|---|---|
name | string | ✓ | Campaign name (min 1 char) |
brief | string | — | Detailed description |
goal | string | — | Campaign objective |
type | enum | — | ONE_TIME, RECURRING, EVERGREEN |
startsAt | datetime | — | Start date (ISO 8601) |
endsAt | datetime | — | End date (ISO 8601) |
context | object | — | Context overrides |
Response 201 Created ​
Returns the created campaign object.
Get Campaign ​
GET /api/campaigns/:id
Returns single campaign by ID.
Response 200 OK ​
Full campaign object (same structure as list items).
Response 404 Not Found ​
{
"message": "Campaign not found"
}Update Campaign ​
PUT /api/campaigns/:id
Request Body ​
{
"name": "Updated Name",
"status": "ACTIVE",
"context": {
"targetAudience": "Custom audience for this campaign"
}
}All fields are optional. Only provided fields are updated.
Response 200 OK ​
Returns the updated campaign object.
Delete Campaign ​
DELETE /api/campaigns/:id
Query Parameters ​
| Parameter | Type | Default | Description |
|---|---|---|---|
action | string | — | delete_all or move_content |
moveToCampaignId | uuid | — | Target campaign when action is move_content |
Response 204 No Content ​
Campaign deleted successfully.
Response 409 Conflict ​
Campaign has published content and cannot be deleted.
{
"error": "PUBLISHED_CONTENT_EXISTS",
"message": "Cannot delete campaign with published content",
"publishedCount": 5
}Duplicate Campaign ​
POST /api/campaigns/:id/duplicate
Creates a deep copy of a campaign and all its content (social posts, blogs, scripts). New items are set to DRAFT status.
Request Body ​
{
"name": "Copy of Spring Sale 2025"
}| Field | Type | Required | Description |
|---|---|---|---|
name | string | ✓ | Name for the new campaign |
Response 201 Created ​
Returns the newly created campaign object.
Find & Replace ​
POST /api/campaigns/:id/find-replace
Performs bulk find and replace across campaign fields (brief, goal) and all associated content (posts, blogs, scripts).
Request Body ​
{
"find": "Old Product Name",
"replace": "New Product Name",
"dryRun": false
}| Field | Type | Required | Description |
|---|---|---|---|
find | string | ✓ | Text to search for (case-insensitive) |
replace | string | ✓ | Text to replace with |
dryRun | boolean | — | If true, returns match count without modifying data (default: false) |
Response 200 OK ​
{
"count": 15,
"dryRun": false
}Resume Campaign ​
POST /api/campaigns/:id/resume
Resume a paused campaign with a chosen strategy.
Request Body ​
{
"strategy": "shift_weekday",
"endDateAction": "extend",
"newEndDate": "2025-04-30T00:00:00Z"
}| Field | Type | Required | Description |
|---|---|---|---|
strategy | enum | ✓ | shift_weekday, shift_calendar, keep_original, cancel |
endDateAction | enum | — | extend, set, keep (default: keep) |
newEndDate | datetime | — | Required when endDateAction is set |
Resume Strategies ​
| Strategy | Description |
|---|---|
shift_weekday | Shift posts forward preserving weekday pattern |
shift_calendar | Shift posts forward by paused duration |
keep_original | Keep original dates, past posts won't auto-publish |
cancel | Cancel all remaining scheduled posts |
Response 200 OK ​
Returns the updated campaign object.
Archive Campaign ​
POST /api/campaigns/:id/archive
Archive or unarchive a campaign. Archiving hides the campaign from default list views but preserves all data and analytics.
Request Body ​
{
"archive": true
}| Field | Type | Required | Description |
|---|---|---|---|
archive | boolean | ✓ | true to archive, false to unarchive |
Response 200 OK ​
Returns the updated campaign object.
NOTE
Archiving sets isArchived: true but does NOT change the campaign's status. A COMPLETED campaign remains COMPLETED; it's just hidden from default views.
Get Campaign Content ​
GET /api/campaigns/:id/content
Returns all content linked to this campaign (posts, blogs, scripts) in a unified format.
Response 200 OK ​
[
{
"id": "uuid",
"type": "social",
"platform": "linkedin",
"content": "Post content...",
"status": "DRAFT",
"scheduledAt": null,
"publishedAt": null,
"createdAt": "2025-01-15T00:00:00Z"
},
{
"id": "uuid",
"type": "blog",
"title": "Blog Post Title",
"status": "SCHEDULED",
"scheduledAt": "2025-01-20T10:00:00Z",
"publishedAt": null,
"createdAt": "2025-01-15T00:00:00Z"
},
{
"id": "uuid",
"type": "script",
"platform": "youtube",
"title": "Video Title",
"status": "draft",
"scheduledAt": null,
"publishedAt": null,
"createdAt": "2025-01-15T00:00:00Z"
}
]Get Campaign Analytics ​
GET /api/campaigns/:id/analytics
Returns aggregated performance metrics for all content linked to the campaign.
Response 200 OK ​
{
"totalViews": 12500,
"totalImpressions": 15000,
"totalLikes": 450,
"totalComments": 120,
"totalShares": 50,
"totalClicks": 300,
"totalEngagement": 620,
"engagementRate": 4.13,
"contentCount": 12,
"publishedCount": 8,
"byPlatform": [
{
"platform": "linkedin",
"views": 5000,
"impressions": 6000,
"engagement": 250,
"contentCount": 3
}
],
"byContentType": [
{
"contentType": "social_post",
"count": 5,
"views": 8000,
"engagement": 400
}
]
}Planning Chat ​
POST /api/campaigns/chat
Interactive AI conversation for campaign planning.
Request Body ​
{
"message": "I want to launch a product awareness campaign",
"history": [
{ "role": "user", "text": "Previous message..." },
{ "role": "assistant", "text": "AI response..." }
],
"context": {
"additionalContext": "Optional context data"
}
}Response 200 OK ​
{
"response": "Great! Let's plan your product awareness campaign...",
"role": "assistant"
}Generate Plan ​
POST /api/campaigns/:id/generate-plan
Extracts structured campaign plan from planning chat history.
Request Body ​
{
"chatHistory": [
{ "role": "user", "text": "I want to increase brand awareness..." },
{ "role": "assistant", "text": "Let's define your target audience..." }
]
}Response 200 OK ​
Returns updated campaign with extracted:
briefgoalcontext(audience, tone, channels)startsAt/endsAt(if timeline discussed)
Generate Content ​
POST /api/campaigns/:id/generate-content
AI generates content drafts based on campaign plan and brand profile.
Response 200 OK ​
{
"message": "Content generated and saved successfully",
"counts": {
"social": 5,
"blog": 2,
"video": 1
},
"ideas": {
"socialPosts": [...],
"blogIdeas": [...],
"videoIdeas": [...]
}
}Generated content is saved to the database and appears in GET /api/campaigns/:id/content.
Context Field Reference ​
The context object supports these fields:
| Field | Type | Description |
|---|---|---|
keyMessages | string[] | Core campaign talking points |
targetAudience | string | Target audience description |
tone | string | Voice/tone for content |
channels | string[] | Platform names for publishing |
Defaults Behavior:
- Omitted fields inherit from
CompanyBrandProfile - Set explicitly to override brand defaults
- Set to
nullto explicitly clear an override
Enums ​
CampaignType ​
| Value | Description |
|---|---|
ONE_TIME | Single campaign with fixed dates |
RECURRING | Repeating campaign (monthly, quarterly) |
EVERGREEN | Ongoing, no end date |
CampaignStatus ​
| Value | Description |
|---|---|
DRAFT | Not yet started |
ACTIVE | Currently running |
PAUSED | Temporarily stopped |
COMPLETED | Finished |
IMPORTANT
isArchived is a separate boolean field, not a status. Archived campaigns retain their original status (e.g., COMPLETED) but are hidden from default views.
Lifecycle Fields ​
| Field | Type | Description |
|---|---|---|
pausedAt | datetime | When campaign was last paused |
resumedAt | datetime | When campaign was last resumed |
completedAt | datetime | When campaign was completed |
lastStatusChangedAt | datetime | Most recent status change |
isArchived | boolean | Soft-archive flag (hidden from default views) |