# How Lead Sync Works

## When a lead syncs

A lead is sent to Aktify automatically when any of the following happens:

- A lead is **added to an Active campaign that has an API key** as a Campaign Member — from the campaign's **Add Leads** button, **Add to Campaign** on a list view or report, the Data Import Wizard, web-to-lead, or any other tool that creates Campaign Members. The package fills in the lead's **Aktify Campaign Id** for you (see [Campaign Members and the Aktify Campaign Id field](#campaign-members-and-the-aktify-campaign-id-field)).
- A lead is **created** with **Aktify Campaign Id** set.
- An existing unsynced lead's **Aktify Campaign Id** is set or changed.
- An existing unsynced lead's **State** or **Zip/Postal Code** is corrected.
- An existing unsynced lead's value changes in any field that is [mapped to metadata](#sending-metadata-with-leads) for its campaign.
- An API key is added to (or activated on) an Active campaign. This also picks up the campaign's existing Campaign Members.

:::caution Adding an API key backfills the whole campaign
The last trigger applies to **all** of the campaign's unsynced leads at once: pasting a key into an Active campaign immediately posts every lead already assigned to it, plus every Lead that is a Campaign Member and not yet assigned to another Aktify campaign. Make sure the campaign's leads are ready to be contacted before you add the key.
:::

## Campaign Members and the Aktify Campaign Id field

Salesforce has two ways a lead can be "in" a campaign, and it helps to know which one drives the sync:

| | What it is | Who sets it |
|---|---|---|
| **Campaign Member** | Salesforce's own record of a Lead (or Contact) belonging to a Campaign. Every standard add-to-campaign action creates one. | Add Leads, Add to Campaign, imports, web-to-lead, marketing tools. |
| **Aktify Campaign Id** | The packaged lookup field on the Lead that names the **one** Aktify campaign the lead is posted to. This is what the sync reads. | The package, automatically, when a Lead becomes a Campaign Member of an Active keyed campaign. Admins can also set it directly on the Lead. |

When a Lead becomes a Campaign Member of a campaign that is **Active** and has an **Aktify Campaign API Key**, the package sets the lead's **Aktify Campaign Id** to that campaign, and the lead is posted. You don't need to touch the field yourself.

A few rules follow from the field holding a single campaign:

- **One Aktify campaign per lead.** A lead that already has an **Aktify Campaign Id** keeps it. Adding that lead to a second Aktify campaign as a Campaign Member does not re-post it or move it. Aktify already has the lead in the first campaign.
- **Only Leads sync.** Contacts added to a campaign are ignored by the package.
- **Converted leads are skipped.**
- **Campaigns without a key, or not Active, claim nothing.** Members added before the key existed are picked up when the key is saved, or from the **Sync Campaign Members** tab.

### The Sync Campaign Members tab

The **Sync Campaign Members** tab in the **Aktify** app lists every campaign that has an API key with four counts: how many Leads are Campaign Members, how many Leads have their **Aktify Campaign Id** pointing at it, and how many of those have and haven't synced.

Click **Sync Members** on a campaign to assign every Lead member that doesn't yet have an Aktify campaign. Use it for members added before the campaign had its key, or before your org upgraded to 1.2.0. The confirmation message reports how many leads were queued and why any were skipped: already assigned to this campaign, already assigned to another Aktify campaign, converted, Contacts, or the campaign being inactive or keyless.

:::caution Sync Members posts leads right away
Like pasting an API key, **Sync Members** immediately posts every unassigned Lead member of the campaign. Make sure the campaign's members are ready to be contacted.
:::

## What a lead needs to qualify

Each lead must have:

- A valid US phone number.
- At least one valid geo signal:
  - A two-character state code or full state name in **State** (e.g. `CA` or `California`), **or**
  - A valid US zip code in **Zip/Postal Code** (`12345` or `12345-6789`).

Leads with neither geo signal are not sent — **Aktify Sync Failed Reason** reads `Valid two-character state or US postal code required`. Fixing the State or Zip/Postal Code retries the sync automatically.

## Sync results

- **Success:** **Aktify Synced** is checked on the lead.
- **Failure:** **Aktify Sync Failed Reason** holds the reason. Common examples:
  - `Api Key required` — the lead has no **Aktify Campaign Id**, or its campaign has no API key set.
  - A duplicate-lead response — the phone number already exists in the Aktify campaign.

See the [Troubleshooting](./troubleshooting) page for the full reference.

## Sending metadata with leads

Aktify campaigns can carry **metadata** on each lead: named values that Aktify uses to personalize messaging or route the conversation. A campaign may *require* certain keys — Aktify tells you which when they provide the campaign's API key.

Metadata mappings are configured **per Campaign**, in the **Aktify Metadata Mapping** card on the **Aktify Create Lead Config Setting** tab (or on the Campaign record, if the component has been added to its page). Each row is one key:

| Column | Meaning |
|---|---|
| **Metadata Key** | The key name exactly as Aktify configured it. Letters, digits, underscores, and hyphens only; each key appears once per campaign. |
| **Lead Field** | The Lead field whose value is sent. Any Lead field can be chosen, standard or custom. Leave it as *No Lead field* to send only the default value. |
| **Default Value** | Sent when the Lead field is blank, or always when no Lead field is chosen. |

### How the value is chosen

For each row, the value sent is:

1. The Lead field's value, if it isn't blank;
2. otherwise the **Default Value**, if set;
3. otherwise an empty string.

Every value is sent as text. Numbers, checkboxes, and dates are converted to their text form, and **picklists send the stored API name, not the display label**. If Aktify expects a different value than your field holds (for example your Plan picklist stores `T3` but the campaign expects `premium`), create a **formula field** on Lead that returns the expected value and map that instead — the package does not translate values.

Campaigns with no mapping rows send no metadata at all, which is fine for campaigns that don't use it.

Saving mappings also re-posts any of the campaign's leads that Aktify previously rejected for missing metadata, so a campaign that was connected before its mappings were configured recovers on its own.

:::caution Required keys must be present, not just non-empty
Aktify checks that each required key is *present* on the lead. An empty string satisfies the check, but it produces an empty spot in any message that uses the key — so give required keys a sensible **Default Value** or make sure the mapped field is always populated.
:::

### Example

A campaign's outreach mentions the plan each lead asked about, so it requires a `plan_tier` key. Your Lead object has a formula field **Aktify Plan Tier** that returns `basic`, `plus`, or `premium` from your existing Plan picklist. The mapping row is:

| Metadata Key | Lead Field | Default Value |
|---|---|---|
| `plan_tier` | Aktify Plan Tier | `basic` |

A lead whose Plan resolves to `premium` is posted with `plan_tier = premium`; a lead with no Plan is posted with `plan_tier = basic`.

## Manual re-sync

The **Sync Lead** tab in the **Aktify** app lists leads that haven't synced. Select the leads you want and click **Sync with Aktify**.

To re-send a lead that already synced, uncheck **Aktify Synced** on the lead first, then sync it again.

## Status sync-back (Aktify → Salesforce)

A scheduled job polls Aktify and updates each synced lead's **Aktify Lead Status** plus the activity counters (**Aktify Calls Placed**, **Aktify Calls Received**, **Aktify Messages Sent**, **Aktify Messages Received**).

**No dedicated setup is required.** Polling activates automatically — with an hourly default — the first time an admin opens the **Aktify** app's config tab or saves a campaign API key, both of which happen during normal setup.

### Changing the polling cadence

On the **Aktify Create Lead Config Setting** tab in the **Aktify** app, the **Status Sync Schedule** card lets an admin pick the interval — **Hourly** (every 1–23 hours), **Daily**, **Every 15 Minutes**, or **Every 30 Minutes**. Saving replaces the existing scheduled job with the new cadence.

The same card's **Sync Statuses Now** button runs one poll immediately — useful for testing or when you don't want to wait for the next scheduled run.

### How it stays reliable

- The poll tracks how far it has successfully processed (**Last Job Run Time** on the config record). A failed or interrupted run resumes from where it stopped instead of skipping that time window.
- Very busy windows (more than 1,000 status changes) are fetched in smaller time slices automatically.
- If a run has errors, they are listed in a warning box below the **Status Sync Schedule** card on the **Aktify Create Lead Config Setting** tab, per campaign — that is the first place to look if statuses stop updating. The poll never raises an error or sends exception emails; a campaign Aktify reports as **stopped** is noted and skipped without holding back the others.
