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

# Adverse Media Check

Perform adverse media analysis on entities to identify negative news, sanctions, criminal records, and other risk factors beyond traditional watchlist checks. Supports analysis of **persons**, **companies**, and **websites/domains**.

## Endpoint

```
POST /kyc/adverse-media
```

## Authentication

Requires `kyc:create` permission. Include your Bearer token in the Authorization header.

## Description

The adverse media check uses AI-powered analysis to search and evaluate publicly available information about an entity. It performs:

1. **Parallel web searches** across multiple sources
2. **LLM analysis** to filter and evaluate findings
3. **Risk scoring** based on identified adverse media
4. **Structured reporting** with source citations

This complements traditional watchlist checks by finding information that may not yet be in official sanctions lists.

### Entity Types

The endpoint supports three entity types:

| Type      | Description                   | Search Focus                                                    |
| --------- | ----------------------------- | --------------------------------------------------------------- |
| `person`  | Individual analysis (default) | Fraud, sanctions, criminal records, professional profiles       |
| `company` | Company/organization analysis | Corporate fraud, regulatory violations, sanctions               |
| `website` | Website/domain reputation     | Fraud reports, security issues, blacklists, consumer complaints |

## Request Body Parameters

<ParamFields>
  <ParamField name="name" type="string" required description="Name of the entity to analyze (person name, company name, or website/domain)" />

  <ParamField name="entity_type" type="string" description="Type of entity: 'person' (default), 'company', or 'website'" />

  <ParamField name="country" type="string" description="Country of residence/operation (helps disambiguate common names). Not applicable for websites." />

  <ParamField name="age" type="integer" description="Age of individual (helps disambiguate common names). Only applicable for persons." />

  <ParamField name="additional_info" type="string" description="Additional context information (company, position, business type, etc.)" />

  <ParamField name="provider" type="string" description="LLM provider: 'bedrock' (default) or 'openai'" />

  <ParamField name="model" type="string" description="Model identifier (for OpenAI provider, e.g., 'gpt-4o-mini')" />

  <ParamField name="data_retention" type="string" description="Set to 'ephemeral' for a zero-retention analysis. Equivalent to the X-Data-Retention: ephemeral header." />
</ParamFields>

## Zero Data Retention (ephemeral mode)

You can request ephemeral processing with either the `X-Data-Retention: ephemeral` header or `"data_retention": "ephemeral"` in the JSON body. Per-request ephemeral must be enabled for your account first: the endpoint identifier `adverse-media.check` (or the wildcard `*`) has to appear in your tenant's `data_processing_config.allowed_ephemeral_endpoints`, otherwise the request is rejected with a `400`. Tenants can also opt in account-wide by setting `data_processing_config.mode` to `ephemeral` — the tenant-level setting always wins over per-request flags and does not require the allowlist. Contact support to enable either option on your account.

When ephemeral mode is active, the API returns the normal analysis response but does not store a validation record (nothing appears in the dashboard history), does not emit the detailed audit event, and never writes the analysis report to disk. The platform retains only an aggregate billing metric (one counted adverse-media check, with no subject or outcome references); tenants with `retain_billing_metrics: false` suppress that too.

An invalid `data_retention` value returns `400` before any quota is consumed.

<Note>
  Adverse media analysis queries third-party providers: the entity name is sent to the Tavily search API and to the configured LLM (AWS Bedrock or OpenAI), which process it under their own no-retention / non-training policies. Ephemeral mode guarantees zero retention in Legaltalent's own stores.
</Note>

## Request Example

<RequestExample>
  ```bash theme={null}
  curl -X POST https://stg.kyc.legaltalent.ai/kyc/adverse-media \
      -H "Authorization: Bearer YOUR_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "John Doe"
      }'
  ```
</RequestExample>

## Additional Request Examples

### Person with Context

```bash theme={null}
curl -X POST https://stg.kyc.legaltalent.ai/kyc/adverse-media \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John Doe",
    "entity_type": "person",
    "country": "US",
    "age": 45,
    "additional_info": "CEO of Tech Corp, based in New York"
  }'
```

### Company Analysis

```bash theme={null}
curl -X POST https://stg.kyc.legaltalent.ai/kyc/adverse-media \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Tech Corp Inc",
    "entity_type": "company",
    "country": "US",
    "additional_info": "Technology company founded in 2010"
  }'
```

### Website/Domain Analysis

```bash theme={null}
curl -X POST https://stg.kyc.legaltalent.ai/kyc/adverse-media \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "example-shop.com",
    "entity_type": "website",
    "additional_info": "E-commerce platform"
  }'
```

### Using OpenAI Provider

```bash theme={null}
curl -X POST https://stg.kyc.legaltalent.ai/kyc/adverse-media \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John Doe",
    "country": "US",
    "provider": "openai",
    "model": "gpt-4o-mini"
  }'
```

## Response Format

### Success Response

<ResponseExample>
  ```json Success Response theme={null}
  {
    "final_risk_score": 75,
    "decision": "HIGH_RISK",
    "summary": "Multiple adverse media findings identified including fraud allegations and regulatory violations.",
    "sources": [
      {
        "id": 1,
        "title": "Tech Executive Charged with Fraud",
        "url": "https://example.com/news/article1",
        "summary": "John Doe, CEO of Tech Corp, faces fraud charges related to investor funds..."
      },
      {
        "id": 3,
        "title": "SEC Investigation into Tech Corp",
        "url": "https://example.com/news/article2",
        "summary": "SEC investigating Tech Corp for securities violations involving executive..."
      }
    ],
    "entity_name": "John Doe",
    "entity_type": "person",
    "country": "US",
    "age": 45,
    "analysis_timestamp": "2024-11-22T10:30:00Z",
    "processing_time_ms": 6000
  }
  ```
</ResponseExample>

### Response Fields

| Field                | Type    | Description                                                       |
| -------------------- | ------- | ----------------------------------------------------------------- |
| `final_risk_score`   | integer | Risk score from 0-100 (higher = higher risk)                      |
| `decision`           | string  | Risk decision: `CLEAR`, `LOW_RISK`, `MEDIUM_RISK`, or `HIGH_RISK` |
| `summary`            | string  | Summary of findings and risk assessment (max 300 chars)           |
| `sources`            | array   | List of adverse media sources found (empty if CLEAR)              |
| `entity_name`        | string  | Name of the analyzed entity                                       |
| `entity_type`        | string  | Type of entity analyzed: `person`, `company`, or `website`        |
| `country`            | string  | Country (if provided)                                             |
| `age`                | integer | Age (if provided, 0 otherwise)                                    |
| `analysis_timestamp` | string  | ISO 8601 timestamp of the analysis                                |
| `processing_time_ms` | integer | Total processing time in milliseconds                             |

### Source Fields

Each source includes:

| Field     | Type    | Description                                                   |
| --------- | ------- | ------------------------------------------------------------- |
| `id`      | integer | Unique source identifier (1-indexed)                          |
| `title`   | string  | Title of the source/article (max 100 chars)                   |
| `url`     | string  | URL to the source                                             |
| `summary` | string  | Summary explaining why this source is adverse (max 200 chars) |

### Decision Values

| Decision      | Score Range | Description                                          |
| ------------- | ----------- | ---------------------------------------------------- |
| `CLEAR`       | 0-20        | No significant adverse media found                   |
| `LOW_RISK`    | 21-40       | Minor adverse findings                               |
| `MEDIUM_RISK` | 41-70       | Moderate adverse findings requiring review           |
| `HIGH_RISK`   | 71-100      | Significant adverse findings, strong risk indicators |

### Clear Response (No Adverse Media)

<ResponseExample>
  ```json Clear Response theme={null}
  {
    "final_risk_score": 5,
    "decision": "CLEAR",
    "summary": "No significant adverse media findings identified for this entity.",
    "sources": [],
    "entity_name": "John Doe",
    "entity_type": "person",
    "country": "US",
    "age": 45,
    "analysis_timestamp": "2024-11-22T10:30:00Z",
    "processing_time_ms": 5600
  }
  ```
</ResponseExample>

### Website Analysis Response

<ResponseExample>
  ```json Website Analysis Response theme={null}
  {
    "final_risk_score": 65,
    "decision": "MEDIUM_RISK",
    "summary": "Multiple fraud reports and consumer complaints found for this website. Users report non-delivery of orders and poor customer service.",
    "sources": [
      {
        "id": 2,
        "title": "Scam Alert: example-shop.com Reviews",
        "url": "https://trustpilot.com/review/example-shop.com",
        "summary": "Multiple users report fraudulent charges and non-delivery of products..."
      },
      {
        "id": 5,
        "title": "BBB Complaints for Example Shop",
        "url": "https://bbb.org/example-shop",
        "summary": "37 complaints filed in the last 12 months regarding refund issues..."
      }
    ],
    "entity_name": "example-shop.com",
    "entity_type": "website",
    "country": "",
    "age": 0,
    "analysis_timestamp": "2024-11-22T10:30:00Z",
    "processing_time_ms": 5200
  }
  ```
</ResponseExample>

## Error Responses

### 400 Bad Request - Missing Name

<ResponseExample>
  ```json Error: Missing Name theme={null}
  {
    "error": "Validation error: 'name' parameter is required"
  }
  ```
</ResponseExample>

### 400 Bad Request - Invalid Entity Type

<ResponseExample>
  ```json Error: Invalid Entity Type theme={null}
  {
    "error": "Validation error: 'entity_type' must be one of ['person', 'company', 'website']"
  }
  ```
</ResponseExample>

### 500 Internal Server Error - Configuration Error

<ResponseExample>
  ```json Error: Configuration Error theme={null}
  {
    "error": "Configuration error: TAVILY_API_KEY not set"
  }
  ```
</ResponseExample>

### 500 Internal Server Error - Analysis Failed

<ResponseExample>
  ```json Error: Analysis Failed theme={null}
  {
    "error": "Internal error: Failed to analyze adverse media: LLM analysis timed out after 10 seconds"
  }
  ```
</ResponseExample>

## Status Codes

| Code | Description                             |
| ---- | --------------------------------------- |
| 200  | Success - Analysis completed            |
| 400  | Bad Request - Invalid parameters        |
| 401  | Unauthorized - Missing or invalid token |
| 403  | Forbidden - Insufficient permissions    |
| 500  | Internal Server Error                   |

## Usage Examples

### Python Example

```python theme={null}
import requests

token = "YOUR_TOKEN"

# Analyze a person
response = requests.post(
    "https://stg.kyc.legaltalent.ai/kyc/adverse-media",
    headers={
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json"
    },
    json={
        "name": "John Doe",
        "entity_type": "person",
        "country": "US",
        "age": 45,
        "additional_info": "CEO of Tech Corp"
    }
)

if response.status_code == 200:
    data = response.json()
    print(f"Risk Score: {data['final_risk_score']}")
    print(f"Decision: {data['decision']}")
    print(f"Summary: {data['summary']}")
    
    if data['sources']:
        print(f"\nFound {len(data['sources'])} adverse sources:")
        for source in data['sources']:
            print(f"- [{source['id']}] {source['title']}: {source['url']}")
else:
    print(f"Error: {response.json()}")
```

### Python - Website Analysis

```python theme={null}
import requests

token = "YOUR_TOKEN"

# Analyze a website
response = requests.post(
    "https://stg.kyc.legaltalent.ai/kyc/adverse-media",
    headers={
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json"
    },
    json={
        "name": "suspicious-shop.com",
        "entity_type": "website",
        "additional_info": "E-commerce site selling electronics"
    }
)

if response.status_code == 200:
    data = response.json()
    print(f"Website: {data['entity_name']}")
    print(f"Risk Score: {data['final_risk_score']}")
    print(f"Decision: {data['decision']}")
    print(f"Summary: {data['summary']}")
else:
    print(f"Error: {response.json()}")
```

### JavaScript Example

```javascript theme={null}
const token = "YOUR_TOKEN";

async function checkAdverseMedia(name, entityType = "person", options = {}) {
  const response = await fetch(
    "https://stg.kyc.legaltalent.ai/kyc/adverse-media",
    {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${token}`,
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        name: name,
        entity_type: entityType,
        country: options.country,
        age: options.age,
        additional_info: options.additionalInfo
      })
    }
  );
  
  const data = await response.json();
  
  if (response.ok) {
    console.log(`Entity: ${data.entity_name} (${data.entity_type})`);
    console.log(`Risk Score: ${data.final_risk_score}`);
    console.log(`Decision: ${data.decision}`);
    console.log(`Summary: ${data.summary}`);
    
    if (data.sources.length > 0) {
      console.log(`\nFound ${data.sources.length} adverse sources`);
      data.sources.forEach(source => {
        console.log(`- [${source.id}] ${source.title}: ${source.url}`);
      });
    }
    
    return data;
  } else {
    console.error("Error:", data.error);
    throw new Error(data.error);
  }
}

// Usage examples
await checkAdverseMedia("John Doe", "person", { country: "US", age: 45 });
await checkAdverseMedia("Tech Corp Inc", "company", { country: "US" });
await checkAdverseMedia("example-shop.com", "website");
```

## Search Process

### Person/Company Analysis

The adverse media check for persons and companies performs parallel searches across:

1. **Fraud/Corruption/Sanctions**: Financial crimes, corruption, sanctions, laundering
2. **Criminal Records**: Arrests, investigations, charges, convictions
3. **Sanction Lists**: OFAC, UN, designated persons, blacklists
4. **Professional Validation**: LinkedIn, professional profiles, company associations
5. **General News**: Recent news articles and media coverage

### Website/Domain Analysis

For website analysis, specialized searches are performed:

1. **Reputation & Reviews**: User reviews, complaints, ratings
2. **Fraud Reports**: Scam reports, phishing alerts, fake site warnings
3. **Security Issues**: Data breaches, vulnerabilities, malware reports
4. **Blacklists**: Domain blacklists, spam lists, unsafe site flags
5. **Consumer Complaints**: Trustpilot, BBB, consumer complaint databases

Results are then analyzed by an LLM to:

* Filter false positives
* Evaluate relevance to the specific entity
* Assess risk factors
* Generate concise summaries

## Provider Options

### AWS Bedrock (Default)

* **Provider**: `"bedrock"`
* **Model**: Claude 3.5 Haiku (with fallback to Claude 3 Haiku)
* **Use Case**: Production deployments on AWS, no API key required (uses IAM role)

### OpenAI

* **Provider**: `"openai"`
* **Model**: Specify model (default: `"gpt-4o-mini"`)
* **Use Case**: High-precision analysis, specific model requirements

## Performance

* **Typical Response Time**: 5-10 seconds
* **Timeout**: 10 seconds per LLM call
* **Retries**: Automatic retries on timeout (up to 3 attempts)
* **Search Sources**: Up to 15 sources analyzed per request
* **LLM Analysis**: Includes timeout protection and error handling

## Integration Tips

1. **Combine with Watchlist Checks**: Use adverse media as a supplement to traditional watchlist checks
2. **Use Context**: Provide country, age, and additional info to improve accuracy
3. **Choose the Right Entity Type**: Use `website` for domain reputation checks, `company` for organizational analysis
4. **Handle Timeouts**: Implement retry logic for production use
5. **Review Scores**: Risk scores should be reviewed by compliance teams, not automated
6. **Source Verification**: Always verify adverse sources before making decisions

## Best Practices

* Use adverse media checks for:
  * Enhanced due diligence on individuals
  * Company/organization risk assessment
  * Website reputation verification before partnerships
  * Ongoing monitoring
  * Risk assessment for high-value relationships
  * Compliance investigations

* **Entity Type Selection**:
  * Use `person` for individual background checks
  * Use `company` for corporate due diligence
  * Use `website` for merchant/partner website verification

* Combine with traditional watchlist checks for comprehensive risk screening

* Review `summary` for human-readable assessment

* Check `sources` URLs to verify findings

* Use risk scores as indicators, not definitive decisions
