Skip to content

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 ​

ParameterTypeDefaultDescription
statusstring or string[]—Filter by status(es)
typestring or string[]—Filter by type(s)
searchstring—Search by name (case-insensitive)
includeArchivedbooleanfalseInclude archived campaigns in results
limitnumber20Max results (1-100)
offsetnumber0Skip N results

Response 200 OK ​

json
{
    "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 ​

json
{
    "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"]
    }
}
FieldTypeRequiredDescription
namestring✓Campaign name (min 1 char)
briefstring—Detailed description
goalstring—Campaign objective
typeenum—ONE_TIME, RECURRING, EVERGREEN
startsAtdatetime—Start date (ISO 8601)
endsAtdatetime—End date (ISO 8601)
contextobject—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 ​

json
{
    "message": "Campaign not found"
}

Update Campaign ​

PUT /api/campaigns/:id

Request Body ​

json
{
    "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 ​

ParameterTypeDefaultDescription
actionstring—delete_all or move_content
moveToCampaignIduuid—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.

json
{
    "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 ​

json
{
    "name": "Copy of Spring Sale 2025"
}
FieldTypeRequiredDescription
namestring✓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 ​

json
{
    "find": "Old Product Name",
    "replace": "New Product Name",
    "dryRun": false
}
FieldTypeRequiredDescription
findstring✓Text to search for (case-insensitive)
replacestring✓Text to replace with
dryRunboolean—If true, returns match count without modifying data (default: false)

Response 200 OK ​

json
{
    "count": 15,
    "dryRun": false
}

Resume Campaign ​

POST /api/campaigns/:id/resume

Resume a paused campaign with a chosen strategy.

Request Body ​

json
{
    "strategy": "shift_weekday",
    "endDateAction": "extend",
    "newEndDate": "2025-04-30T00:00:00Z"
}
FieldTypeRequiredDescription
strategyenum✓shift_weekday, shift_calendar, keep_original, cancel
endDateActionenum—extend, set, keep (default: keep)
newEndDatedatetime—Required when endDateAction is set

Resume Strategies ​

StrategyDescription
shift_weekdayShift posts forward preserving weekday pattern
shift_calendarShift posts forward by paused duration
keep_originalKeep original dates, past posts won't auto-publish
cancelCancel 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 ​

json
{
    "archive": true
}
FieldTypeRequiredDescription
archiveboolean✓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 ​

json
[
    {
        "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 ​

json
{
    "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 ​

json
{
    "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 ​

json
{
    "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 ​

json
{
    "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:

  • brief
  • goal
  • context (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 ​

json
{
    "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:

FieldTypeDescription
keyMessagesstring[]Core campaign talking points
targetAudiencestringTarget audience description
tonestringVoice/tone for content
channelsstring[]Platform names for publishing

Defaults Behavior:

  • Omitted fields inherit from CompanyBrandProfile
  • Set explicitly to override brand defaults
  • Set to null to explicitly clear an override

Enums ​

CampaignType ​

ValueDescription
ONE_TIMESingle campaign with fixed dates
RECURRINGRepeating campaign (monthly, quarterly)
EVERGREENOngoing, no end date

CampaignStatus ​

ValueDescription
DRAFTNot yet started
ACTIVECurrently running
PAUSEDTemporarily stopped
COMPLETEDFinished

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 ​

FieldTypeDescription
pausedAtdatetimeWhen campaign was last paused
resumedAtdatetimeWhen campaign was last resumed
completedAtdatetimeWhen campaign was completed
lastStatusChangedAtdatetimeMost recent status change
isArchivedbooleanSoft-archive flag (hidden from default views)

TendSocial Documentation