On this page

POST/campaigns/:campaignId/leads/batch-update

Credits: None
LinkedIn risk: None


Purpose

Update tag, excluded, and/or CRM/profile fields for up to 100 leads in one call. Prefer this over many PATCH …/leads/:leadId calls.

CRM fields match the in-app editor (empty string clears). LinkedIn URL is not writable.

Exclude is workspace-global when a LinkedIn URL is available. If there is no LinkedIn URL, only the campaign lead’s excluded flag is set locally (same as single PATCH). Auto-exclude tags (Not interested, Wrong person) apply immediately (unlike some inbox flows).


Request

POST /campaigns/search_abc/leads/batch-update
X-API-Key: sk_live_...
Idempotency-Key: optional-key
Content-Type: application/json
{
  "updates": [
    { "leadId": "lead_xyz", "excluded": true },
    { "leadId": "lead_abc", "tag": "Interested", "custom1": "Warm intro" }
  ]
}
FieldNotes
updatesYes — non-empty array, length 1…maxItems (default/hard max 100)
updates[].leadIdRequired; lead_ prefix normalized
updates[].tagOptional; allowlisted labels or null to clear
updates[].excludedOptional boolean
updates[].…Optional CRM/profile strings (same keys as PATCH lead)

At least one of tag / excluded / a CRM field per item. Unknown top-level keys → 400. Soft per-item: bad id, duplicate leadId (first wins), auto-exclude tag + excluded: false.

Idempotency: array order matters (fingerprint). Persist 200 only when summary.updated > 0.


Response 200

{
  "results": [
    {
      "index": 0,
      "leadId": "lead_xyz",
      "status": "updated",
      "tag": null,
      "excluded": true
    }
  ],
  "summary": {
    "total": 1,
    "updated": 1,
    "not_found": 0,
    "validation_error": 0,
    "failed": 0
  },
  "creditsCharged": 0
}

Statuses: updated · not_found · validation_error · failed. Optional fields object when CRM writes landed.

If the handler fails mid-batch after durable writes, response is still 200 with completed rows as updated (only fields that actually landed — e.g. a tagged auto-exclude row does not claim excluded: true until the bulk/local exclude step succeeds) and remaining as failed. Idempotency-Key is persisted when summary.updated > 0.


vs single PATCH

BehaviorPATCHBatch update
Auto-exclude timingMay defer in some inbox flowsImmediate
Global exclude (with LinkedIn URL)Yes (per lead)Yes (one bulk)
No LinkedIn URL + excludeLead flag onlySame (local mark)
excluded: falseLead flag onlySame
CRM/profile scalarsYesYes
lead.tagged webhook1Up to 100

MCP

Tool: update_leads_batch.