Leads
Create or upsert lead
Creates a lead or updates the existing non-deleted lead with the same campaign/email pair. This endpoint supports idempotent retries via Idempotency-Key and emits lead.created or lead.updated outbound webhook events.
/v1/campaigns/{id}/leadsAuthorization
bearerAuth Use an account API key in the Authorization header: Authorization: Bearer f_....
In: header
Path Parameters
Campaign id.
uuidHeader Parameters
Optional idempotency key for campaign create, lead create, and bulk lead imports. Retries with the same key and body return the cached response.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
emailOptional person-level tags. Pass catalog names or aliases (for example Hunter, Hunter.io, Running Meta Ads) or any custom name. Matching is case-insensitive. Unknown names create an account-owned tag. Tags attach to the person (global_lead_id), not the campaign lead row, so they persist across campaigns. Do not put MillionVerifier statuses here — use email_verification. Catch-All Domain and Role Account are operator filters and are not auto-applied from verification.
Optional structured email verification from a vendor such as MillionVerifier. Send this when you already paid for a check; omit it otherwise. Status values: ok, catch_all, invalid, unknown, disposable. Stored on lead_email_facts, not as tags, and survives rollup refresh. Do not invent a status.
Value in
- "ok"
- "catch_all"
- "invalid"
- "unknown"
- "disposable"
date-timecurl -X POST "https://example.com/v1/campaigns/497f6eca-6276-4993-bfeb-53cbbbba6f08/leads" \ -H "Content-Type: application/json" \ -d '{ "email": "jane@example.com", "name": "Jane Doe", "first_name": "Jane", "last_name": "Doe", "company_name": "Acme Co", "website": "https://www.acmeco.com", "linkedin_url": "https://www.linkedin.com/in/janedoe", "company_linkedin_url": "https://www.linkedin.com/company/acme-co", "custom_lead_data": { "company": "Acme Co", "source": "Landing Page" }, "tags": [ "Hunter", "ICP Fit" ], "email_verification": { "status": "ok", "provider": "millionverifier", "quality": "good" } }'{ "data": { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "campaign_id": "78614b6c-fe7c-41e2-8e25-c9b3a3c91904", "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65", "global_lead_id": "string", "email": "user@example.com", "name": "string", "first_name": "string", "last_name": "string", "company_name": "string", "website": "string", "linkedin_url": "string", "company_linkedin_url": "string", "phone_number": "string", "mobile_phone_number": "string", "custom_lead_data": {}, "source": "api", "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z", "deleted_at": "2019-08-24T14:15:22Z" }, "created": true}{ "data": { "id": "9c3cb55a-5e5e-47b6-a95e-31461779ce92", "campaign_id": "1d8dc901-3d2d-4d9f-9dcc-4f8b3aa1a1fb", "email": "jane@example.com", "first_name": "Jane", "custom_lead_data": { "company": "Acme Co", "source": "Landing Page" }, "source": "api", "created_at": "2026-05-21T18:00:00.000Z" }, "created": true}{ "error": { "type": "invalid_request_error", "code": "invalid_flow", "message": "Flow validation failed" }, "details": [ { "path": "nodes[1].data.variants[0].id", "code": "invalid_variant_id", "message": "Email variants must have a stable UUID id." } ]}{ "error": { "type": "authentication_error", "code": "invalid_api_key", "message": "A valid Furnace API key is required" }}{ "error": { "type": "permission_error", "code": "smartlead_read_only", "message": "Smartlead campaigns are read-only via the API" }}{ "error": { "type": "invalid_request_error", "code": "campaign_not_found", "message": "Campaign not found" }}{ "error": { "type": "rate_limit_error", "code": "rate_limit_exceeded", "message": "Rate limit exceeded for this account" }}{ "error": { "type": "api_error", "code": "internal_error", "message": "Internal server error" }}