Skip to main content
DeveloperAPI Reference

Campaigns API

Create, manage, and monitor cold email campaigns programmatically via the NimbusOS REST API, with examples for launch, pause, analytics, and enrollment.

9 min read
Updated April 23, 2026
2,000 words

The Campaigns API exposes the full campaign lifecycle: create, configure, enroll contacts, launch, pause, resume, analyze, and archive. Every endpoint respects workspace isolation and the deliverability brain's resume gate. This article covers the endpoints with example requests, the interactions with contacts and sequences, and the common programmatic patterns.

Base URL and Authentication

https://getnimbusos.com/api/v1/campaigns/

Bearer token authentication. JWT or API key with the campaigns:read and campaigns:write scopes.

Campaign Object

{
  "id": "camp_abc123",
  "workspace_id": "ws_xyz789",
  "name": "Q2 Cold Outreach - Tier A RevOps",
  "status": "active",
  "campaign_type": "cold_outreach",
  "platform": "reachinbox",
  "sequence_id": "seq_def456",
  "sending_account_ids": ["ea_001", "ea_002", "ea_003"],
  "min_health_score": 70,
  "daily_send_limit": 500,
  "max_new_leads_per_day": 50,
  "smart_time_gaps": true,
  "send_window_start": 9,
  "send_window_end": 17,
  "send_days": [1, 2, 3, 4, 5],
  "open_tracking_enabled": true,
  "link_tracking_enabled": true,
  "stop_on_reply": true,
  "stop_on_domain_reply": false,
  "stop_on_unsubscribe": true,
  "contact_filter": {
    "segment_ids": ["seg_hot_abc"],
    "icp_tier": ["A"],
    "grade": ["A", "B"]
  },
  "metrics": {
    "total_sent": 1250,
    "delivered": 1238,
    "opened": 622,
    "clicked": 89,
    "replied": 47,
    "bounced": 12,
    "unsubscribed": 3,
    "spam_complaints": 0,
    "open_rate": 0.503,
    "reply_rate": 0.038,
    "bounce_rate": 0.010
  },
  "started_at": "2026-04-10T09:00:00Z",
  "created_at": "2026-04-09T16:00:00Z",
  "updated_at": "2026-04-23T14:00:00Z"
}

List Campaigns

GET /api/v1/campaigns/?status=active,paused&page_size=50

Query parameters:

  • status: draft, active, paused, completed, archived
  • campaign_type: cold_outreach, nurture, re_engagement, warmup
  • platform: reachinbox, smartlead, instantly, lemlist, native
  • client_id: agency-only filter
  • created_after, updated_after

Response has the same cursor pagination shape as Contacts API.

Get Campaign

GET /api/v1/campaigns/camp_abc123/

Returns the full campaign object with metrics.

Create Campaign

POST /api/v1/campaigns/
Content-Type: application/json

{
  "name": "Q2 Cold Outreach - Tier A RevOps",
  "campaign_type": "cold_outreach",
  "platform": "reachinbox",
  "sequence_id": "seq_def456",
  "sending_account_ids": ["ea_001", "ea_002", "ea_003"],
  "min_health_score": 70,
  "daily_send_limit": 500,
  "max_new_leads_per_day": 50,
  "smart_time_gaps": true,
  "send_window_start": 9,
  "send_window_end": 17,
  "stop_on_reply": true,
  "contact_filter": {
    "segment_ids": ["seg_hot_abc"]
  }
}

Creation returns the campaign in draft status with a 201. Campaigns are not live until explicitly launched.

Validation runs on create:

  • sequence_id must exist in the workspace
  • sending_account_ids must exist and be active
  • contact_filter must resolve to at least 1 contact

Validation errors return 400 with field-level detail.

Update Campaign

PATCH /api/v1/campaigns/camp_abc123/
Content-Type: application/json

{
  "daily_send_limit": 750,
  "max_new_leads_per_day": 75
}

Some fields can be updated after launch (limits, filters). Others are immutable once active (campaign_type, platform). Attempting to update an immutable field returns 422.

Launch Campaign

POST /api/v1/campaigns/camp_abc123/launch/

Runs the resume gate check for cold_outreach campaigns. Returns:

  • 200 OK: campaign moved to active status.
  • 422 Gate Blocked: the resume gate failed. Response body includes the specific reason (e.g., "fleet has only 14 stage 3+ inboxes; 20 required").

When the gate blocks, the campaign remains in draft. You can fix the underlying condition and re-launch.

Pause Campaign

POST /api/v1/campaigns/camp_abc123/pause/
Content-Type: application/json

{
  "reason": "reviewing_copy"
}

Halts sends immediately. In-flight sends already queued for the current batch complete. New enrollments stop.

Resume Campaign

POST /api/v1/campaigns/camp_abc123/resume/

Re-runs the resume gate check (cold_outreach only). On success, campaign moves back to active. Pending sends re-queue at their original schedule; sends past their schedule by over 24 hours are dropped.

Archive Campaign

POST /api/v1/campaigns/camp_abc123/archive/

Moves the campaign to archived status. No further operations allowed except read. Archived campaigns are excluded from the default list view but are retained indefinitely for analytics and audit.

Enrollment Endpoints

Get current enrollments

GET /api/v1/campaigns/camp_abc123/enrollments/?status=active&page_size=100

Returns contact IDs and per-contact sequence state.

Manually enroll contacts

POST /api/v1/campaigns/camp_abc123/enroll/
Content-Type: application/json

{
  "contact_ids": ["cont_abc", "cont_def"]
}

Enrolls the contacts even if they do not match the campaign's filter. Useful for testing or specific overrides.

Remove contacts

POST /api/v1/campaigns/camp_abc123/remove-contacts/
Content-Type: application/json

{
  "contact_ids": ["cont_abc"],
  "stop_pending_sends": true
}

Removes contacts from the campaign. If stop_pending_sends=true, any queued sends for those contacts are canceled.

Analytics Endpoints

Campaign summary

GET /api/v1/campaigns/camp_abc123/analytics/summary/

Returns the metrics object with a time series breakdown.

Step-level breakdown

GET /api/v1/campaigns/camp_abc123/analytics/steps/

Returns per-step metrics for the campaign's sequence.

Reply intent distribution

GET /api/v1/campaigns/camp_abc123/analytics/reply-intents/

Returns counts per reply intent category.

Bounce breakdown

GET /api/v1/campaigns/camp_abc123/analytics/bounces/

Returns bounce classification counts and sample SMTP codes.

Export

GET /api/v1/campaigns/camp_abc123/export/?format=csv&include=events

Generates an export with the full send log. Async for campaigns over 10k sends; returns a job ID to poll.

Webhook Events

Campaign events emitted via webhook:

  • campaign.created
  • campaign.launched
  • campaign.paused
  • campaign.resumed
  • campaign.auto_paused (from deliverability brain)
  • campaign.completed
  • campaign.archived

Subscribe through the Webhooks API.

Common Patterns

Pattern 1: Create and launch in one script

import requests

headers = {"Authorization": "Bearer nmbapi_..."}

# Create draft
resp = requests.post(
    "https://getnimbusos.com/api/v1/campaigns/",
    headers=headers,
    json={
        "name": "Automated Q3 Cold",
        "campaign_type": "cold_outreach",
        "platform": "reachinbox",
        "sequence_id": "seq_abc",
        "sending_account_ids": ["ea_001", "ea_002"],
        "contact_filter": {"segment_ids": ["seg_hot"]},
        "max_new_leads_per_day": 25,
    },
)
camp_id = resp.json()["id"]

# Launch
launch = requests.post(
    f"https://getnimbusos.com/api/v1/campaigns/{camp_id}/launch/",
    headers=headers,
)
if launch.status_code == 422:
    print("Gate blocked:", launch.json())

Pattern 2: Daily metrics pull

Scheduled job pulls metrics for every active campaign and writes to an internal data warehouse for custom dashboards.

GET /api/v1/campaigns/?status=active

Then for each, GET /api/v1/campaigns/:id/analytics/summary/.

Pattern 3: Auto-pause on external signal

External system detects a quality issue. Calls POST /api/v1/campaigns/:id/pause/ with a reason. Team is notified via Slack. Investigation happens before manual resume.

Pattern 4: Sequence rotation

Script creates a new campaign weekly with the latest sequence template, enrolls the next batch of contacts from a segment, launches after the gate clears. This is how agencies run continuous outreach pipelines without manual campaign creation.

Rate Limits

Campaign endpoints respect the standard API rate limits (see Rate Limits article). Launch and resume are counted as multiple operations internally; expect to be able to launch several campaigns per minute, not dozens.

Bulk analytics pulls for many campaigns in parallel should stay under 10 concurrent requests to avoid rate limit blowback.

Error Responses

Common campaign-specific errors:

  • 422 gate_blocked: resume gate failed on launch or resume
  • 409 invalid_transition: trying to pause a draft, launch an active, etc.
  • 422 empty_filter: contact filter resolves to zero contacts
  • 422 inactive_inbox: a selected sending account is paused

Response body includes actionable detail.

Troubleshooting

"Campaign was created but has zero enrollments after 1 hour"

Contact filter is empty. Check contact_filter resolves to contacts. Run the search endpoint with the same filter to verify.

"Launch returned 422 and I cannot figure out why"

The 422 response includes a blocking_reasons array. Check each reason. Most common: fleet stage count, bounce rate, or no eligible sending inbox.

"Analytics summary is empty even though the campaign is live"

First sends take 5 to 15 minutes to process. If longer, check the campaign's enrollment count. Zero enrollments means the contact filter is producing no matches.

"Pause did not stop queued sends"

Pause halts enrollment and new sends but does not cancel sends that are already in the platform-level send queue. Use remove-contacts with stop_pending_sends=true to cancel specific pending sends.

Frequently Asked Questions

Can I clone a campaign via API?

Yes. POST /api/v1/campaigns/:id/clone/ creates a new draft with the same configuration. Name appends "(copy)" by default. Clone does not carry over enrollments.

How do I get the real-time send log?

GET /api/v1/campaigns/:id/sends/ with cursor pagination. For streaming, use the webhook events (email.sent, etc.) rather than polling this endpoint.

Can I create a campaign from a template via API?

Not directly. Create from scratch with the sequence_id of a template-derived sequence. Full template-to-campaign shortcut is a UI-only feature.

Is there a rate limit on campaign creation?

10 campaign creations per minute per workspace is the soft limit. For higher volume, contact support.

Useful next pages after this one: Contacts API for the contact endpoints that campaigns reference, Webhooks API for the event stream from campaigns, and Rate Limits for throughput management.

Related articles

Still stuck?

Our team answers every support ticket. If the answer is not in the docs, open a ticket and we will write the missing page.