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

# Velocity and anomaly scoring

> Track action frequency across rolling time windows, detect velocity anomalies, and auto-ingest risk signals when thresholds are exceeded.

The velocity and anomaly scoring API tracks how frequently a subject performs a given action across multiple rolling time windows — 1 minute, 5 minutes, 1 hour, and 24 hours. When the weighted velocity score crosses a threshold, the platform automatically creates a [risk signal](/guides/risk-signals), connecting anomaly detection directly to the Anti-Fraud Identity Firewall pipeline.

<Info>
  Velocity scoring is part of the [Anti-Fraud Identity Firewall](/guides/risk-signals). Signals generated by velocity anomalies flow into the same pipeline as other fraud signals, so you can query and review them from the **Risk & Fraud > Signals** console page or the [list signals endpoint](/api-reference/risk-signals/list).
</Info>

## How it works

<Steps>
  <Step title="Record actions">
    Call `POST /v1/risk/velocity/record` each time a subject performs a tracked action — login attempts, API calls, transaction requests, or any custom action type.
  </Step>

  <Step title="Rolling window tracking">
    The platform increments counters for the subject and action type across four rolling windows (1 m, 5 m, 1 h, 24 h). Windows reset automatically when they expire.
  </Step>

  <Step title="Weighted scoring">
    A velocity score is computed from the window counts. Short windows are weighted more heavily to detect bursts: 1 m × 30, 5 m × 20, 1 h × 10, 24 h × 5.
  </Step>

  <Step title="Automatic signal ingestion">
    When the velocity score reaches 60 or above, the platform automatically ingests a risk signal with `signal_type: "velocity"`. You don't need a separate API call.
  </Step>

  <Step title="Review and respond">
    Query velocity windows for a subject, list high-velocity anomalies across your tenant, and review signals in the console or via the API.
  </Step>
</Steps>

## Prerequisites

* An active Truthlocks tenant with an API key
* Action event data from your application (login attempts, API calls, transactions, or any repeatable action)

## Recording an action

Send a `POST` request to `/v1/risk/velocity/record` with the subject, action type, and optional metadata:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.truthlocks.com/v1/risk/velocity/record \
    -H "X-API-Key: tl_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "subject_id": "user_abc123",
      "action_type": "login.failed",
      "ip_address": "198.51.100.42"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.truthlocks.com/v1/risk/velocity/record", {
    method: "POST",
    headers: {
      "X-API-Key": "tl_live_...",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      subject_id: "user_abc123",
      action_type: "login.failed",
      ip_address: "198.51.100.42",
    }),
  });
  const result = await response.json();
  ```

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

  resp = httpx.post(
      "https://api.truthlocks.com/v1/risk/velocity/record",
      headers={"X-API-Key": "tl_live_..."},
      json={
          "subject_id": "user_abc123",
          "action_type": "login.failed",
          "ip_address": "198.51.100.42",
      },
  )
  result = resp.json()
  ```
</CodeGroup>

The response returns the current window counts, the computed velocity score, and whether a risk signal was auto-ingested:

```json theme={null}
{
  "subject_id": "user_abc123",
  "action_type": "login.failed",
  "windows": {
    "1m": 3,
    "5m": 8,
    "1h": 15,
    "24h": 42
  },
  "velocity_score": 72,
  "signal_ingested": true,
  "signal_id": "a1b2c3d4-..."
}
```

## Scoring model

The velocity score is a weighted sum of action counts across four rolling windows. Short windows carry higher weight to prioritize burst detection:

| Window    | Weight | Purpose                                                       |
| :-------- | :----- | :------------------------------------------------------------ |
| 1 minute  | 30     | Detects rapid bursts (credential stuffing, automated attacks) |
| 5 minutes | 20     | Catches sustained short-term abuse                            |
| 1 hour    | 10     | Identifies medium-term patterns                               |
| 24 hours  | 5      | Flags persistent anomalies over longer periods                |

The final score is capped at 100. When the score reaches **60 or above**, a risk signal is automatically ingested with `signal_type: "velocity"`.

### Score interpretation

| Score range | Interpretation | Example                                              |
| :---------- | :------------- | :--------------------------------------------------- |
| 0–29        | Normal         | Typical user activity                                |
| 30–59       | Elevated       | Above-average frequency, worth monitoring            |
| 60–79       | High           | Likely automated or abusive — signal auto-ingested   |
| 80–100      | Critical       | Strong anomaly — immediate investigation recommended |

## Querying velocity windows

Retrieve the current velocity windows for a specific subject:

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.truthlocks.com/v1/risk/velocity/user_abc123 \
    -H "X-API-Key: tl_live_..."
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.truthlocks.com/v1/risk/velocity/user_abc123", {
    headers: { "X-API-Key": "tl_live_..." },
  });
  const windows = await response.json();
  ```

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

  resp = httpx.get(
      "https://api.truthlocks.com/v1/risk/velocity/user_abc123",
      headers={"X-API-Key": "tl_live_..."},
  )
  windows = resp.json()
  ```
</CodeGroup>

The response includes all tracked action types for the subject, with counts per window and the computed velocity score for each:

```json theme={null}
{
  "subject_id": "user_abc123",
  "actions": [
    {
      "action_type": "login.failed",
      "windows": {
        "1m": 0,
        "5m": 2,
        "1h": 8,
        "24h": 23
      },
      "velocity_score": 45
    },
    {
      "action_type": "api.request",
      "windows": {
        "1m": 12,
        "5m": 45,
        "1h": 200,
        "24h": 800
      },
      "velocity_score": 87
    }
  ]
}
```

## Listing high-velocity anomalies

Query subjects with velocity scores above a threshold across your tenant:

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.truthlocks.com/v1/risk/velocity?min_score=50&limit=25" \
    -H "X-API-Key: tl_live_..."
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    "https://api.truthlocks.com/v1/risk/velocity?min_score=50&limit=25",
    { headers: { "X-API-Key": "tl_live_..." } }
  );
  const anomalies = await response.json();
  ```

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

  resp = httpx.get(
      "https://api.truthlocks.com/v1/risk/velocity",
      params={"min_score": 50, "limit": 25},
      headers={"X-API-Key": "tl_live_..."},
  )
  anomalies = resp.json()
  ```
</CodeGroup>

Each result includes the subject, action type, current window counts, and the velocity score that qualified the anomaly:

```json theme={null}
{
  "anomalies": [
    {
      "subject_id": "user_abc123",
      "action_type": "login.failed",
      "windows": {
        "1m": 5,
        "5m": 12,
        "1h": 30,
        "24h": 85
      },
      "velocity_score": 68,
      "last_recorded_at": "2027-07-03T14:22:00Z"
    }
  ],
  "cursor": "eyJsYXN0X2lkIjo..."
}
```

## Integration patterns

### Block or throttle on high velocity

Use the velocity score from the record response to decide whether to allow, throttle, or block an action:

```javascript theme={null}
const result = await recordAction(subjectId, "api.request", ipAddress);

if (result.velocity_score >= 80) {
  await blockSubject(subjectId);
  await notifySecurityTeam(result);
} else if (result.velocity_score >= 60) {
  await throttleRequests(subjectId, { maxPerMinute: 5 });
} else if (result.velocity_score >= 30) {
  await addRateLimitWarning(subjectId);
}
```

### Combine with ATO detection

Velocity scoring tracks any action type across multiple time windows, while [ATO detection](/guides/ato-detection) is specifically optimized for login-based account takeover patterns with built-in threshold rules and alert management. Use both together for layered protection:

* **Velocity scoring** for general abuse detection — API rate abuse, transaction flooding, registration spam
* **ATO detection** for focused login security — failed login velocity, credential stuffing alerts, subject risk profiles

### Monitor via webhooks

Configure a [webhook endpoint](/guides/webhooks) to receive real-time notifications when velocity-based risk signals are created, so your security team can respond without polling.

### Custom action types

You can track any action type your application produces. Common examples:

| Action type            | Use case                      |
| :--------------------- | :---------------------------- |
| `login.failed`         | Failed login attempts         |
| `api.request`          | API call frequency            |
| `transaction.create`   | Payment or transfer attempts  |
| `registration.attempt` | Account creation spam         |
| `password.reset`       | Password reset abuse          |
| `verification.request` | Verification request flooding |

## Usage metering

Each call to `POST /v1/risk/velocity/record` increments the `antifraud.velocity_records` usage counter for your billing cycle. You can monitor your consumption with the [usage API](/api-reference/billing/usage) or in the console at **Settings > Billing > Usage** under the **Anti-Fraud** section.

<Info>
  Velocity record quotas vary by plan tier. See the [billing overview](/billing/overview#metered-products) for details on all Anti-Fraud metered products.
</Info>

## What's next

* [Record velocity action API reference](/api-reference/risk/velocity-record)
* [Get velocity windows API reference](/api-reference/risk/velocity-windows)
* [List velocity anomalies API reference](/api-reference/risk/velocity-anomalies)
* [Risk signals guide](/guides/risk-signals)
* [Account takeover detection guide](/guides/ato-detection)
* [Deepfake and impersonation detection guide](/guides/deepfake-detection)
