---
title: Adverse action
description: How an AdverseAction node fires, the notice stages and flows, the draft-first default, the webhook events it emits, and where the notice PDFs end up.
canonical_url: "https://cascades.crscreditapi.com/docs/concepts/adverse-action"
doc_version: "1.0.0"
last_updated: "2026-09-23T19:55:02Z"
source: docs/concepts/adverse-action.md
---

# Adverse action

When a cascade declines an applicant on the basis of a consumer report, the FCRA requires an **adverse-action notice**. In Cascades that is an `Action` node with `action_type: "AdverseAction"`: it picks the reasons from the conditions that failed, renders the operator's notice template to a PDF, emails it to the applicant, and keeps the archive. The API sees the results as execution state, webhook events and notice artifacts.

For the legal background and the operator's obligations, see [Adverse action notices](/docs/compliance/adverse-action-notices).

## Where does the node sit, and why does it matter?

An `AdverseAction` node must be downstream of an `IfElse` decision, and its branch decides its mode:

| Placement | Mode | Runs when |
|---|---|---|
| In the decision's `human_review_steps` | **Human review** | The decision flags the execution for review — the draft is rendered before the pause; a reviewer sends or skips it on denial |
| In the decision's `fail_steps` | **Rejected** | The decision auto-fails the applicant |
| In `pass_steps`, or not under any decision | invalid | The cascade will not save |

## Draft first, or auto-send?

A decline never delivers a notice unattended unless the node opts in. The node's `send_strategy` is:

- **`draft_first`** (default) — the executor parks an editable **draft** (reasons, recipient, rendered PDF) and the execution waits. An operator reviews and sends it from the app; sending records the denial and delivers in one step. Approving the applicant instead discards the draft.
- **`auto_send`** — an explicit opt-in for unattended API and batch runs: the notice is generated and emailed immediately.

Human-review mode pre-generates the draft when the execution is flagged, so the reviewer's **Deny** dialog already shows the pre-selected reasons and lets them edit or skip the notice (a skip is recorded as `notice_intentionally_skipped` in the audit trail, never as compliant).

## Which reasons go on the notice?

The executor looks at the conditions that matched in the upstream decision and maps each condition's `field` to an FCRA reason key through a compliance-editable mapping (`fico` or `credit_score` → `credit_score_low`, `inquir` → `too_many_inquiries`, `eviction` → `eviction_record`, and so on). Thresholds are never encoded in the mapping — whatever threshold the operator wrote is the threshold. Reviewers can override the list before sending. The full reason vocabulary is listed on the [compliance page](/docs/compliance/adverse-action-notices#which-reasons-can-a-notice-carry).

## Notice stages and flows

`flow` follows the cascade's use case and drives the stage sequence:

| Flow | Stages | Notes |
|---|---|---|
| `employment` | `pre_adverse` → waiting period → `post_adverse` | Pre-adverse notice with a copy of the report and the Summary of Rights; the execution enters `waiting`; the waiting period is floored to 5 days; then the final notice |
| `tenant_screening` | `final` | Single notice |
| `credit_lending` | `final` | Single notice |

## Which webhooks fire?

| Event | When |
|---|---|
| `adverse_action.triggered` | Notice handling began. Employment: pre-adverse sent and the wait scheduled. Single-notice flows: final notice sent |
| `adverse_action.completed` | Obligations fulfilled. Employment: post-adverse sent on resume. Single-notice flows: same instant as `triggered` |
| `adverse_action.failed` | A notice email could not be delivered |
| `adverse_action.retry_scheduled` | Employment only: the post-adverse send failed and a retry is scheduled (`retry_at`) |

Payloads carry `workflow_execution_id`, `node_id`, `external_reference`, `flow`, `notice_stage` and, where relevant, `sent_to` and `completed_at`. Details per event are under [Webhook events](/docs/api/webhooks).

## Where are the PDFs?

- Per execution: `GET /executions/{id}/notice_artifacts` lists the notice PDFs; `GET …/notice_artifacts/{artifact_id}` downloads one (`executions:read:full`).
- Per batch: `GET /batches/{id}/adverse_action_notices.zip` bundles every applicant's notices (`404` while none exist).

The archive is immutable: a resend from the audit dashboard re-delivers the exact bytes that were sent, with a `[Resent]` subject prefix.

## Templates

Notice templates are per operator, versioned (each upload is an immutable version), and can be assigned as the default for a bureau (`equifax`, `experian`, `transunion`, `lexisnexis`, `cic`) so the notice matches the report that drove the decision. Email subject and body are customisable with `{{applicant_name}}`, `{{notice_date}}` and `{{recipient}}` placeholders. Manage them at [/adverse_action_templates](/adverse_action_templates); there is no API for template management yet.

## Related

- [Human review](/docs/concepts/human-review)
- [Webhooks](/docs/concepts/webhooks)
- [Adverse action notices (compliance)](/docs/compliance/adverse-action-notices)

## Sitemap

See the full [sitemap](https://cascades.crscreditapi.com/sitemap.md) for all pages.
