Skip to content
linkifunnels.com Open app

Add a contact to a campaign via the API

Enroll a person in a campaign's email sequence from your server when there is no tracked click to attribute, such as an organic signup or a CRM sync.

10 minutesOwner or editor

A person enters a campaign’s email sequence in one of three ways: they become a lead through a tracked link, you add them by hand on the Recipients tab, or your server adds them with this endpoint. Use it when signups reach you without a click id, for example organic traffic, a newsletter form, or a sync from your CRM.

POSThttps://app.linkifunnels.com/api/v1/campaigns/{slug}/leads

The slug is the last part of the campaign’s address in the app, app.linkifunnels.com/campaigns/<slug>. Authenticate with an API token from Settings, then Connect your site, then Manage tokens, passed as a bearer token. Tokens are scoped to one workspace. See Authenticate API requests.

Terminal window
curl -X POST \
https://app.linkifunnels.com/api/v1/campaigns/welcome-series/leads \
-H "Authorization: Bearer $LINKIFUNNELS_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "dana@northwind.io",
"name": "Dana Whitaker",
"external_id": "cus_8201"
}'

When to use it instead of the conversions API

Section titled “When to use it instead of the conversions API”

If the visitor arrived through a tracked link, send the click id to the conversions API instead. That credits the post that produced the lead and enrolls the person in the campaign automatically. This endpoint has no click to attribute, so it records the lead against the campaign directly. The person counts in the campaign’s leads, appears on the Recipients tab and in Contacts with “API” as how they came in, and does not appear in any post’s numbers.

Send JSON. Only email is required.

Parameter Type Required Description
email string Yes The person’s email address. Matched case-insensitively against the contacts in your workspace
name string No Stored on the contact. An existing name is overwritten
external_id string No A stable id from your system, the same one you send to the conversions API, so a later sale ties to this contact
Email alone is enough
{ "email": "dana@northwind.io" }

The response always carries an outcome so you can tell what happened without inspecting the rest.

Status outcome Meaning
201 created A new contact was created, recorded as a lead of the campaign, and enrolled
201 reused An existing contact was recorded as a lead and enrolled, or a stopped enrollment was resumed from its next unsent email without a new lead
200 already_enrolled The contact is already in the sequence. The enrollment is untouched, though a name or external_id you sent is still applied to the contact
200 suppressed The address has unsubscribed or bounced. Nothing was enrolled and enrollment is null

The call is idempotent. Sending the same email twice returns already_enrolled the second time, so retries after a timeout are safe. The first email goes out after its configured delay, counted from the moment of enrollment, once the sequence is live. A campaign without an active email accepts contacts too: they wait with next_send_at set to null, and the first send is scheduled when you activate an email.

Response
{
"outcome": "created",
"contact": {
"id": 1204,
"email": "dana@northwind.io",
"name": "Dana Whitaker",
"external_id": "cus_8201"
},
"enrollment": {
"id": 5531,
"state": "active",
"enrolled_at": "2026-09-22T09:41:12Z",
"next_send_at": "2026-09-22T09:41:12Z"
}
}

Anyone who unsubscribed from your emails or whose address bounced is on your workspace’s suppression list and is never enrolled, whichever way they arrive. See Handle unsubscribes and bounces. Enrollments created this way count toward your sending limits like any other, and sending pauses automatically when recipients complain.

Status Body Meaning
401 unauthorized The bearer token is missing or revoked
404 unknown campaign No campaign with that slug exists in the token’s workspace
422 email is required The request had no email
429 rate_limited More than 120 enrollments per minute on this token
Error response
{ "error": "unknown campaign" }