Campaigns
Open as markdownFor 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.
| Operation | What it does |
|---|---|
GET /v1/campaigns | List campaigns. |
POST /v1/campaigns | Create a draft campaign with its sequence. |
GET /v1/campaigns/{id} | One campaign. |
POST /v1/campaigns/{id}/prospects | Import prospects: dedupe, suppression, region gate, verification, one credit each. |
GET /v1/campaigns/{id}/preflight | Everything that still blocks launch. |
POST /v1/campaigns/{id}/launch | Launch through the sending engine. |
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. |
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). |
GET /v1/campaigns/{id}/report | Sent, 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#
| Name | Type | Notes |
|---|---|---|
limit | integer | Rows per page, 1 to 100. More than 100 is held to 100. |
cursor | string | The 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.
{
"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
}statusisdraft,activeorpaused.pause_reasonexplains a pause andpause_originsays who paused it (customerorsystem); both arenullotherwise.- Oldest first, 20 a page. Send
limit(1 to 100) for more, and sendnext_cursorback ascursorfor the next page;next_cursorisnullon 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 inRetry-After.
Example request#
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.
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | Yes | Up to 120 characters. |
timezone | string | No | Default "America/New_York". At least 3 characters. Up to 64 characters. |
steps | array of object | Yes | 1 to 6 items. |
steps[].delay_days | integer | Yes | Days to wait after the previous step. 0 for step 1. From 0 to 30. |
steps[].variants | array of object | Yes | A/B alternatives. The first is the control. Every body must contain {{unsubscribe}} and {{sender_address}}. 1 to 4 items. |
steps[].variants[].subject | string | Yes | Up to 200 characters. |
steps[].variants[].body | string | Yes | Up to 5000 characters. |
Example body:
{
"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.
{
"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
bodymust contain both{{unsubscribe}}and{{sender_address}}. The first step hasdelay_days0 and later steps wait at least 1 day. - A subject that starts with
Re:orFwd: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 inRetry-After.
Example request#
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#
| Name | Type | Notes |
|---|---|---|
id | string | Id of the campaign. |
Response#
Status 200 OK.
{
"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 inRetry-After.
Example request#
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#
| Name | Type | Notes |
|---|---|---|
id | string | Id of the campaign. |
Request body#
Send a JSON object.
| Field | Type | Required | Notes |
|---|---|---|---|
allow_risky | boolean | No | Also import role mailboxes and free-provider addresses. Default false. |
prospects | array of object | Yes | 1 to 500 items. |
prospects[].email | string | Yes | An email address. It is trimmed and lowercased. Up to 254 characters. |
prospects[].first_name | string | No | Up to 80 characters. |
prospects[].company | string | No | Up to 120 characters. |
prospects[].country | string | Yes | ISO 3166-1 alpha-2 country of the prospect. Required: it decides region gating. Exactly 2 characters. |
Example body:
{
"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.
{
"imported": 2,
"skipped": [
{
"email": "lena@fabrikam.example",
"reason": "region_blocked"
}
],
"credits_charged": 2,
"credits_remaining": 9848
}skipped[].reasonis one ofinvalid_email,duplicate_in_request,region_blocked,suppressed,already_imported,suppressed_or_already_imported, or a verification verdict such asinvalid: domain accepts no mail.- Prospects in the EU, UK and Israel are skipped as
region_blocked. riskyaddresses (role mailboxes and free providers) are skipped unless you sendallow_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 inRetry-After.
Example request#
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#
| Name | Type | Notes |
|---|---|---|
id | string | Id of the campaign. |
Response#
Status 200 OK.
{
"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 inRetry-After.
Example request#
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#
| Name | Type | Notes |
|---|---|---|
id | string | Id of the campaign. |
Response#
Status 200 OK.
{
"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 inRetry-After.
Example request#
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#
| Name | Type | Notes |
|---|---|---|
id | string | Id of the campaign. |
Response#
Status 200 OK.
{
"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.statusispaused,not_launchedfor a draft, orunavailablewith amessagewhen 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 inRetry-After.
Example request#
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#
| Name | Type | Notes |
|---|---|---|
id | string | Id of the campaign. |
Response#
Status 200 OK.
{
"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_reasonandpause_origin(customerorsystem) 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 inRetry-After.
Example request#
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#
| Name | Type | Notes |
|---|---|---|
id | string | Id of the campaign. |
Response#
Status 200 OK.
{
"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
nulluntil at least one send is recorded. They are fractions, so0.05is 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 inRetry-After.
Example request#
curl YOUR_API_BASE_URL/v1/campaigns/cmp_2LmQx7RtVw3ZbN1pEs9fKd/report \
-H "Authorization: Bearer $COLDMEETINGS_API_KEY"