HCC Docs

Existing leads

Leads that arrive reach a running campaign, so a new campaign knows nothing of the leads you already have. A backfill runs them through its filter and onLead, only when you ask: never on a deploy or a resume.

It works while the campaign is paused, and nothing dials until it runs, so you can backfill, see how many enrolled, then turn it on.

const run = await hcc.campaigns.backfill('renewals');

const now = await hcc.campaigns.backfillStatus('renewals');
// { status: 'running', scanned: 40000, checked: 900, enrolled: 310, skipped: 500, failed: 0, ... }

await hcc.campaigns.cancelBackfill('renewals');
await hcc.campaigns.retryBackfill('renewals');

Who it takes

  • The filter comes first, then onLead. Both are what you deployed in .enroll and .onLead: a backfill takes no filter of its own. A campaign with no onLead takes every lead that matches, with no call to your server.
  • Skips. c.remove() here counts as a skip. A lead on your Do Not Call list stays out and counts as a skip too, whatever onLead says, though onLead can still be asked about it.
  • It's safe to repeat. A lead already in the campaign stays where it is, and your server isn't asked about it. A lead that left stays out, whatever onLead says. The exception is a removed one, which onLead can bring back with c.enroll(), to start over, unless the campaign says reenroll: false. With no onLead it stays out.
  • While the campaign is running, the leads it enrolls can be dialed straight away, within calling hours and your limits.

How it runs

  • The filter costs your server nothing, as a lead that doesn't match is never sent. It has no index, so a backfill reads every lead in the environment in small steps. A deploy during a run can narrow it, as a lead has to match the filter it started with and the one deployed now.
  • It goes at your server's pace. At most 4 batches of 50 are unanswered at once, and the next goes when one's answered. Each lead's ctx.eventId is stable across this run's retries and new on the next run.
  • It can't pause your campaign. If your server fails it backs off for about a quarter of an hour, and carries on if it comes back. If not, the run ends as failed, with failure saying why, and retryBackfill goes on from where it stopped.
  • A done run can have failed leads too, when your handler failed for some: retryBackfill asks about only those.
  • One at a time per campaign: a second backfill gets a 409. It needs campaigns:write.

testCampaign has it too: await t.backfill([gold, silver]) says who'd be enrolled and skipped, and t.matches(lead) reads the filter just as we do.