:::endpoint GET /v1/admin/fraud/flags/{flag}

Everything the inspector of the Review queue shows to decide one flag: what the
detector saw, who the flag is about and what it took from each of them, other
traders seen on the same address, and other flags of the same people.

Opening a flag decides nothing. Deciding is [a change of status](/docs/api/admin/fraud-flag-update),
and lifting one person's restriction is [its own call](/docs/api/admin/fraud-restriction-lift).

Needs a firm. Our own staff name one with the `Propper-Workspace` header.

## Request

```bash
curl "https://api.proppertrading.com/v1/admin/fraud/flags/fflag_yhkjqnd8h67ggtbf" \
  -H "Authorization: Bearer ptat_9f2c1a44_3b8e7d2f5c9a1b4e6d8f0a2c4e6b8d1f" \
  -H "Propper-Workspace: acme"
```

## Response

Every field of a [row of the list](/docs/api/admin/fraud-flags), and more:

{
    "data": {
        "object": "fraud_flag",
        "id": "fflag_yhkjqnd8h67ggtbf",
        "detector": "shared_ip",
        "category": "ip",
        "label": "Shared IP",
        "score": 15,
        "severity": "low",
        "risk": 15,
        "level": "restrict",
        "status": "open",
        "subject": "Nikolai Johnson",
        "others": 3,
        "ip": "203.0.113.12",
        "restricted": true,
        "created_at": "2026-08-21T12:14:51+00:00",
        "reviewed_at": null,
        "description": "Several accounts logging in from the exact same address.",
        "access": false,
        "last_seen_at": "2026-08-21T16:49:51+00:00",
        "reviewer": null,
        "network": {
            "location": "Sao Paulo, BR",
            "country_code": "BR",
            "isp": "Vivo",
            "org": "Vivo",
            "asn": "AS44932 Vivo",
            "classification": "residential",
            "is_tor": false,
            "is_proxy": false,
            "is_hosting": false,
            "is_mobile": false
        },
        "evidence": {
            "isp": "British Telecommunications PLC",
            "location": "London, GB",
            "user_count": 4
        },
        "traders": [
            {
                "id": "usr_fr6xeczydychxcvu",
                "name": "Nikolai Johnson",
                "email": "nikolai.johnson.6@example.com",
                "level": "restrict",
                "exempt": false,
                "restriction": {
                    "id": "frest_jdbk9qmced79kyft",
                    "since": "2026-08-21T12:14:51+00:00",
                    "lifted_at": "2026-08-21T17:14:51+00:00",
                    "lifted_by": null
                },
                "suspended": false,
                "open_flags": 1,
                "risk": {
                    "score": 10,
                    "sum": 10,
                    "threshold": 80,
                    "window_days": 90,
                    "lines": [
                        {
                            "flag": "fflag_yhkjqnd8h67ggtbf",
                            "kind": "detector",
                            "flags": 1,
                            "label": null,
                            "level": "restrict",
                            "exempt": false,
                            "points": null,
                            "seen_at": "2026-08-21T16:49:51+00:00",
                            "detector": "shared_ip"
                        },
                        {
                            "flag": "fflag_c2zy2b4yy7j33qmm",
                            "kind": "detector",
                            "flags": 1,
                            "label": null,
                            "level": "flag",
                            "exempt": false,
                            "points": 10,
                            "seen_at": "2026-08-20T09:12:03+00:00",
                            "detector": "vpn"
                        }
                    ]
                },
                "joined_at": "2026-08-31T06:19:14+00:00"
            },
            {
                "id": "usr_z7edd96kjp5nrdcg",
                "name": "Julia Hughes",
                "email": "julia.hughes.7@example.com",
                "level": "restrict",
                "exempt": false,
                "restriction": {
                    "id": "frest_ytz98bnpqvxc3s53",
                    "since": "2026-08-21T12:14:51+00:00",
                    "lifted_at": null,
                    "lifted_by": null
                },
                "suspended": false,
                "open_flags": 1,
                "risk": {
                    "score": 0,
                    "sum": 0,
                    "threshold": 80,
                    "window_days": 90,
                    "lines": [
                        {
                            "flag": "fflag_yhkjqnd8h67ggtbf",
                            "kind": "detector",
                            "flags": 1,
                            "label": null,
                            "level": "restrict",
                            "exempt": false,
                            "points": null,
                            "seen_at": "2026-08-21T16:49:51+00:00",
                            "detector": "shared_ip"
                        }
                    ]
                },
                "joined_at": "2026-09-06T02:22:54+00:00"
            },
            {
                "id": "usr_h4wnyaajk37bn3st",
                "name": "Camila Fischer",
                "email": "camila.fischer.8@example.com",
                "level": null,
                "exempt": true,
                "restriction": null,
                "suspended": false,
                "open_flags": 1,
                "risk": {
                    "score": 0,
                    "sum": 0,
                    "threshold": 80,
                    "window_days": 90,
                    "lines": [
                        {
                            "flag": "fflag_yhkjqnd8h67ggtbf",
                            "kind": "detector",
                            "flags": 1,
                            "label": null,
                            "level": null,
                            "exempt": true,
                            "points": null,
                            "seen_at": "2026-08-21T16:49:51+00:00",
                            "detector": "shared_ip"
                        }
                    ]
                },
                "joined_at": "2026-09-11T10:01:22+00:00"
            },
            {
                "id": "usr_8yrcbhmqm4sa5kvj",
                "name": "Tariq Kim",
                "email": "tariq.kim.9@example.com",
                "level": "flag",
                "exempt": false,
                "restriction": null,
                "suspended": false,
                "open_flags": 1,
                "risk": {
                    "score": 15,
                    "sum": 15,
                    "threshold": 80,
                    "window_days": 90,
                    "lines": [
                        {
                            "flag": "fflag_yhkjqnd8h67ggtbf",
                            "kind": "detector",
                            "flags": 1,
                            "label": null,
                            "level": "flag",
                            "exempt": false,
                            "points": 15,
                            "seen_at": "2026-08-21T16:49:51+00:00",
                            "detector": "shared_ip"
                        }
                    ]
                },
                "joined_at": "2026-04-05T21:41:25+00:00"
            }
        ],
        "neighbours": [
            {
                "id": "usr_6dtx95uysmvhqhhz",
                "name": "Nadia Martin",
                "last_seen_at": "2026-09-11T19:26:51+00:00"
            },
            {
                "id": "usr_8putksyq9xvz42k4",
                "name": "Lotte Oliveira",
                "last_seen_at": "2026-09-11T19:26:51+00:00"
            }
        ],
        "takes": [
            "block_new_orders",
            "hold_payouts"
        ],
        "history": [],
        "action_url": "/admin/fraud?flag=fflag_yhkjqnd8h67ggtbf",
        "can": {
            "manage": true,
            "traders": true,
            "affiliates": true,
            "rules": true
        }
    },
    "meta": {
        "request_id": "req_01m50zckycazn8zmqsahnqswcz"
    }
}

| Field          | Description |
| -------------- | ----------- |
| `description`  | What the detector looks for, in one sentence in the admin's language. Null for a trading rule without one |
| `access`       | Whether the detector decides who may connect at all. At Block such a detector refuses the session rather than suspending the account |
| `last_seen_at` | When the flag last changed. A detector that sees the same situation again refreshes the flag rather than raising a second one, but a decision moves this too |
| `reviewer`     | Who decided it, by name, null while it is active. `Propper` when one of our own staff decided it |
| `network`      | What the address is, from the lookup, when the flag has one address and the lookup ran: `classification` is `residential`, `mobile`, `datacenter`, `vpn`, `residential_proxy`, `tor`, `local` or `unknown` |
| `evidence`     | What the detector measured, as it stored it, with every internal number taken out. Its keys depend on the detector, see below |
| `traders`      | Each person the flag is about: the `level` they were held to, `exempt` when an override kept them out, the `restriction` this flag placed on them (`lifted_at` set once it no longer holds, and `lifted_by` naming who lifted it the same way as `reviewer`), `suspended` when they cannot log in, how many `open_flags` they have, and their `risk` score. `id` and `email` are null for somebody outside the firm, and so is `risk` |
| `traders[].risk` | The trader's risk score and where it comes from. `score` is the total, capped at 100, and `sum` what the lines add up to before the cap. `threshold` is the score that suspends a trader when a new flag reaches it, null while escalation is off. `window_days` is how long a flag counts after it was last seen, `0` for until it is decided. `lines` has one entry per detector the trader has an active flag from, see below |
| `neighbours`   | Up to six other traders of the firm seen on the flag's address, newest sighting first |
| `takes`        | What a restriction takes away at this firm today: `block_new_orders`, `hold_payouts`, `block_purchases`, `hold_affiliate_payouts`. Empty when Restrict takes nothing |
| `history`      | Up to eight other flags of the same people, newest first, as rows of the list |
| `can`          | What this person may do here: `manage` decides flags and lifts restrictions, `traders` opens a trader, `affiliates` an affiliate, `rules` a trading rule |

### Risk score lines

Each line is one detector, once however many flags it raised for this trader.

| Line field | Description |
| ---------- | ----------- |
| `detector` | The detector's key, or a trading rule's |
| `kind`     | `detector`, `trading` for a trading rule, `manual` for a flag raised by somebody of the team, or `blocklist` for an entry of the firm's blocklist. Only `detector` ever adds points |
| `label`    | The rule's name for a trading rule, the reason for a `manual` flag, the value that matched for `blocklist`, null for a detector |
| `level`    | The level the detector has for this trader now, null when exempt or for a trading rule. For `manual` and `blocklist`, the level the flag was raised at |
| `points`   | What it adds. Null when it adds nothing: at `restrict`, `block` or `off` the level is the consequence, an `exempt` trader was kept out of a group flag by an override, and a trading rule never counts |
| `exempt`   | An override kept this trader out of the flag |
| `flag`     | The id of the flag of this detector seen most recently |
| `flags`    | How many active flags of this detector the trader has |
| `seen_at`  | When a detector last saw it |

### Evidence

The keys a detector stores, all of them optional:

| Detector | Keys |
| -------- | ---- |
| `vpn`, `tor`, `residential_proxy`, `datacenter` | `classification`, `isp`, `org`, `location` |
| `shared_ip` | `user_count`, `isp`, `location` |
| `shared_subnet` | `subnet`, `user_count`, `ip_count` |
| `concurrent_sessions` | `active_ip_count`, `window_minutes`, `ips` |
| `impossible_travel` | `from` and `to` (each `location` and `ip`), `distance_km`, `gap_minutes`, `speed_kmh` |
| `new_country` | `country_code`, `known_countries` |
| `country_mismatch` | `registration_country`, `login_country`, `location` |
| `blocked_country` | `country_code`, `policy`, `location` |
| `max_countries` | `count`, `window_days`, `countries` |
| `shared_device` | `device`, `fingerprint`, `user_count` |
| `emulator` | `device`, `fingerprint`, `webgl_renderer` |
| `headless_browser` | `device`, `fingerprint`, `webgl_renderer`, `webdriver` |
| `no_fingerprint` | `grace_minutes` |
| `group_hedging` | `occurrence_count`, `window_seconds`, and `occurrences`, each with `opened_at`, `instrument`, `lots` (the two sizes) and `gap_seconds` |
| `copy_trading` | `similarity_pct`, `matched_trades`, `window_days` |
| `shared_payment` | `fingerprint`, `user_count` |
| `shared_identity` | `phone_masked`, `user_count` |
| `affiliate_shared_device`, `affiliate_shared_ip` | `referral_count`, `shared`, `referrals` (each `id` and `name`), `affiliate` |
| `affiliate_signup_burst` | `referral_count`, `window_days`, `referrals`, `affiliate` |
| `affiliate_refund_pattern` | `purchases`, `refunded`, `refund_pct`, `window_days`, `referrals`, `affiliate` |
| `manual` | `reason`, `trader_message` (what the trader reads instead of the fixed banner), `expires_at` (when the restriction ends), `raised_by` (a name) |
| `blocklist` | `entry` (the blocklist entry's id), `type` (`email`, `email_domain`, `ip`, `device`, `payment` or `phone`), `value`, `where` (`sign_in`, `device` or `payment`) |
| A trading rule | `measured`, `threshold` and `unit` (`%`, `s` or none), `rule` (the rule's id), `rule_name`, and whatever the rule measured: `violation_count`, `window_hours`, `symbol`, `lots`, `open_price`, `stop_loss`, `ticket`, `close_reason`, `size_multiplier`, `first_lots`, `last_lots`, `worst_lots`, `median_lots`, `trade_count`, `buys`, `sells`, `instrument_count`, `max_instruments`, `best_trade_profit`, `net_profit`, `since`, `require_no_sl`, `tickets` |

Countries are ISO codes of two letters. `affiliate` is the affiliate's id, a
`referrals` entry's `id` is null for somebody outside the firm.

## Errors

| Status | Code                      | Meaning                                                                         |
| ------ | ------------------------- | ------------------------------------------------------------------------------- |
| 400    | `workspace_required`      | Asked by our own staff without naming a firm                                    |
| 401    | `invalid_token`           | Not a token, or the secret does not match                                       |
| 401    | `revoked_token`           | Signed out here or from another device                                          |
| 401    | `expired_token`           | Ninety days without use, or a set expiry passed                                 |
| 403    | `admin_access_required`   | This account no longer helps run the environment                                |
| 403    | `insufficient_scope`      | This device does not hold `admin:read`                                          |
| 403    | `workspace_not_permitted` | The `Propper-Workspace` header names an environment this account cannot act in  |
| 403    | `forbidden`               | Without `view_fraud`                                                            |
| 404    | `resource_not_found`      | No flag with that id in this firm                                               |