Skip to main content
POST
Add Lead to Campaign Endpoint

Endpoint

  • Method: POST
  • Path: /api/campaigns/{id}/leads
{id} is the campaign ID in Tuco. Copy the campaign ID from the campaign detail page in the app (copy button next to the ID).

Path parameter

string
required
The campaign id. Copy it from the campaign detail page in the app (the copy button next to the ID). A campaign that is not in your workspace returns 404.

Request body

Send either leadId (enrol a lead you already have) or lead (create-or-reuse one). Sending neither returns 400.
string
An existing lead id. Must belong to the same workspace.
object
Create a new lead — or reuse the matching one — and enrol it. See Deduplication for what counts as a match.

Quick start (copy-paste example)

Request (existing lead):
Request (create new lead and add to campaign):
Response (201):

Use Cases

  • Enroll an existing lead into an iMessage campaign from your backend or CRM.
  • Create a new lead and add them to a running or scheduled campaign in a single call.

Request Body (Existing Lead)

Tuco will:
  • Validate that the lead belongs to the same workspace.
  • Attach the lead to the campaign’s list (if needed).
  • Create the campaign messages for that lead based on the campaign’s steps and settings.

Request Body (Create & Add Lead)

If you send lead instead of leadId, Tuco:
  • Creates the lead in the same workspace.
  • Adds it to the campaign’s underlying list.
  • Starts that lead through the campaign sequence.

Response

When the lead is already enrolled in this campaign, you receive 200 instead of 201:
If the campaign or lead cannot be found you receive a 404. If the payload is invalid (for example, missing both leadId and lead) you receive a 400 with a descriptive error. Authentication failures return 401.

Deduplication

When you send lead (rather than leadId), Tuco runs a workspace-wide dedup check before creating anything. Match rule: any of email, phone, altEmail1-3, altPhone1-3 matching an existing lead (after normalization) reuses that lead. Normalization:
  • email → trimmed and lowercased
  • phone → E.164 (+15551234567)
Important: when an existing lead matches, the request body fields (firstName, email, phone, companyName, etc.) are NOT applied to it. The existing lead is reused as-is. To update a matched lead, call PATCH /api/leads/{id} separately, then add to the campaign by leadId.

GHL Workflow Integration (15-minute sync gap)

Tuco’s GHL connector syncs contacts on a 15-minute schedule. To enroll a GHL contact into a Tuco campaign immediately, call this endpoint from a GHL workflow Webhook action.

How merging works across the sync gap

When you add a lead via this API and the periodic GHL sync later sees the same contact, Tuco merges by phone only (integration-sync.ts). Recommendation: pass ghlContactId (and optionally ghlLocationId) in the request body for deterministic linking. The endpoint:
  • Adds integrationIds.ghlRecordId to the dedup match (a second call with the same ghlContactId reuses the lead even if phone or email shifted).
  • Backfills integrationIds.ghlRecordId / ghlLocationId onto a matched existing lead when the lead doesn’t have them yet (never overwrites).
If you can’t pass ghlContactId, always send phone in E.164 — the next periodic GHL sync (every 15 minutes) merges by phone. Email-only matching at sync time is not supported and will create a duplicate GHL-sourced lead. The same applies for HubSpot via hsContactId (stored as integrationIds.hubspotRecordId).