---
title: "Stop a campaign"
method: POST
path: "/v1/campaigns/{campaignId}/stop"
tags: ["Campaigns"]
---

# Stop a campaign

`POST /v1/campaigns/{campaignId}/stop`

## Request

- Base URL: `https://api.folk.app`
- URL: `https://api.folk.app/v1/campaigns/{campaignId}/stop`
- Auth: HTTP bearer

Stop a scheduled or sending campaign, or only some of its recipients. Messages already sent stay sent; those not sent yet are not sent, with `notSentReason: "stopped"`.

Without a body, the whole campaign becomes `cancelled`: a scheduled campaign sends nothing, and a sending one sends none of its next steps. Stopping a cancelled campaign again leaves it unchanged. A campaign whose last step is already sending can only be stopped for some recipients.

With `recipientIds`, only their messages not sent yet are stopped and the other recipients still receive theirs. Once no recipient is left to send to, the campaign becomes `cancelled`, and a scheduled one sends nothing; a campaign whose last step is already sending isn't cancelled: that step ends with the messages already sent. Merged contacts are resolved, and ids that are not recipients of the campaign or have nothing left to send are listed in `warnings`.

A campaign still `processing` its messages answers 409 with a `Retry-After` header. A campaign that is not launched, finished or failed answers 409: delete a `draft` or `in_review` campaign instead, or remove recipients from an `in_review` one with `DELETE /v1/campaigns/:campaignId/recipients/:contactId`.<br/><Warning>This endpoint is currently in open beta. The API surface may change as we iterate based on feedback.</Warning>

## Path parameters

- `campaignId` string, required

## Headers

- `Idempotency-Key` string: A unique key, such as a UUID, that makes retrying this request safe: a retry with the same key and body returns the original response without running the operation again. Keys are kept for 24 hours after the request completes.

## Request body

- object
  - `recipientIds` string[]: Stop only these people or companies, at most 100: every message of theirs not sent yet, in every step, is not sent. The other recipients still receive their messages; once no recipient is left to send to, the campaign becomes `cancelled`, unless its last step is already sending. In review, remove recipients with `DELETE /v1/campaigns/:campaignId/recipients/:contactId` instead. Omit to stop the whole campaign.

## Response `200`

The campaign, once stopped.

- object
  - `data` CMPCampaign, required: A campaign: one or more emails, each a step, sent to a list of people or companies.
    - `id` string, required
    - `name` string, required: The name of the campaign.
    - `status` 'draft' | 'processing' | 'in_review' | 'scheduled' | 'sending' | 'finished' | 'cancelled' | 'failed', required: The status of the campaign. One of: draft, processing, in_review, scheduled, sending, finished, cancelled, failed. `processing` means messages are being generated: poll until `in_review`.
    - `groupId` string, nullable, required: The group the campaign was created from, or null for a campaign created from a selection of contacts, or whose group was deleted since.
    - `entityType` 'person' | 'company', required: Whether the recipients are people or companies.
    - `steps` CampaignStep[], required: The steps of the campaign, by position. A campaign that sends a single email has one step.
      - `position` integer, required: The 1-based position of the step in the campaign. Steps are addressed by position.
      - `sender` object, nullable, required: Who the step is sent from. Each step has its own sender. `id` is null once the sender was deleted; `email` and `displayName` are then those the step was set up with. Null when the step has no sender.
        - `id` string, nullable, required: The ID of the sender, or null once it was deleted. `email` and `displayName` are then those the email was set up with.
        - `email` string, required: The email address the email is sent from.
        - `displayName` string, nullable, required: The name the email is sent under.
      - `subject` string, required: The subject template, in plain text with `{{variables}}`. Literal `{{` is written `\{{`.
      - `body` string, required: The body template, in HTML with `{{variables}}`. Always HTML, whatever format it was written in. A signed body ends with `<p>{{signature}}</p>`; an unsubscribe link is `<a href="{{unsubscribeLink}}">`.
      - `cc` string[], required: Email addresses copied on every message.
      - `bcc` string[], required: Email addresses blind-copied on every message.
      - `delayDays` integer, required: Days to wait after the previous step before sending this one. 0 for the first step.
      - `sameThread` boolean, required: Whether the step is sent as a reply in the first step's thread, with its subject.
      - `status` 'draft' | 'processing' | 'in_review' | 'scheduled' | 'sending' | 'sent' | 'cancelled' | 'failed', required: The status of the step. One of: draft, processing, in_review, scheduled, sending, sent, cancelled, failed. `scheduled` means the campaign is scheduled or sending, and the step waits for its send date.
      - `messageCount` integer, required: The number of messages generated for this step.
      - `sentCount` integer, required: The number of messages of this step that were sent.
      - `notSentCount` integer, required: The number of messages of this step that were not sent.
    - `stopOnReply` boolean, required: Whether the remaining steps stop for a recipient who replied.
    - `recipientCount` integer, required: The number of recipients of the campaign.
    - `createdBy` string, required: The ID of the user who created the campaign.
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, nullable, required
    - `scheduledAt` string, date-time, nullable, required
    - `startedAt` string, date-time, nullable, required
    - `finishedAt` string, date-time, nullable, required
    - `error` 'spam_detected' | 'not_enough_credits' | 'send_failed' | 'generation_failed' | 'review_failed' | 'null', nullable, required: Why the campaign failed, when its status is `failed`, or what went wrong while preparing a `draft` or `in_review` campaign, such as `generation_failed` when its messages could not all be generated. One of: spam_detected, not_enough_credits, send_failed, generation_failed, review_failed.
  - `deprecations` string[]

## Other responses

- `400`: The request was unacceptable, often due to missing an invalid parameter.
- `401`: No valid API key provided.
- `403`: The API key doesn’t have permissions to perform the request.
- `404`: The requested resource doesn’t exist.
- `409`: A request with the same `Idempotency-Key` is still being processed, or the resource is in a state that does not allow the operation.
- `422`: The request was unacceptable, often due to missing or invalid parameters.
- `429`: Too many requests hit the API too quickly. We recommend an exponential backoff of your requests.
- `500`: Something went wrong on our end.
- `503`: The server is overloaded or down for maintenance.

## Changes

- **2026-11-03** `c6818f3ba60d`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/folk/apis/folk-external-api/changes/v1/campaigns/:campaignId/stop/post.md)

---

[API](https://skmtc.dev/folk/apis/folk-external-api.md) - [All operations](https://skmtc.dev/folk/apis/folk-external-api/llms.txt) - [OpenAPI document](https://skmtc.dev/folk/apis/folk-external-api/revisions/c6818f3ba60d?raw)
