Docs
Campaigns

Enroll contacts

POSThttps://api.norreach.app/v1/campaigns/{id}/enrollments

Puts contacts into a campaign: contact_ids (up to 10,000) or every contact on a list_id (a list of at most as many). Only this workspace's contacts are enrolled (others come back in not_found_ids); contacts already in the campaign are skipped and reported, never enrolled twice; the campaign's own enrollment rules may exclude some (excluded). A live campaign starts them now — or holds each first send in Approvals when it asks before sending; a draft or paused one holds them until it runs. At most 50 000 new enrollments a day per workspace (429 send_cap_reached). The suppression list, consent and quiet hours are checked again at every send. Also needs campaigns:write (it changes the campaign's audience).

⚠ campaigns:launchRole must allow: campaigns.launchIdempotency-Key requiredSupports dry_runReaches peopleOperation id: enroll_contacts
POST/campaigns/{id}/enrollments
curl -X POST "https://api.norreach.app/v1/campaigns/{id}/enrollments" \
  -H "Authorization: Bearer $NORREACH_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "contact_ids": [
    "7d1c3b2a-5e4f-4a1b-9c8d-0e1f2a3b4c5d",
    "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
  ]
}'
Enroll contacts
{
  "object": "enrollment_result",
  "campaign_id": "3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f",
  "dry_run": false,
  "requested": 2,
  "enrolled": 1,
  "already_enrolled": 1,
  "already_enrolled_ids": [
    "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
  ],
  "not_found": 0,
  "not_found_ids": [],
  "excluded": 0,
  "held_for_approval": false,
  "remaining_contact_ids": []
}

Authorizations

Authorizationstringheaderrequired

Bearer authentication: send Authorization: Bearer <key>, with an API key or an OAuth access token. The key needs the scope campaigns:launch. API keys and scopes

Path parameters

idstring (uuid)pathrequired

An id (UUID).

Query parameters

dry_runbooleanquery

Run every check and return what would happen, changing nothing.

Headers

Idempotency-Keystringheaderrequired

Any unique string (≤ 255). The same key with the same request returns the first answer for 24 hours.

Body

application/json

contact_idsstring (uuid)[]
list_idstring (uuid)

An id (UUID).

Response

200application/json— Enroll contacts

object"enrollment_result"required
campaign_idstring (uuid)required

An id (UUID).

dry_runbooleanrequired
requestedintegerrequired

Distinct contacts asked for.

enrolledintegerrequired

New enrollments made (or, in a dry run, at most this many).

already_enrolledintegerrequired
already_enrolled_idsstring (uuid)[]required
not_foundintegerrequired

Ids that aren't contacts of this workspace — never enrolled.

not_found_idsstring[]required
excludedintegerrequired

Skipped by the campaign's own enrollment rules (recently messaged, per-company cap).

held_for_approvalbooleanrequired

The campaign asks before it sends: each first send waits in Approvals.

remaining_contact_idsstring (uuid)[]required

Not processed this time (the request ran out of time) — send them again; already enrolled contacts are skipped.

Errors

Errors are application/problem+json with a stable code.

StatusCodeMeaning
400bad_requestThe request couldn't be read.
400unknown_fieldThe request has a field this operation doesn't know.
400idempotency_key_requiredThis operation needs an Idempotency-Key header.
401unauthorizedA valid API key is required.
403insufficient_scopeThis API key doesn't have the scope this operation needs.
403feature_not_enabledThe API isn't switched on for this workspace.
403role_forbiddenThe key's creator's role can't do this.
404not_foundThat doesn't exist.
409idempotency_in_progressA request with this Idempotency-Key is still running.
409conflictThat conflicts with the current state.
409outreach_pausedOutreach is paused for this workspace.
413too_largeThe request body is too large.
422validation_failedThe request has invalid fields.
422idempotency_mismatchThis Idempotency-Key was used with a different request.
429rate_limitedToo many requests. Slow down and try again.
429send_cap_reachedThe workspace's sending limit for now is reached.
500server_errorSomething went wrong on our side.
503unavailableThe API isn't available right now. Try again shortly.