Rewrite One Sentence Across A Campaign’s Unsent Copy
li_bulk_edit_stepsFind an exact sentence in a campaign's UNSENT message steps and replace it, across every contact in one call.
A strategy's text is snapshotted PER PROSPECT at import, so a retired line exists once per person; use this for the SAME sentence campaign-wide, li_edit_step for per-person corrections.
⚠️ EXACT SUBSTRING, NEVER A REGEX or a pattern of any kind. $& and $1 in the replacement are literal characters. That is a safety property, not a simplification: there is no prior text stored anywhere, so a pattern typed against hundreds of live queues could not be undone.
⚠️ dryRun DEFAULTS TO TRUE. The first call previews: it reports how many steps match, what each would become, and how many CONTACTS hold no match at all. Pass dryRun=false to write.
⚠️ READ contactsUnmatched — it is the field that tells you your find-string was wrong. "191 changed, 23 people do not have that sentence" is a completely different fact from "done", and only that number says which. truncated means the cap stopped the scan, so the sweep is PARTIAL: run it again, or raise limit.
Every write goes through the same per-step guards as li_edit_step, so a step that sends between the preview and the write is refused rather than overwritten and lands in refused. Nothing is rescheduled — only the words change.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| find | Yes | The exact text to find, matched as a plain substring. An empty string is refused — it matches every step. | |
| kind | No | Narrow to ONE step of the sequence (e.g. followup_1). Omitted sweeps all of them. | |
| limit | No | How many unsent steps to scan (max 500). The reply says `truncated` when the cap stopped it, so a partial sweep never reads as a complete one. | |
| dryRun | No | DEFAULTS TO TRUE — preview only, nothing written. Pass false to apply the rewrite. | |
| replace | Yes | What to put in its place, inserted literally. Pass "" to delete the text. | |
| campaignId | Yes | The campaign whose unsent copy to sweep — from li_list_campaigns. | |
| afterStepId | No | Continue a capped sweep from here — pass the `resumeAfterStepId` the previous reply gave you. Without it a second call re-reads the SAME window, and because the first run already replaced those lines they come back as `contactsUnmatched` — the field that means your find-string was wrong. So "run it again" needs this, or it reports the opposite of what happened. 1,630 steps against a cap of 500 is three calls. |