:::endpoint GET /v1/admin/fraud/detection

The Detectors screen of the website: whether fraud detection runs, who hears
about a flag, when a trader's risk score suspends them and how long a flag
keeps counting, what Restrict takes away, and every detector with its level,
its score and thresholds and how much it caught.

A trader's risk score is the sum of the scores of every detector they have an
active flag from, once per detector, capped at 100. Only detectors on
`monitor` or `flag` add their score. On `restrict` and `block` the level is the
consequence and the detector adds nothing, and `off` adds nothing either.

The detectors are the platform's, the same 24 for every firm and always in
this order. A firm chooses only their levels, scores and thresholds. One detector with
its open flags and exceptions is [a detector](/docs/api/admin/fraud-detector),
and a change is [a save](/docs/api/admin/fraud-detection-update).

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

## Request

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

## Response

Shortened to two of the 24 detectors:

{
    "data": {
        "object": "fraud_detection",
        "global": {
            "enabled": true,
            "notify_admins": true,
            "escalation_enabled": true,
            "escalation_score": 80,
            "score_window_days": 90,
            "sensitivity": "balanced"
        },
        "restrict": {
            "block_new_orders": true,
            "hold_payouts": true,
            "block_purchases": false,
            "hold_affiliate_payouts": false
        },
        "standing": {
            "restricted": 6,
            "suspended": 1
        },
        "detectors": [
            {
                "object": "fraud_detector",
                "key": "vpn",
                "name": "VPN",
                "description": "A connection through a known commercial VPN exit.",
                "category": "ip",
                "default_level": "flag",
                "default_score": 10,
                "access": true,
                "group": false,
                "level": "flag",
                "score": 10,
                "params": {},
                "overrides": 2,
                "flags_30d": 16,
                "open_flags": 13,
                "exposure": {
                    "traders": 16
                },
                "fields": []
            },
            {
                "object": "fraud_detector",
                "key": "max_countries",
                "name": "Too many countries",
                "description": "One account logging in from more countries than one person plausibly visits.",
                "category": "geo",
                "default_level": "flag",
                "default_score": 20,
                "access": false,
                "group": false,
                "level": "flag",
                "score": 20,
                "params": {
                    "max_countries": 3,
                    "window_days": 30
                },
                "overrides": 1,
                "flags_30d": 1,
                "open_flags": 1,
                "exposure": {
                    "by_country_count": {
                        "1": 11
                    }
                },
                "fields": [
                    {
                        "key": "max_countries",
                        "type": "integer",
                        "default": 3,
                        "min": 1,
                        "max": 50,
                        "unit": "",
                        "options": [],
                        "overridable": true,
                        "label": "Countries allowed",
                        "hint": "Distinct countries an account may log in from inside the window."
                    },
                    {
                        "key": "window_days",
                        "type": "integer",
                        "default": 30,
                        "min": 1,
                        "max": 90,
                        "unit": "d",
                        "options": [],
                        "overridable": true,
                        "label": "Window",
                        "hint": "The rolling period the countries are counted over."
                    }
                ]
            }
        ]
    },
    "meta": {
        "request_id": "req_01m50zcm1n6trjh6w07q0fp3mm"
    }
}

| Field       | Description |
| ----------- | ----------- |
| `global`    | `enabled`, the master switch: off, no detector runs and nothing is enforced. `notify_admins` sends admins a notice when a flag needs a decision. `escalation_enabled` and `escalation_score` (30 to 100) suspend a trader when a new flag takes their risk score to that or higher, whatever the levels. `score_window_days` is how long a flag keeps counting after a detector last saw it: `30`, `60`, `90`, `180` or `365`, or `0` for until somebody decides it. `sensitivity` is deprecated and always `"balanced"`: it was replaced by a score per detector and does nothing |
| `restrict`  | What a restriction takes away: `block_new_orders`, `hold_payouts`, `block_purchases`, `hold_affiliate_payouts` |
| `standing`  | Traders `restricted` right now, and flags that `suspended` somebody |
| `detectors` | Every detector, see below |

| Detector field  | Description |
| --------------- | ----------- |
| `key`           | Stored on every flag it raises, and never changes |
| `name`, `description` | In the admin's language |
| `category`      | `ip`, `geo`, `device`, `linking` or `affiliate` |
| `default_level` | The level of a firm that never chose one |
| `default_score` | The score of a firm that never chose one |
| `access`        | Decides who may connect at all. At `block` it refuses the session instead of suspending the account |
| `group`         | One flag names several accounts at once |
| `level`         | `off`, `monitor`, `flag`, `restrict` or `block` |
| `score`         | What a flag of this detector adds to a trader's risk score, 0 to 100 in steps of 5. Kept on every level, but only counts on `monitor` and `flag` |
| `params`        | The thresholds as the firm set them, by key. `{}` for a detector without any |
| `fields`        | What each threshold is: `type` (`integer`, `choice` or `countries`), `min` and `max`, `unit` (`min`, `s`, `d`, `km`, `km/h`, `%` or empty), the `options` of a choice, the `default`, `overridable` when an override may change it for one trader, and a `label` and `hint` in words |
| `overrides`     | Overrides in force on this detector |
| `flags_30d`     | Flags it raised in the last 30 days |
| `open_flags`    | Its flags that are still active, Monitor ones included |
| `exposure`      | Who it would catch, for six detectors only, over the last 30 days. The four anonymiser detectors give `traders` on such an address. The country policy gives `by_country`, traders per country code, to count what a policy would catch. Too many countries gives `by_country_count`, traders by how many countries they used. Null for the rest |

## 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`                                                            |