Campaigns

Open as markdown

For AI agents: the docs index is at /llms.txt, and every page is also served as markdown at its URL plus .md.

A campaign is a sequence of steps, a list of prospects and a status. This is where credits are spent: each imported prospect costs one.

Base URL: YOUR_API_BASE_URL. Every request and response is JSON. Errors use one envelope.

OperationWhat it does
GET /v1/campaignsList campaigns.
POST /v1/campaignsCreate a draft campaign with its sequence.
GET /v1/campaigns/{id}One campaign.
POST /v1/campaigns/{id}/prospectsImport prospects: dedupe, suppression, region gate, verification, one credit each.
GET /v1/campaigns/{id}/preflightEverything that still blocks launch.
POST /v1/campaigns/{id}/launchLaunch through the sending engine.
POST /v1/campaigns/{id}/pausePause a campaign. Always pauses locally, even when the engine is unreachable; an unconfirmed engine pause is retried until it succeeds.
POST /v1/campaigns/{id}/resumeResume a campaign you paused. Runs the preflight, removes suppressed leads at the sending engine, then restarts it. Refused while the engine has not confirmed the pause (409), and for a campaign ColdMeetings paused itself (403).
GET /v1/campaigns/{id}/reportSent, bounce, complaint and reply rates, reply intents, meetings booked.

GET/v1/campaigns#

List campaigns.

Authentication: send your API key as a bearer token. See Authentication.

Query parameters#

NameTypeNotes
limitintegerRows per page, 1 to 100. More than 100 is held to 100.
cursorstringThe next_cursor of the previous page, sent back unchanged to the same route. Leave it out for the first page. A cursor that was edited or came from another route is refused.

Response#

Status 200 OK.

JSON
{
  "campaigns": [
    {
      "id": "cmp_2LmQx7RtVw3ZbN1pEs9fKd",
      "name": "Q4 outbound to software teams",
      "status": "draft",
      "timezone": "America/New_York",
      "pause_reason": null,
      "pause_origin": null,
      "steps": [
        {
          "delay_days": 0,
          "variants": [
            {
              "subject": "Outbound without the busywork",
              "body": "Hello,\n\nWe run outbound for B2B software teams, from sending domains to booked calls. Would a short call about your pipeline be useful?\n\n{{sender_address}}\n{{unsubscribe}}"
            }
          ]
        },
        {
          "delay_days": 3,
          "variants": [
            {
              "subject": "Following up",
              "body": "Hello,\n\nA quick follow up on my note. If outbound is not a priority this quarter, tell me and I will stop writing.\n\n{{sender_address}}\n{{unsubscribe}}"
            }
          ]
        }
      ],
      "created_at": "2026-10-17T12:00:00.000Z",
      "launched_at": null
    }
  ],
  "next_cursor": null
}
  • status is draft, active or paused. pause_reason explains a pause and pause_origin says who paused it (customer or system); both are null otherwise.
  • Oldest first, 20 a page. Send limit (1 to 100) for more, and send next_cursor back as cursor for the next page; next_cursor is null on the last page.

Errors#

  • unauthorized, HTTP 401: The API key is missing, malformed, revoked or unknown.
  • rate_limited, HTTP 429: Too many requests for this key. Wait the number of seconds in Retry-After.

Example request#

Shell
curl YOUR_API_BASE_URL/v1/campaigns \
  -H "Authorization: Bearer $COLDMEETINGS_API_KEY"

POST/v1/campaigns#

Create a draft campaign with its sequence.

Creates a draft. Nothing is sent until you import prospects and launch.

Authentication: send your API key as a bearer token. See Authentication.

Request body#

Send a JSON object.

FieldTypeRequiredNotes
namestringYesUp to 120 characters.
timezonestringNoDefault "America/New_York". At least 3 characters. Up to 64 characters.
stepsarray of objectYes1 to 6 items.
steps[].delay_daysintegerYesDays to wait after the previous step. 0 for step 1. From 0 to 30.
steps[].variantsarray of objectYesA/B alternatives. The first is the control. Every body must contain {{unsubscribe}} and {{sender_address}}. 1 to 4 items.
steps[].variants[].subjectstringYesUp to 200 characters.
steps[].variants[].bodystringYesUp to 5000 characters.

Example body:

JSON
{
  "name": "Q4 outbound to software teams",
  "timezone": "America/New_York",
  "steps": [
    {
      "delay_days": 0,
      "variants": [
        {
          "subject": "Outbound without the busywork",
          "body": "Hello,\n\nWe run outbound for B2B software teams, from sending domains to booked calls. Would a short call about your pipeline be useful?\n\n{{sender_address}}\n{{unsubscribe}}"
        }
      ]
    },
    {
      "delay_days": 3,
      "variants": [
        {
          "subject": "Following up",
          "body": "Hello,\n\nA quick follow up on my note. If outbound is not a priority this quarter, tell me and I will stop writing.\n\n{{sender_address}}\n{{unsubscribe}}"
        }
      ]
    }
  ]
}

Response#

Status 201 Created.

JSON
{
  "id": "cmp_2LmQx7RtVw3ZbN1pEs9fKd",
  "name": "Q4 outbound to software teams",
  "status": "draft",
  "timezone": "America/New_York",
  "pause_reason": null,
  "pause_origin": null,
  "steps": [
    {
      "delay_days": 0,
      "variants": [
        {
          "subject": "Outbound without the busywork",
          "body": "Hello,\n\nWe run outbound for B2B software teams, from sending domains to booked calls. Would a short call about your pipeline be useful?\n\n{{sender_address}}\n{{unsubscribe}}"
        }
      ]
    },
    {
      "delay_days": 3,
      "variants": [
        {
          "subject": "Following up",
          "body": "Hello,\n\nA quick follow up on my note. If outbound is not a priority this quarter, tell me and I will stop writing.\n\n{{sender_address}}\n{{unsubscribe}}"
        }
      ]
    }
  ],
  "created_at": "2026-10-17T12:00:00.000Z",
  "launched_at": null
}
  • Every body must contain both {{unsubscribe}} and {{sender_address}}. The first step has delay_days 0 and later steps wait at least 1 day.
  • A subject that starts with Re: or Fwd: is refused, because it pretends to continue an earlier thread.

Errors#

  • unauthorized, HTTP 401: The API key is missing, malformed, revoked or unknown.
  • invalid_input, HTTP 400: The sequence breaks a rule. The message lists every problem. A body that is empty, is not JSON or fails validation also answers this, and the message names the field.
  • payload_too_large, HTTP 413: The body is over 256 KiB.
  • rate_limited, HTTP 429: Too many requests for this key. Wait the number of seconds in Retry-After.

Example request#

Shell
curl -X POST YOUR_API_BASE_URL/v1/campaigns \
  -H "Authorization: Bearer $COLDMEETINGS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Q4 outbound to software teams",
  "timezone": "America/New_York",
  "steps": [
    {
      "delay_days": 0,
      "variants": [
        {
          "subject": "Outbound without the busywork",
          "body": "Hello,\n\nWe run outbound for B2B software teams, from sending domains to booked calls. Would a short call about your pipeline be useful?\n\n{{sender_address}}\n{{unsubscribe}}"
        }
      ]
    },
    {
      "delay_days": 3,
      "variants": [
        {
          "subject": "Following up",
          "body": "Hello,\n\nA quick follow up on my note. If outbound is not a priority this quarter, tell me and I will stop writing.\n\n{{sender_address}}\n{{unsubscribe}}"
        }
      ]
    }
  ]
}'

GET/v1/campaigns/{id}#

One campaign.

Authentication: send your API key as a bearer token. See Authentication.

Path parameters#

NameTypeNotes
idstringId of the campaign.

Response#

Status 200 OK.

JSON
{
  "id": "cmp_2LmQx7RtVw3ZbN1pEs9fKd",
  "name": "Q4 outbound to software teams",
  "status": "draft",
  "timezone": "America/New_York",
  "pause_reason": null,
  "pause_origin": null,
  "steps": [
    {
      "delay_days": 0,
      "variants": [
        {
          "subject": "Outbound without the busywork",
          "body": "Hello,\n\nWe run outbound for B2B software teams, from sending domains to booked calls. Would a short call about your pipeline be useful?\n\n{{sender_address}}\n{{unsubscribe}}"
        }
      ]
    },
    {
      "delay_days": 3,
      "variants": [
        {
          "subject": "Following up",
          "body": "Hello,\n\nA quick follow up on my note. If outbound is not a priority this quarter, tell me and I will stop writing.\n\n{{sender_address}}\n{{unsubscribe}}"
        }
      ]
    }
  ],
  "created_at": "2026-10-17T12:00:00.000Z",
  "launched_at": null
}

Errors#

  • unauthorized, HTTP 401: The API key is missing, malformed, revoked or unknown.
  • unknown_product, HTTP 404: No such campaign on this account.
  • rate_limited, HTTP 429: Too many requests for this key. Wait the number of seconds in Retry-After.

Example request#

Shell
curl YOUR_API_BASE_URL/v1/campaigns/cmp_2LmQx7RtVw3ZbN1pEs9fKd \
  -H "Authorization: Bearer $COLDMEETINGS_API_KEY"

POST/v1/campaigns/{id}/prospects#

Import prospects: dedupe, suppression, region gate, verification, one credit each.

Each prospect that is imported costs one prospect credit. Skipped prospects cost nothing.

Authentication: send your API key as a bearer token. See Authentication.

Path parameters#

NameTypeNotes
idstringId of the campaign.

Request body#

Send a JSON object.

FieldTypeRequiredNotes
allow_riskybooleanNoAlso import role mailboxes and free-provider addresses. Default false.
prospectsarray of objectYes1 to 500 items.
prospects[].emailstringYesAn email address. It is trimmed and lowercased. Up to 254 characters.
prospects[].first_namestringNoUp to 80 characters.
prospects[].companystringNoUp to 120 characters.
prospects[].countrystringYesISO 3166-1 alpha-2 country of the prospect. Required: it decides region gating. Exactly 2 characters.

Example body:

JSON
{
  "allow_risky": false,
  "prospects": [
    {
      "email": "jordan@northwind.example",
      "first_name": "Jordan",
      "company": "Northwind",
      "country": "US"
    },
    {
      "email": "sam@contoso.example",
      "first_name": "Sam",
      "company": "Contoso",
      "country": "CA"
    },
    {
      "email": "lena@fabrikam.example",
      "first_name": "Lena",
      "company": "Fabrikam",
      "country": "DE"
    }
  ]
}

Response#

Status 201 Created.

JSON
{
  "imported": 2,
  "skipped": [
    {
      "email": "lena@fabrikam.example",
      "reason": "region_blocked"
    }
  ],
  "credits_charged": 2,
  "credits_remaining": 9848
}
  • skipped[].reason is one of invalid_email, duplicate_in_request, region_blocked, suppressed, already_imported, suppressed_or_already_imported, or a verification verdict such as invalid: domain accepts no mail.
  • Prospects in the EU, UK and Israel are skipped as region_blocked.
  • risky addresses (role mailboxes and free providers) are skipped unless you send allow_risky: true.
  • Credits are held while the import runs and charged only for prospects that were really imported. A failed request releases the hold.

Errors#

  • unauthorized, HTTP 401: The API key is missing, malformed, revoked or unknown.
  • invalid_input, HTTP 400: The campaign is not a draft, or the body is invalid. A body that is empty, is not JSON or fails validation also answers this, and the message names the field.
  • payload_too_large, HTTP 413: The body is over 256 KiB.
  • unknown_product, HTTP 404: No such campaign on this account.
  • insufficient_credits, HTTP 402: The import needs more credits than the account has. Nothing is imported or charged.
  • provider_unavailable, HTTP 503: Verification could not be reached. Nothing is charged.
  • rate_limited, HTTP 429: Too many requests for this key. Wait the number of seconds in Retry-After.

Example request#

Shell
curl -X POST YOUR_API_BASE_URL/v1/campaigns/cmp_2LmQx7RtVw3ZbN1pEs9fKd/prospects \
  -H "Authorization: Bearer $COLDMEETINGS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "allow_risky": false,
  "prospects": [
    {
      "email": "jordan@northwind.example",
      "first_name": "Jordan",
      "company": "Northwind",
      "country": "US"
    },
    {
      "email": "sam@contoso.example",
      "first_name": "Sam",
      "company": "Contoso",
      "country": "CA"
    },
    {
      "email": "lena@fabrikam.example",
      "first_name": "Lena",
      "company": "Fabrikam",
      "country": "DE"
    }
  ]
}'

GET/v1/campaigns/{id}/preflight#

Everything that still blocks launch.

Lists everything that still blocks a launch. ready is true when blockers is empty.

Authentication: send your API key as a bearer token. See Authentication.

Path parameters#

NameTypeNotes
idstringId of the campaign.

Response#

Status 200 OK.

JSON
{
  "ready": false,
  "blockers": [
    "The campaign has no prospects. Import some first.",
    "No mailbox sits on a domain with verified SPF, DKIM and DMARC."
  ]
}

Errors#

  • unauthorized, HTTP 401: The API key is missing, malformed, revoked or unknown.
  • unknown_product, HTTP 404: No such campaign on this account.
  • rate_limited, HTTP 429: Too many requests for this key. Wait the number of seconds in Retry-After.

Example request#

Shell
curl YOUR_API_BASE_URL/v1/campaigns/cmp_2LmQx7RtVw3ZbN1pEs9fKd/preflight \
  -H "Authorization: Bearer $COLDMEETINGS_API_KEY"

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

Launch through the sending engine.

Runs the same checks as preflight, then hands the campaign to the sending engine.

Authentication: send your API key as a bearer token. See Authentication.

Path parameters#

NameTypeNotes
idstringId of the campaign.

Response#

Status 200 OK.

JSON
{
  "id": "cmp_2LmQx7RtVw3ZbN1pEs9fKd",
  "name": "Q4 outbound to software teams",
  "status": "active",
  "timezone": "America/New_York",
  "pause_reason": null,
  "pause_origin": null,
  "steps": [
    {
      "delay_days": 0,
      "variants": [
        {
          "subject": "Outbound without the busywork",
          "body": "Hello,\n\nWe run outbound for B2B software teams, from sending domains to booked calls. Would a short call about your pipeline be useful?\n\n{{sender_address}}\n{{unsubscribe}}"
        }
      ]
    },
    {
      "delay_days": 3,
      "variants": [
        {
          "subject": "Following up",
          "body": "Hello,\n\nA quick follow up on my note. If outbound is not a priority this quarter, tell me and I will stop writing.\n\n{{sender_address}}\n{{unsubscribe}}"
        }
      ]
    }
  ],
  "created_at": "2026-10-17T12:00:00.000Z",
  "launched_at": "2026-10-17T12:00:00.000Z"
}

Errors#

  • unauthorized, HTTP 401: The API key is missing, malformed, revoked or unknown.
  • unknown_product, HTTP 404: No such campaign on this account.
  • invalid_input, HTTP 400: Preflight found blockers. The message lists them.
  • provider_unavailable, HTTP 503: The sending engine could not be reached. The campaign stays a draft.
  • rate_limited, HTTP 429: Too many requests for this key. Wait the number of seconds in Retry-After.

Example request#

Shell
curl -X POST YOUR_API_BASE_URL/v1/campaigns/cmp_2LmQx7RtVw3ZbN1pEs9fKd/launch \
  -H "Authorization: Bearer $COLDMEETINGS_API_KEY"

POST/v1/campaigns/{id}/pause#

Pause a campaign. Always pauses locally, even when the engine is unreachable; an unconfirmed engine pause is retried until it succeeds.

The campaign is paused here first, even when the sending engine cannot be reached. A pause the engine has not confirmed is retried until it does, and the campaign cannot be resumed meanwhile. A background job checks every 5 minutes for retries that are due. Attempts wait 5 minutes, 30 minutes, 2 hours, 6 hours and then 12 hours; when the last attempt fails, an operator is told.

Authentication: send your API key as a bearer token. See Authentication.

Path parameters#

NameTypeNotes
idstringId of the campaign.

Response#

Status 200 OK.

JSON
{
  "id": "cmp_2LmQx7RtVw3ZbN1pEs9fKd",
  "name": "Q4 outbound to software teams",
  "status": "paused",
  "timezone": "America/New_York",
  "pause_reason": "paused by customer",
  "pause_origin": "customer",
  "steps": [
    {
      "delay_days": 0,
      "variants": [
        {
          "subject": "Outbound without the busywork",
          "body": "Hello,\n\nWe run outbound for B2B software teams, from sending domains to booked calls. Would a short call about your pipeline be useful?\n\n{{sender_address}}\n{{unsubscribe}}"
        }
      ]
    },
    {
      "delay_days": 3,
      "variants": [
        {
          "subject": "Following up",
          "body": "Hello,\n\nA quick follow up on my note. If outbound is not a priority this quarter, tell me and I will stop writing.\n\n{{sender_address}}\n{{unsubscribe}}"
        }
      ]
    }
  ],
  "created_at": "2026-10-17T12:00:00.000Z",
  "launched_at": "2026-10-17T12:00:00.000Z",
  "engine": {
    "status": "paused"
  }
}
  • engine.status is paused, not_launched for a draft, or unavailable with a message when the engine could not be told yet.

Errors#

  • unauthorized, HTTP 401: The API key is missing, malformed, revoked or unknown.
  • unknown_product, HTTP 404: No such campaign on this account.
  • rate_limited, HTTP 429: Too many requests for this key. Wait the number of seconds in Retry-After.

Example request#

Shell
curl -X POST YOUR_API_BASE_URL/v1/campaigns/cmp_2LmQx7RtVw3ZbN1pEs9fKd/pause \
  -H "Authorization: Bearer $COLDMEETINGS_API_KEY"

POST/v1/campaigns/{id}/resume#

Resume a campaign you paused. Runs the preflight, removes suppressed leads at the sending engine, then restarts it. Refused while the engine has not confirmed the pause (409), and for a campaign ColdMeetings paused itself (403).

Starts a campaign you paused sending again. Before anything starts, the preflight runs and every address you have suppressed since is removed from the campaign's leads at the sending engine; if the engine does not confirm, nothing starts. A campaign that ColdMeetings paused itself, for example for spam complaints, cannot be resumed with this request. Only an operator can resume it, and only once the 7-day cooldown has passed since the pause.

Authentication: send your API key as a bearer token. See Authentication.

Path parameters#

NameTypeNotes
idstringId of the campaign.

Response#

Status 200 OK.

JSON
{
  "id": "cmp_2LmQx7RtVw3ZbN1pEs9fKd",
  "name": "Q4 outbound to software teams",
  "status": "active",
  "timezone": "America/New_York",
  "pause_reason": null,
  "pause_origin": null,
  "steps": [
    {
      "delay_days": 0,
      "variants": [
        {
          "subject": "Outbound without the busywork",
          "body": "Hello,\n\nWe run outbound for B2B software teams, from sending domains to booked calls. Would a short call about your pipeline be useful?\n\n{{sender_address}}\n{{unsubscribe}}"
        }
      ]
    },
    {
      "delay_days": 3,
      "variants": [
        {
          "subject": "Following up",
          "body": "Hello,\n\nA quick follow up on my note. If outbound is not a priority this quarter, tell me and I will stop writing.\n\n{{sender_address}}\n{{unsubscribe}}"
        }
      ]
    }
  ],
  "created_at": "2026-10-17T12:00:00.000Z",
  "launched_at": "2026-10-17T12:00:00.000Z"
}
  • pause_reason and pause_origin (customer or system) show why a paused campaign is paused.

Errors#

  • unauthorized, HTTP 401: The API key is missing, malformed, revoked or unknown.
  • unknown_product, HTTP 404: No such campaign on this account.
  • invalid_input, HTTP 400: The campaign is not a paused campaign that was launched, or the preflight found blockers (the message lists them).
  • forbidden, HTTP 403: ColdMeetings paused this campaign itself, for example for spam complaints. Only an operator can lift that pause, and only after the 7-day cooldown.
  • conflict, HTTP 409: The engine has not confirmed the campaign's pause yet, or the plan's active campaigns are all in use.
  • provider_unavailable, HTTP 503: The sending engine could not remove suppressed leads or start the campaign. Nothing was started and the campaign stays paused.
  • rate_limited, HTTP 429: Too many requests for this key. Wait the number of seconds in Retry-After.

Example request#

Shell
curl -X POST YOUR_API_BASE_URL/v1/campaigns/cmp_2LmQx7RtVw3ZbN1pEs9fKd/resume \
  -H "Authorization: Bearer $COLDMEETINGS_API_KEY"

GET/v1/campaigns/{id}/report#

Sent, bounce, complaint and reply rates, reply intents, meetings booked.

Authentication: send your API key as a bearer token. See Authentication.

Path parameters#

NameTypeNotes
idstringId of the campaign.

Response#

Status 200 OK.

JSON
{
  "campaign": {
    "id": "cmp_2LmQx7RtVw3ZbN1pEs9fKd",
    "name": "Q4 outbound to software teams",
    "status": "active",
    "timezone": "America/New_York",
    "pause_reason": null,
    "pause_origin": null,
    "steps": [
      {
        "delay_days": 0,
        "variants": [
          {
            "subject": "Outbound without the busywork",
            "body": "Hello,\n\nWe run outbound for B2B software teams, from sending domains to booked calls. Would a short call about your pipeline be useful?\n\n{{sender_address}}\n{{unsubscribe}}"
          }
        ]
      },
      {
        "delay_days": 3,
        "variants": [
          {
            "subject": "Following up",
            "body": "Hello,\n\nA quick follow up on my note. If outbound is not a priority this quarter, tell me and I will stop writing.\n\n{{sender_address}}\n{{unsubscribe}}"
          }
        ]
      }
    ],
    "created_at": "2026-10-17T12:00:00.000Z",
    "launched_at": "2026-10-17T12:00:00.000Z"
  },
  "prospects": 2,
  "sent": 120,
  "bounces": 2,
  "complaints": 0,
  "replies": 6,
  "bounce_rate": 0.0167,
  "reply_rate": 0.05,
  "spam_rate": 0,
  "reply_intents": {
    "interested": 2,
    "not_interested": 3,
    "opt_out": 1
  },
  "meetings_booked": 1
}
  • The rates are null until at least one send is recorded. They are fractions, so 0.05 is five percent.

Errors#

  • unauthorized, HTTP 401: The API key is missing, malformed, revoked or unknown.
  • unknown_product, HTTP 404: No such campaign on this account.
  • rate_limited, HTTP 429: Too many requests for this key. Wait the number of seconds in Retry-After.

Example request#

Shell
curl YOUR_API_BASE_URL/v1/campaigns/cmp_2LmQx7RtVw3ZbN1pEs9fKd/report \
  -H "Authorization: Bearer $COLDMEETINGS_API_KEY"
Documentation menu