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).

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 PUT /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).