Complete a campaign
Complete changes an active campaign to completed. It does not delete posts or confirm that every planned post reached a social platform.
Before you start
-
Find the campaign with List campaigns, then read it in the intended authorized brand.
-
Check that its status is
activeand its stored scheduling window is still valid. Reconstructing the entity checks the window again: its end must be in the future, its duration must be 1 hour–365 days, and start must precede end. -
Require the original authenticated user identity in the verified service context; an API key alone does not establish it. Never fabricate authentication headers. The credential needs
app_topolo_socialize.calendar:writeand the required workspace grant. Bind that resource separately from input, validate/plan the exact mutation, and obtain approval before running it.
Request
POST /api/campaigns/{id}/complete
The only input field is the existing campaign id (required, non-empty string).
Worked examples
These are source-derived, synthetic and unrun examples. Assume valid access, verified original authenticated user identity and an illustration clock of 2026-10-21T12:00Z. They provide no live execution approval.
Complete an active campaign
Request
{
"id": "campaign_example"
}
Response illustration
{
"id": "campaign_example",
"name": "Example campaign",
"createdBy": "user_example",
"status": "completed",
"paused": false,
"pausedAt": null,
"resumedAt": null,
"windowStartDate": "2026-10-21T00:00:00.000Z",
"windowEndDate": "2026-10-22T00:00:00.000Z",
"variants": [
{
"id": "campaign_example_default",
"name": "default",
"weight": 100,
"postId": "post_example"
}
],
"createdAt": "2026-10-20T12:00:00.000Z",
"updatedAt": "2026-10-21T12:00:00.000Z"
}
Read campaigns.get and verify status completed in the intended campaign/brand. A completed campaign does not prove that every post was published or that the operator received a notification.
State-precondition refusal illustration
Request
{
"id": "campaign_example"
}
Response illustration
{
"type": "/problems/internal-server-error",
"title": "Internal Server Error",
"status": 500,
"detail": "Cannot complete campaign with status draft"
}
The domain throws a plain Error before the campaign state UPDATE. The reviewed route serializes it as HTTP500, not an invented409/422. Earlier authorization mirror writes may still have occurred.
Verify completion
Read the same campaign again. Verify status: completed, the campaign id and its owning brandId. The immediate mutation response is a domain projection; it omits optional profile/brand fields and excludes variants with no post id without deleting those rows. Use the later read for stored state.
Notifications
After updating the campaign, the route attempts a best-effort completion notification. Its response carries no notification receipt, and the helper can silently return false. Before entering that helper, however, the caller reads the original authenticated user identity. If it is missing, the caller can return HTTP400 problem details (type: /problems/validation-error, title: Validation Error, detail: Authentication context missing) after completed status has already been saved. Re-read the campaign; do not treat that error as rollback or retry completion to resend a notification. Check separately authorized notification evidence if notification delivery matters; repeating the completion request is not a delivery retry.
Effects and recovery
Authorization can synchronize the app-local brand mirror before campaign completion. The status update has no transactional rollback in this contract. After a lost response, read current state before considering another operation; a completed campaign is not accepted as an idempotent repeat.
Invalid domain status/window conditions are plain errors serialized as HTTP500 problem details (type, title, status, detail) by the reviewed route. A state refusal occurs before the campaign update, but earlier authorization mirror writes may already have happened. Preserve the actual response and request id; do not invent a 409/422 response or change dates to bypass the refusal.
Change log
- 2026-10-21: Added the active-to-completed transition, source-specific window/error behavior, synthetic examples, persisted-state checks and the distinction between campaign completion and notification delivery.
Source
Reviewed route, campaign service/domain, brand access, error serializer and notification helper at source f8e30bad6947f868302f24e9cb31b6a2bdd1fbf6. The current declaration was refreshed; the serving-source association remains unknown.