Preflight check reference
Every preflight check a voice campaign can fail, what each code actually means, and the exact change that clears it — including the ones you cannot clear yourself.
Preflight is the deterministic compliance and operational check that stands between a campaign and a phone ringing. It runs server-side, it is the same code every time, and the model is never consulted — which is why the codes below are worth learning. A check either blocks (error) or needs acknowledging (warning). Preflight passes when there are no errors, whatever the warnings say.
Before you start
Running a preflight needs the voice edit permission. Viewers see results only after someone with the permission has run one.
When it runs
Three times, and this catches people out:
- At approval — and again inside the Approve dialog, so a stale pass is not accepted.
- At launch, resume included. Launch is refused if any check fails, even if approval succeeded an hour earlier.
- Before every single dial, with the lead's own checks added on top.
The panel says it plainly: Compliance checks re-run server-side at approval, launch, and before every dial.
How to read a row
Each row carries a code (the machine name, worth quoting in a support message), a severity, a plain-English message, a remediation line, and — for per-lead checks — the number of leads affected. The remediation text comes from the check itself, not from a help article, so it is always accurate for your exact situation.
Campaign checks that block
These are checked before approval, before launch, and again before every dial.
| Code | What it means | How to clear it |
|---|---|---|
emergency_stop_active | The workspace emergency stop is on. Every campaign is paused and no launch can succeed | Clear it in Settings → Voice & Telephony → Emergency stop |
agent_version_unpublished | The campaign points at an agent draft | Publish the agent version, or select a published one on the campaign |
product_version_unpublished | The campaign points at a product draft | Publish the product version, or select a published one |
disclosure_missing | No AI disclosure text is configured | Fill Honest disclosure wording on the agent version, then publish it |
recording_policy_missing | The workspace has never chosen a recording policy | Set Recording policy in Settings → Voice & Telephony |
calling_window_missing | The campaign has no calling windows at all | Configure at least one allowed day and time window |
transfer_unconfigured | Allow human transfer is on with an empty destination | Set a Destination number in Tools and guardrails, or switch transfer off |
transfer_unconfigured is the most common first failure
Turning on Allow human transfer reveals the destination fields but does not require them, so it is easy to leave the number blank and move on. The check fires at approval, long after you have forgotten. If you are not actually transferring anyone yet, switch Allow human transfer off — that clears it too.
Caller ID and live-call checks
These only fire when the workspace is on a live voice runtime. On the default mock runtime they are skipped entirely — which is why a campaign can look perfectly healthy and still never dial a real number.
| Code | What it means | How to clear it |
|---|---|---|
caller_id_missing | No approved caller number is selected on the campaign | Select an active, approved caller number in the campaign settings |
caller_id_inactive | The selected number exists but is not activated | Activate it in the telephony settings, or choose another |
caller_id_not_allowed | The number is not allowed for this campaign | Allow the number for the campaign in the phone-number settings |
live_calls_disabled | Live calling is off at the platform level | Not clearable from the admin. Live dialing is armed by Zyan — contact support |
allowlist_empty | The campaign is in test mode and the live-call allowlist is empty, so nothing is dialable | Verified test destinations must be added to the allowlist at the platform level |
You cannot arm live calling from Settings
live_calls_disabled and allowlist_empty name platform environment
settings, not fields in the admin portal. No toggle in
SettingsVoice & Telephony clears them. Until Zyan arms
live dialing for your workspace, use Voice Lab, scenario simulation, or a live
usability test to a saved test number.
External verified caller ID
Using a verified number that Zyan does not own is behind an experimental flag and restricted to test-mode campaigns. Three codes come out of it:
| Code | Severity | What it means | How to clear it |
|---|---|---|---|
external_caller_id_forbidden | Error | The campaign's caller number is an external verified caller ID and the experimental flag is off | Use a platform-owned number instead. The flag is not exposed in the admin — contact Zyan support if you need it |
external_caller_id_requires_test_mode | Error | The flag is on, but the campaign is not in test mode | Keep Test campaign ticked while using an external caller ID |
external_caller_id_experimental | Warning | The campaign will display an external verified caller ID; attestation, reputation and callback behaviour may differ from a platform-owned number | Acknowledge it at approval, then watch attestation after each call and be ready to disable |
external_caller_id_forbidden is not a mistake you made
It means the number you chose is a verified caller ID rather than a number owned by the platform, and that path is experimental. The fix is to select a different caller number, not to change a setting. There is no in-app switch for the flag.
Audience checks
| Code | Severity | What it means | How to clear it |
|---|---|---|---|
audience_policy_denied | Error | Audience classification is consumer cold, which is denied by default policy | Reclassify: consent-backed leads, internal test numbers, or a counsel-approved B2B classification. There is no override |
audience_b2b_ack | Warning | B2B calling rules vary by jurisdiction and industry | Confirm counsel has reviewed the applicable federal, state, industry, recording, disclosure, calling-hour and do-not-call rules, then type the acknowledgment at approval |
Per-lead checks
These are added to the campaign checks immediately before each attempt. They appear in the preflight panel with an affected-lead count, and in the Block reason column on the campaign's Leads table.
| Code | What it means | How to clear it |
|---|---|---|
invalid_destination | The lead's number is not valid E.164 | Fix or remove the lead's phone number |
lead_suppressed | The lead is suppressed or previously opted out | Suppressed leads are never dialed. Remove the lead from the campaign |
wrong_number | The number was previously recorded as a wrong number | Update the lead with a corrected number before any further attempt |
no_consent | The campaign is consent-backed and this lead has no valid consent record | Attach a consent record with evidence, or reclassify the campaign under an approved policy |
consent_expired | The lead's consent record has expired | Re-obtain consent, or remove the lead |
outside_calling_window | The lead's local time is outside the campaign's windows | Nothing to fix — the dialer defers until the next window opens |
max_attempts_reached | The lead has used all its allowed attempts | No further attempts are permitted for that lead |
cooldown_active | The retry cooldown has not elapsed since the last attempt | Wait. The remediation names the exact number of minutes left |
destination_not_allowlisted | The campaign is in test mode and this destination is not on the live-call allowlist | Add the number to the allowlist at the platform level, or take the campaign out of test mode through the approval flow |
Checks that defer rather than stop
Three checks are temporary by nature. The per-lead errors
outside_calling_window and cooldown_active both mean not yet: the dialer
defers the attempt and comes back. daily_cap_reached is a campaign-level
warning that resolves itself the next day.
| Code | Severity | Behaviour |
|---|---|---|
outside_calling_window | Error, per lead | Deferred until the lead's next window opens |
cooldown_active | Error, per lead | Deferred until the cooldown elapses |
daily_cap_reached | Warning, campaign | Dialing resumes on the next allowed day, or raise Daily cap |
A roster full of outside_calling_window at four in the afternoon is not a
fault. A roster full of it at eleven in the morning means your Timezone
fallback is wrong for those leads.
Warnings and the typed acknowledgment
Warnings do not block preflight, but they do block the Approve dialog until you type an exact acknowledgment phrase. The label reads Type “…” to continue and it is matched byte-for-byte — this is an API contract, not free text. Copy the phrase from the label rather than typing it from memory.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Preflight passed at approval and the launch was still refused | Preflight re-runs at launch; something changed in between | Run it again and read the new rows — the emergency stop and version status are the usual culprits |
| A check names an environment setting you cannot find | live_calls_disabled, allowlist_empty and the external caller ID flag are platform-level | They are not exposed in the admin portal — contact Zyan support |
| Preflight looks clean but no real calls happen | The mock runtime skips the caller-ID and live-call checks entirely | A clean preflight on the mock runtime is not proof of live readiness |
| The same lead is blocked every time you look | max_attempts_reached or lead_suppressed are permanent for that lead | Correct the record, or remove the lead |
| Approve stays disabled with no visible error | A warning is present and the acknowledgment has not been typed exactly | Copy the phrase from the label |
| A campaign that ran yesterday now fails on the agent version | Publishing a new agent version archives the old one | A pinned version stays usable after approval; drafts must point at the current published version |