> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zenoo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Alert Review

> Triage and resolve AML alerts via the API using priority-based queuing, AI research, and bulk operations.

# Alert Review

This guide demonstrates how to triage and resolve AML alerts through the API. You will list open alerts by priority, inspect a specific alert, trigger AI-powered research, review the AI assessment, and resolve the alert.

## Prerequisites

* A valid API key (see [Authentication](/getting-started/authentication))
* At least one case with open alerts (see [End-to-End Onboarding](/use-cases/onboarding))

<Steps>
  <Step title="List open alerts by priority">
    Retrieve all open alerts sorted by priority score (highest first). This mirrors the analyst inbox view.

    <CodeGroup>
      ```bash curl theme={null}
      curl -X GET "https://api.zenoo.com/v1/alerts?status=Open&sort=-priority_score&limit=25" \
        -H "Authorization: Bearer your-api-key"
      ```

      ```python Python theme={null}
      import requests

      response = requests.get(
          "https://api.zenoo.com/v1/alerts",
          headers={"Authorization": "Bearer your-api-key"},
          params={
              "status": "Open",
              "sort": "-priority_score",
              "limit": 25,
          },
      )
      alerts = response.json()
      for alert in alerts["data"]:
          print(
              f"[{alert['priority']}] {alert['category']}: {alert['title']} "
              f"(score: {alert['priority_score']}, SLA: {alert['sla_status']})"
          )
      ```

      ```javascript Node.js theme={null}
      const params = new URLSearchParams({
        status: "Open",
        sort: "-priority_score",
        limit: "25",
      });

      const response = await fetch(
        `https://api.zenoo.com/v1/alerts?${params}`,
        { headers: { Authorization: "Bearer your-api-key" } }
      );
      const alerts = await response.json();
      alerts.data.forEach((a) =>
        console.log(
          `[${a.priority}] ${a.category}: ${a.title} (score: ${a.priority_score}, SLA: ${a.sla_status})`
        )
      );
      ```
    </CodeGroup>

    **Response:**

    ```json theme={null}
    {
      "data": [
        {
          "token": "alt_001",
          "type": "Screening",
          "category": "Sanctions Hit",
          "title": "Sanctions Hit: Global Corp LLC",
          "status": "Open",
          "priority": "Critical",
          "priority_score": 95,
          "match_score": 88,
          "sla_status": "On Track",
          "sla_due_date": "2026-02-17T10:00:00Z",
          "case_token": "cas_abc123",
          "entity_name": "Global Corp LLC"
        },
        {
          "token": "alt_002",
          "type": "Screening",
          "category": "PEP Match",
          "title": "PEP Match: Maria Garcia",
          "status": "Open",
          "priority": "High",
          "priority_score": 78,
          "match_score": 72,
          "sla_status": "On Track",
          "sla_due_date": "2026-02-18T10:00:00Z",
          "case_token": "cas_def456",
          "entity_name": "Maria Garcia"
        }
      ],
      "meta": {
        "total": 2,
        "page": { "cursor": null, "has_more": false }
      }
    }
    ```

    <Tip>
      Use the `sort` parameter with a `-` prefix for descending order. Common sort fields: `priority_score`, `created_at`, `sla_due_date`.
    </Tip>

    ### Filtering options

    | Parameter    | Type   | Description                                                                         |
    | ------------ | ------ | ----------------------------------------------------------------------------------- |
    | `status`     | string | Filter by status: `Open`, `Acknowledged`, `Resolved`, `False Positive`, `Escalated` |
    | `category`   | string | Filter by category: `PEP Match`, `Sanctions Hit`, `Adverse Media`, etc.             |
    | `type`       | string | Filter by type: `Screening`, `Identity`, `Company`, `Document`, `Financial`         |
    | `priority`   | string | Filter by priority: `Critical`, `High`, `Medium`, `Low`                             |
    | `case_token` | string | Filter alerts belonging to a specific case                                          |
    | `sort`       | string | Sort field with optional `-` prefix for descending                                  |
    | `limit`      | number | Results per page (default 25, max 100)                                              |
    | `cursor`     | string | Pagination cursor from previous response                                            |
  </Step>

  <Step title="Get alert details">
    Retrieve the full details of the highest-priority alert, including screening match data and AI fields.

    <CodeGroup>
      ```bash curl theme={null}
      curl -X GET "https://api.zenoo.com/v1/alerts/alt_001" \
        -H "Authorization: Bearer your-api-key"
      ```

      ```python Python theme={null}
      response = requests.get(
          "https://api.zenoo.com/v1/alerts/alt_001",
          headers={"Authorization": "Bearer your-api-key"},
      )
      alert = response.json()
      print(f"Category: {alert['category']}")
      print(f"Match Score: {alert['match_score']}%")
      print(f"Description: {alert['description']}")
      ```

      ```javascript Node.js theme={null}
      const alertRes = await fetch("https://api.zenoo.com/v1/alerts/alt_001", {
        headers: { Authorization: "Bearer your-api-key" },
      });
      const alert = await alertRes.json();
      console.log(`Category: ${alert.category}`);
      console.log(`Match Score: ${alert.match_score}%`);
      console.log(`Description: ${alert.description}`);
      ```
    </CodeGroup>

    **Response:**

    ```json theme={null}
    {
      "token": "alt_001",
      "type": "Screening",
      "category": "Sanctions Hit",
      "title": "Sanctions Hit: Global Corp LLC",
      "description": "WorldCheck screening returned a potential sanctions match against OFAC SDN list for entity 'Global Corp LLC'.",
      "status": "Open",
      "priority": "Critical",
      "priority_score": 95,
      "match_score": 88,
      "risk_tier": "High",
      "sla_status": "On Track",
      "sla_due_date": "2026-02-17T10:00:00Z",
      "case_token": "cas_abc123",
      "entity_name": "Global Corp LLC",
      "source_data": {
        "provider": "WorldCheck",
        "list_name": "OFAC SDN",
        "matched_name": "Global Corporation LLC",
        "match_type": "Exact"
      },
      "ai_research": null,
      "created_at": "2026-02-16T09:00:00Z"
    }
    ```
  </Step>

  <Step title="Trigger AI research">
    Request AI-powered analysis of the alert. The AI reviews the screening match against public sources to assess whether it is a true positive or false positive.

    <CodeGroup>
      ```bash curl theme={null}
      curl -X POST "https://api.zenoo.com/v1/alerts/alt_001/ai-research" \
        -H "Authorization: Bearer your-api-key"
      ```

      ```python Python theme={null}
      response = requests.post(
          "https://api.zenoo.com/v1/alerts/alt_001/ai-research",
          headers={"Authorization": "Bearer your-api-key"},
      )
      result = response.json()
      print(f"Status: {result['status']}")  # processing
      ```

      ```javascript Node.js theme={null}
      const aiRes = await fetch(
        "https://api.zenoo.com/v1/alerts/alt_001/ai-research",
        {
          method: "POST",
          headers: { Authorization: "Bearer your-api-key" },
        }
      );
      const aiResult = await aiRes.json();
      console.log(`Status: ${aiResult.status}`); // processing
      ```
    </CodeGroup>

    **Response:**

    ```json theme={null}
    {
      "status": "processing",
      "message": "AI research initiated. Results will be available shortly.",
      "estimated_seconds": 15
    }
    ```

    <Info>
      AI research runs asynchronously. Typical completion time is 10-30 seconds. You will receive a `alert.ai_research_completed` webhook event when results are ready, or you can poll the endpoint below.
    </Info>
  </Step>

  <Step title="Get AI research results">
    Retrieve the AI assessment once processing completes.

    <CodeGroup>
      ```bash curl theme={null}
      curl -X GET "https://api.zenoo.com/v1/alerts/alt_001/ai-research" \
        -H "Authorization: Bearer your-api-key"
      ```

      ```python Python theme={null}
      response = requests.get(
          "https://api.zenoo.com/v1/alerts/alt_001/ai-research",
          headers={"Authorization": "Bearer your-api-key"},
      )
      research = response.json()
      print(f"Assessment: {research['assessment']}")
      print(f"Confidence: {research['confidence']}%")
      print(f"False Positive Probability: {research['false_positive_probability']}%")
      print(f"Recommended Action: {research['recommended_action']}")
      ```

      ```javascript Node.js theme={null}
      const researchRes = await fetch(
        "https://api.zenoo.com/v1/alerts/alt_001/ai-research",
        { headers: { Authorization: "Bearer your-api-key" } }
      );
      const research = await researchRes.json();
      console.log(`Assessment: ${research.assessment}`);
      console.log(`Confidence: ${research.confidence}%`);
      console.log(`FP Probability: ${research.false_positive_probability}%`);
      console.log(`Recommended: ${research.recommended_action}`);
      ```
    </CodeGroup>

    **Response:**

    ```json theme={null}
    {
      "status": "completed",
      "assessment": "The matched entity 'Global Corporation LLC' on the OFAC SDN list is a different legal entity registered in Iran. The subject entity 'Global Corp LLC' is incorporated in Delaware, USA with no apparent connection to the sanctioned entity beyond name similarity.",
      "confidence": 85,
      "false_positive_probability": 82,
      "recommended_action": "Approve",
      "sources": [
        { "title": "OFAC SDN List", "url": "https://sanctionssearch.ofac.treas.gov/" },
        { "title": "Delaware Division of Corporations", "url": "https://icis.corp.delaware.gov/" }
      ],
      "researched_at": "2026-02-16T09:01:15Z"
    }
    ```
  </Step>

  <Step title="Resolve the alert">
    Based on the AI assessment and your review, resolve the alert with an action and notes.

    <CodeGroup>
      ```bash curl theme={null}
      curl -X POST "https://api.zenoo.com/v1/alerts/alt_001/resolve" \
        -H "Authorization: Bearer your-api-key" \
        -H "Content-Type: application/json" \
        -d '{
          "action": "Approve",
          "notes": "False positive confirmed. Matched entity is Global Corporation LLC (Iran), unrelated to subject Global Corp LLC (Delaware, USA). AI confidence 85%. No sanctions exposure."
        }'
      ```

      ```python Python theme={null}
      response = requests.post(
          "https://api.zenoo.com/v1/alerts/alt_001/resolve",
          headers={
              "Authorization": "Bearer your-api-key",
              "Content-Type": "application/json",
          },
          json={
              "action": "Approve",
              "notes": "False positive confirmed. Matched entity is Global Corporation LLC (Iran), unrelated to subject Global Corp LLC (Delaware, USA). AI confidence 85%. No sanctions exposure.",
          },
      )
      print(response.json()["status"])  # Resolved
      ```

      ```javascript Node.js theme={null}
      const resolveRes = await fetch(
        "https://api.zenoo.com/v1/alerts/alt_001/resolve",
        {
          method: "POST",
          headers: {
            Authorization: "Bearer your-api-key",
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            action: "Approve",
            notes:
              "False positive confirmed. Matched entity is Global Corporation LLC (Iran), unrelated to subject Global Corp LLC (Delaware, USA). AI confidence 85%. No sanctions exposure.",
          }),
        }
      );
      const resolved = await resolveRes.json();
      console.log(resolved.status); // Resolved
      ```
    </CodeGroup>

    **Response:**

    ```json theme={null}
    {
      "token": "alt_001",
      "status": "Resolved",
      "resolution_action": "Approve",
      "resolved_by": "analyst@example.com",
      "resolved_at": "2026-02-16T09:05:00Z"
    }
    ```

    ### Resolution actions

    | Action                    | When to use                                       |
    | ------------------------- | ------------------------------------------------- |
    | `Approve`                 | Alert reviewed, no issues found or risk accepted  |
    | `Decline`                 | Confirmed compliance issue, reject the entity     |
    | `Escalate`                | Uncertain or complex, route to senior reviewer    |
    | `Request Document`        | Additional evidence needed from the client        |
    | `Approve with Conditions` | Approved with caveats (e.g., enhanced monitoring) |

    <Warning>
      If a sanctions hit is confirmed as a true positive, use `Decline` and escalate the case immediately. Processing sanctioned entities may violate legal obligations.
    </Warning>
  </Step>
</Steps>

## Alert lifecycle

Alerts move through a defined set of statuses from creation to resolution:

```mermaid theme={null}
stateDiagram-v2
    [*] --> Open : Alert created
    Open --> Acknowledged : Analyst claims
    Open --> Resolved : Direct resolution
    Open --> False_Positive : Confirmed FP
    Open --> Escalated : Escalate to manager
    Acknowledged --> Resolved : After review
    Acknowledged --> False_Positive : Confirmed FP
    Acknowledged --> Escalated : Escalate
    Resolved --> [*]
    False_Positive --> [*]
    Escalated --> [*]
```

| Status           | Description                                    |
| ---------------- | ---------------------------------------------- |
| `Open`           | Alert created, awaiting analyst review         |
| `Acknowledged`   | Analyst has claimed and is reviewing the alert |
| `Resolved`       | Alert reviewed and resolved with an action     |
| `False Positive` | Confirmed as a false positive match            |
| `Escalated`      | Escalated to a senior reviewer or manager      |

## Priority scoring

Every alert receives a composite priority score (0-290 points) calculated from five components. The priority score drives the default sort order in the analyst inbox: highest-score alerts appear first.

| Component       | Max Points | Calculation                                      |
| --------------- | ---------- | ------------------------------------------------ |
| SLA urgency     | 100        | Breached = 100, linear decay from due date       |
| Risk tier       | 100        | Critical = 100, High = 75, Medium = 50, Low = 25 |
| Category weight | 60         | Sanctions = 60, PEP = 45, Adverse Media = 30     |
| Match score     | 10         | Screening confidence / 10                        |
| Case risk       | 20         | Parent case risk score / 5                       |

### Priority labels

| Priority   | Score Range |
| ---------- | ----------- |
| `Critical` | 200+        |
| `High`     | 120-199     |
| `Medium`   | 60-119      |
| `Low`      | 0-59        |

## Bulk operations

For high-volume alert processing, use the bulk endpoints. See [Bulk Operations Guide](/guides/bulk-operations) for details.

```bash theme={null}
curl -X POST "https://api.zenoo.com/v1/alerts/bulk/resolve" \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "alert_tokens": ["alt_003", "alt_004", "alt_005"],
    "action": "Approve",
    "notes": "Batch resolved: low-risk name mismatches confirmed as formatting differences."
  }'
```

## Next steps

* [Alert Management Guide](/guides/alert-management). Deep dive into the alert lifecycle and priority scoring.
* [AI Research Guide](/guides/ai-research). Learn about AI-powered analysis and auto-disposition.
* [Bulk Operations Guide](/guides/bulk-operations). Process alerts at scale.
* [Pagination Guide](/guides/pagination). Navigate large result sets efficiently.
