MCP

prospect/post_bulk

Tool: create

bulk-upsert prospects by email into a list and/or campaign.

Upserts each prospect by email (inserts new, updates existing) and optionally adds all to a list and/or campaign. Returns counters and prospect IDs for every affected row.

This is the campaign-enrolment path. Passing campaignId (see Params) adds contacts to a campaign — the intended, safe use for enrolling new contacts. The merge caveat below is about values you explicitly supply overwriting existing ones — it has nothing to do with enrolment, and omitted fields are never at risk. End-to-end flow: sending-a-campaign.

Upsert is keyed by email and MERGES onto existing prospects — provided fields overwrite, omitted fields are preserved (not cleared). Never send null here: it is silently dropped, yet the response still reports the prospect as updated, so it looks like a successful write while the old value survives (call-contract). To update a single existing prospect, prospect/patch_by_id is more direct. Without listId, prospects are subscribed to the account's 'Unassigned' list (subscriptionsAdded:1 reflects that implicit assignment). The Unassigned list is an ordinary list — it can be renamed or deleted like any other.

Max 100 rows per call (split larger imports). Enrolling into a Running campaign starts sending to those prospects immediately — get the user's confirmation first.

Naming trap: this op takes query param listId; single create (prospect/post) takes body field baseListId. They are NOT interchangeable.

Campaign enrollment: passing campaignId enrolls prospects into the campaign's FIRST sequence; there is no sequence-targeting option.

campaignAdded: -1 is a sentinel, not a count — it can come back in place of 0/1, sometimes with totalProcessed: 0. Its meaning is unspecified, so it is evidence neither of enrolment nor of a skip: settle it by reading prospect/get with includeCampaignIds.campaignIds: [<campaignId>].

Conditional — shown while this account's documentation includes the Outreach Playbook

Load quality is decided before this call. Email finding and verification gives the bounce numbers to hold a list to — total under 2%, hard bounces under 1% — why to verify before every send rather than once at build time, and how to handle catch-all and role addresses. List hygiene and data quality covers what else makes an import safe: B2B contact data decays 22-28% a year, deduplicate by person and by company, and opt-outs and hard bounces must stay suppressed across list rebuilds.

Arguments

name type req notes
listId integer List to assign all prospects to; omitted → Unassigned list
campaignId integer Enrols into campaign's first sequence
addOnlyIfNew boolean Skip prospects already in CRM when true
notInOtherCampaign boolean Skip prospects enrolled in any other campaign when true

Body

field type req constraints description
prospects array ≥1 items Array of prospect objects; each is upserted by email
prospects[].email string ≤256 chars Email key for the upsert
prospects[].firstName string ≤512 chars Omitted → preserved on existing prospects; send "" to clear — never null
prospects[].lastName string ≤512 chars Omitted → preserved on existing prospects; send "" to clear — never null
prospects[].company string ≤512 chars Omitted → preserved on existing prospects; send "" to clear — never null
prospects[].sendingStatus string see schemas/prospect Campaign participation state
prospects[].sendingActive boolean Whether eligible for campaign sending
prospects[].industry string ≤512 chars
prospects[].city string ≤512 chars
prospects[].website string ≤512 chars
prospects[].phone string ≤512 chars
prospects[].country string ≤512 chars
prospects[].domain string ≤180 chars
prospects[].companySocial string ≤512 chars
prospects[].companySize string ≤32 chars
prospects[].jobPosition string ≤512 chars
prospects[].location string ≤512 chars
prospects[].personalSocial string ≤512 chars
prospects[].customImageUrl string ≤256 chars
prospects[].screenshotUrl string ≤256 chars
prospects[].logoUrl string ≤256 chars
prospects[].state string ≤128 chars
prospects[].icebreaker string ≤4000 chars
prospects[].custom1–custom20 string ≤2000 chars each Free-text custom fields
prospects[].notes string Internal notes

Response

201 — upsert summary with IDs; 200 — empty OK (no-op path).

field type description
totalProcessed integer Total prospects processed (inserts + updates)
prospectsInserted integer New prospects created
prospectsUpdated integer Existing prospects updated
duplicatesInBatch integer Duplicate emails removed from the batch before processing
subscriptionsAdded integer List subscriptions created (includes implicit Unassigned assignment)
campaignAdded integer Prospects enrolled into the campaign (only when campaignId supplied); -1 is a sentinel, not a count — see the note above
prospectIds array Prospect IDs affected by this operation
prospectIdByEmail object Map of normalized email → prospectId for affected rows

Errors: 400, 401, 404, 406, 409, 415, 422, 429, 500 — shared schema: schemas/errors.

Invoke

Call create with name: "prospect/post_bulk".