Skip to main content

SLA and escalation

Searches run asynchronously. When automation cannot finish, or when time limits are exceeded, SNH AI escalates with verification.action_required (typically HUMAN_ESCALATION). Some post-research action-required events are non-terminal HITL holds: the search stays IN_PROGRESS so a human can add contacts or terminate it. Organization-level policy controls SLA windows and which escalation sources are enabled. Related: Errors · Webhook events · Third-party ban

Workflow terminal conditions

Research phase

  • No contacts / no actionable contacts / voice-only / research task failed: With searchConfig.parallelProcessing: true, non-terminal verification.action_required with HUMAN_ESCALATION and metadata.escalationSubtype of POST_RESEARCH_NO_CONTACTS, POST_RESEARCH_VOICE_ONLY, or POST_RESEARCH_TASK_FAILED. This includes channel-policy dead ends where contacts exist but every method is CHANNEL_DISABLED (for example email contacts when only fax is allowed). The search remains IN_PROGRESS for human contact updates or customer termination. When parallelProcessing is false or omitted (default), those paths terminalize.
  • Third-party record detected: non-terminal verification.action_required with THIRD_PARTY_RECORD (structured contact details). With searchConfig.parallelProcessing: true, the search remains IN_PROGRESS, stores metadata.actionRequiredHold.subtype: "POST_RESEARCH_THIRD_PARTY", and waits for a human contact update or customer termination. When parallelProcessing is false or omitted (default), the path terminalizes (legacy search-wide cancel).
  • Inbound third-party redirect: when third-party deferral is disabled, emits verification.action_required with THIRD_PARTY_RECORD and metadata.actionRequiredHold.subtype: "INBOUND_THIRD_PARTY". With searchConfig.parallelProcessing: true, this is a stay-open hold (pending outbound cancelled for the responding contact thread; other contacts may continue with a no-remaining-work backstop), and automatic SLA reassignment does not terminate the hold. When third-party deferral is enabled, the search stores metadata.pendingThirdParty and keeps trying other channels until the deferred emission is due. When parallelProcessing is false or omitted, inbound third-party paths use legacy search-wide cancel and terminalize.
  • Banned third-party vendor: When searchConfig.thirdPartyBan contains the detected vendor code, the THIRD_PARTY_RECORD webhook is suppressed and the search continues with manual or outbound handling. Inbound redirects to a banned vendor emit non-terminal HUMAN_ESCALATION with metadata.escalationSubtype: "THIRD_PARTY_BAN" and stop only the responding contact thread when parallelProcessing: true; otherwise they use legacy search-wide cancel and terminalize. See Third-party ban.

Outbound phase

  • Transient retry cap reached: After 3 transient retries per channel (voice/email/fax), the search is reassigned with HUMAN_ESCALATION
  • Processing failure: After max retries, the search escalates with SYSTEM_FAILURE, UPSTREAM_ISSUE, or SLA_REACHED

SLA and automatic reassignment

  • Frequency: Checks run every 4 hours (system-level, not configurable)
  • Search SLA: Default 24 hours (organization-configurable via policy.global.searchSlaMinutes)
  • Reassignment window: Default 48 hours (organization-configurable via policy.global.reassignmentWindowMinutes)
  • Weekend adjustment: Deadlines that fall on Saturday/Sunday move to the next Monday (system behavior)
  • Trigger: Whichever of SLA or reassignment window is reached first
  • Reason code: HUMAN_ESCALATION with metadata
  • Contact plan: Optionally included when policy.global.includeContactPlanInEscalation is true (default false)
Example weekend adjustment: search created Friday 5 PM with a 24-hour SLA → Saturday 5 PM is extended to Monday 5 PM.

Configuring SLA settings

These settings are configured at the organization level via unified policy (not per API request unless you use searchConfig.timing):
Per-search overrides: see Search-level configuration (timing.searchSlaMinutes).

Per-source human escalation (optional)

Disable escalation for specific reasons via policy.global.humanEscalation.enabledForSource. Set a source to false to prevent reassignment for that reason. Omitted sources remain enabled. searchConfig.escalation.disableAutoEscalation=true on a search always suppresses escalation for that search, regardless of this tenant-level setting.
Important: Disabling a source means the system will not escalate for that reason. Some searches may remain IN_PROGRESS until another condition is met. Use only when you accept that behavior. Existing organizations are unchanged if they do not set this config.

Important notes

  • When a workflow is terminalized, no further outbound attempts are made
  • Terminal conditions and automatic reassignment are idempotent (no duplicate escalation webhooks)
  • Contact plan data in escalation webhooks is opt-in per organization (includeContactPlanInEscalation)