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

# Brand impersonation watchlist, scan & takedown cases

> Protect your own brand from smishing and lookalike impersonation: keep a watchlist of your brand names, domains, and sender IDs, score observed candidates against it, and track takedown cases with a filing-ready evidence pack.

# Brand impersonation watchlist, scan & takedown cases

Most brand-protection tooling looks inward — it screens the traffic *you*
send. This module looks outward: a third party running a smishing campaign
with a lookalike domain, a spoofed SMS/RCS sender ID, or a display name
that reads as your brand. You register the tokens that are legitimately
yours (brand names, domains, sender IDs), score any candidate you observe
against them, and when a candidate is clearly hostile, open a takedown case
that assembles the evidence pack a registrar, carrier, or platform abuse
desk expects.

All endpoints below are rooted at
`https://api.orbit.devotel.io/api/v1/brand-identity/impersonation`. The same
workflow is available in the dashboard under **Settings → Compliance →
Brand impersonation watchlist**.

***

## What the scanner detects

Each candidate you submit is scored against your watchlist and returns a
**band** with a matching **recommendation**:

| Band         | Score  | Recommendation    | Meaning                                                                                                                                      |
| ------------ | ------ | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `clean`      | 0–24   | `monitor`         | No meaningful similarity to your protected tokens, or the candidate *is* one of your own registered assets — that is never flagged.          |
| `suspicious` | 25–59  | `investigate`     | Worth a human look — a partial match, an abused TLD, or smishing lure language.                                                              |
| `malicious`  | 60–100 | `urgent_takedown` | High-confidence impersonation — a single-character typosquat, a homoglyph spoof, or your exact brand label under a TLD you never registered. |

The score is a transparent sum of named findings, never a black-box
reputation number. Each finding tells you exactly which signal fired:

| Finding code                   | Severity | What fired                                                                                                                                        |
| ------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `homoglyph_spoof`              | `block`  | The candidate visually matches a protected token after normalizing look-alike characters (`rn` → `m`, `0` → `o`, `vv` → `w`, digit/letter swaps). |
| `domain_label_exact_wrong_tld` | `block`  | The registrable label is exactly your brand token but under a TLD you never registered (`acme.com` → `acme.tk`).                                  |
| `typosquat_close`              | `block`  | One character edit away from a protected token (`acnne.com`).                                                                                     |
| `typosquat_near`               | `warn`   | Two edits away.                                                                                                                                   |
| `combosquat`                   | `block`  | A protected token embedded inside a larger string or subdomain (`acme.verify-account.tk`).                                                        |
| `abused_tld`                   | `warn`   | The domain sits on a TLD that is commonly abused or free to register.                                                                             |
| `lure_keywords`                | `info`   | The candidate value or its `sample_text` contains smishing lure language.                                                                         |

Two guardrails keep the verdict trustworthy:

* **Your own assets are never flagged.** A candidate that exactly matches
  (or, for domains, is a subdomain of) something on your watchlist returns
  a clean verdict — it is your brand, not impersonation.
* **Signals are capped and bounded.** A scan accepts at most 50 candidates,
  compared tokens are length-capped, and finding severities map onto the
  triage bands above (`block` findings drive the score hard, `warn`
  findings add moderate weight, `info` findings nudge it).

***

## Watchlist management

The watchlist declares which tokens are *yours*. It does two jobs: it tells
the scanner what to fuzzy-match candidates against, and it tells the
scanner what to exclude (your own assets pass clean).

Fields:

| Field                  | Contents                       | Limit                                              |
| ---------------------- | ------------------------------ | -------------------------------------------------- |
| `brand_names`          | Your brand and product names   | Up to 20 entries (the dashboard enforces this cap) |
| `protected_domains`    | Domains you have registered    | Up to 50 entries                                   |
| `protected_sender_ids` | SMS/RCS sender IDs you operate | Up to 50 entries                                   |

Read the current watchlist:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/brand-identity/impersonation/watchlist" \
  -H "Authorization: Bearer $ORBIT_API_KEY"
```

Replace it (a PUT replaces the whole watchlist — send all three lists every
time):

```bash theme={null}
curl -X PUT "https://api.orbit.devotel.io/api/v1/brand-identity/impersonation/watchlist" \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "brand_names": ["Acme", "Acme Pay"],
    "protected_domains": ["acme.com", "acmepay.com"],
    "protected_sender_ids": ["ACME", "AcmePay"]
  }'
```

How matching works, per candidate type:

* **Domain candidates** are compared against the *registrable label* of each
  protected domain plus your brand names — so `acnne.com` matches your
  `acme` token regardless of which TLD the attacker chose.
* **Sender ID candidates** are compared against your protected sender IDs
  plus brand names.
* **Display name candidates** are compared against your brand names.

Comparison is fuzzy by design: homoglyph and leetspeak substitutions are
normalized first, then edit-distance is measured. Tokens shorter than three
characters are never fuzzy-matched — a two-letter token would false-positive
on everything.

***

## Running a scan

`POST /brand-identity/impersonation/scan` scores a batch of candidates.
It is **read-only and advisory**: nothing persists, nothing is transmitted,
and no case is opened. Use it to evaluate what you observed before deciding
whether it deserves a case.

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/brand-identity/impersonation/scan" \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "candidates": [
      {
        "type": "domain",
        "value": "acme-verify.tk",
        "channel": "sms",
        "sample_text": "Acme: confirm your account at acme-verify.tk"
      },
      {
        "type": "sender_id",
        "value": "AcmeSupport"
      }
    ]
  }'
```

Each candidate carries:

| Field         | Type   | Notes                                                                   |
| ------------- | ------ | ----------------------------------------------------------------------- |
| `type`        | enum   | `domain`, `sender_id`, or `display_name` (required).                    |
| `value`       | string | The observed domain, sender ID, or display name (required).             |
| `channel`     | string | Where you saw it — `sms`, `whatsapp`, `rcs`, … (optional).              |
| `observed_at` | string | When you observed it (optional).                                        |
| `sample_text` | string | The message body it appeared in — scanned for lure keywords (optional). |
| `source_url`  | string | Where the candidate was observed (optional).                            |

The response sorts verdicts worst-first and reports `candidateCount`,
`worstBand`, `urgentCount`, and `investigateCount` alongside the per-candidate
verdicts. Duplicate `(type, value)` pairs are collapsed; batches are capped
at 50 candidates.

Because nothing persists, scanning the same batch twice is safe and returns
the same verdicts.

***

## Takedown cases

When a verdict deserves action, open a case. `POST /brand-identity/
impersonation/cases` re-scores the candidate, assembles an **evidence pack**,
and stores the case:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/brand-identity/impersonation/cases" \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "candidate": {
      "type": "domain",
      "value": "acme-verify.tk",
      "channel": "sms",
      "sample_text": "Acme: confirm your account at acme-verify.tk"
    },
    "note": "Reported by support on 2026-08-24; customer received smishing SMS."
  }'
```

The evidence pack contains the matched brand token, the score and band, the
individual findings, a **recommended recipient class** for the abuse desk
best positioned to act, and a ready-to-send `noticeSummary` text:

| Candidate type | Recommended recipient      |
| -------------- | -------------------------- |
| `domain`       | `domain_registrar_abuse`   |
| `sender_id`    | `carrier_sms_abuse`        |
| `display_name` | `messaging_platform_abuse` |

(For a lookalike domain you may also need `hosting_provider_abuse`; pick
whichever desk owns the infrastructure the attacker is using.)

List cases, newest first, optionally filtered by status:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/brand-identity/impersonation/cases?status=open" \
  -H "Authorization: Bearer $ORBIT_API_KEY"
```

Advance or dismiss a case:

```bash theme={null}
curl -X PATCH "https://api.orbit.devotel.io/api/v1/brand-identity/impersonation/cases/bpcase_…" \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status": "reported", "note": "Filed with registrar abuse desk."}'
```

The lifecycle is a state machine:

```
open → evidence_ready → reported → resolved
  ↘         ↘               ↘
   dismissed       dismissed   dismissed → (reopen to) open
```

* `open` — assembled, awaiting review.
* `evidence_ready` — you have reviewed the pack and it is ready to file.
* `reported` — you have submitted it to the abuse desk.
* `resolved` — the impersonating asset is down or the desk confirmed action.
* `dismissed` — false positive or accepted risk; a dismissed case can be
  reopened back to `open`.

An impossible jump (`open` → `resolved`, or anything out of `resolved`)
returns `409`; an unknown case id returns `404`. Setting a case to its
current status is an idempotent no-op. Case storage is bounded — the oldest
resolved/dismissed cases are pruned first once a tenant reaches the cap.

Watchlist updates and case lifecycle changes are written to your audit log.

***

## Advisory only — what Orbit does not do for you

This module **detects and prepares; it does not submit**. Assembling the
evidence pack is all Orbit does automatically — actually filing the notice
with a domain registrar, a carrier SMS abuse desk, a hosting provider, or a
messaging platform is **your action, done outside the product**. No case
status advances on its own, nothing is transmitted to an abuse desk, and
`reported` / `resolved` mean what *you* did with the pack, not anything
Orbit sent. These are tenant-owned controls: tune them to your own
trust-and-safety workflow.

***

## Related

* [Sender ID registration](/compliance/sender-id-registration) — register
  the legitimate sender IDs this module protects.
* [Fraud Shield](/compliance/fraud-shield) — the inward-facing counterpart:
  fraud alerts raised on your own account's traffic.
* [Restricted industries](/compliance/restricted-industries) — content
  categories with their own posting rules.
* [Webhook events](/webhooks/events) — subscribe to compliance event
  fan-out.
