# Game Balance

Game development tools for validating game stats against real-world specifications. Identify firearms where your game balance deviates significantly from expected values.

Source: https://docs.gunspec.io/en/api/game

## Balance Report

`GET /v1/game/balance-report`

Auth: API key required  
Tier: Studio+

Returns outliers and distribution warnings across the game stat set, for spotting firearms that are over- or under-tuned relative to the rest of the catalog.

### Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `threshold` | number | no | How far from the mean a stat must sit to be flagged |

### Response 200 (application/json)

| Field | Type | Description |
| --- | --- | --- |
| `data` | object[] | The response payload. |
| `data[].firearmId` | string | Slug of the firearm this row belongs to. |
| `data[].firearmName` | string | Display name of the firearm this row is about. |
| `data[].deviations` | object[] | Every stat on this firearm that sits further from the mean than `threshold`. |
| `data[].deviations[].stat` | string | Which statistic this row is about, named as the field is: `weightEmptyG`, `damage`. |
| `data[].deviations[].value` | number | This firearm value for the stat. |
| `data[].deviations[].mean` | number | Arithmetic mean across the records counted. |
| `data[].deviations[].stdDev` | number | Standard deviation across the records counted. |
| `data[].deviations[].zScore` | number | Standard deviations from the mean. Positive is above it; the sign says which way the firearm is out of line. |

```json
{
  "success": true,
  "data": [
    {
      "firearmId": "m2-browning",
      "firearmName": "M2 Browning",
      "deviations": [
        {
          "stat": "damage",
          "value": 98,
          "mean": 54.2,
          "stdDev": 12.9,
          "zScore": 3.4
        }
      ]
    }
  ]
}
```

### Errors

| Status | Code | Message |
| --- | --- | --- |
| 400 | `VALIDATION_ERROR` | Validation error |
| 401 | `UNAUTHORIZED` | API key required |
| 403 | `FORBIDDEN` | Valid key, not permitted |
| 429 | `RATE_LIMITED` | Rate limit exceeded |
| 500 | `INTERNAL_ERROR` | Unexpected server error |

### Notes

- Requires **Studio** tier or higher.
- Only firearms with at least one deviation exceeding the threshold are included in the response.
- Expected values are derived from real-world specs (muzzle energy, weight, dimensions, etc.) normalized to a 0-100 scale within each firearm category.
- A lower threshold surfaces more deviations, useful for fine-tuning. A higher threshold only flags major outliers.

### Example

```bash
curl --request GET \
  --url 'https://api.gunspec.io/v1/game/balance-report?threshold=20' \
  --header 'X-API-Key: your_key'
```

## Tier List

`GET /v1/game/tier-list`

Auth: API key required  
Tier: Builder+

Ranks firearms into S/A/B/C/D tiers for a single game stat.

### Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `stat` | string | no | Which stat to tier by |
| `category` | string | no | Restrict the tier list to a category slug |

### Response 200 (application/json)

| Field | Type | Description |
| --- | --- | --- |
| `data` | object | The response payload. |
| `data.stat` | string | Which statistic this row is about, named as the field is: `weightEmptyG`, `damage`. |
| `data.tiers` | object | Firearms grouped into tiers, strongest first. |
| `data.tiers.S` | object[] | Top tier for this stat. |
| `data.tiers.A` | object[] | Second tier. |
| `data.tiers.B` | object[] | Third tier. |
| `data.tiers.C` | object[] | Fourth tier. |
| `data.tiers.D` | object[] | Bottom tier for this stat. |

```json
{
  "success": true,
  "data": {
    "stat": "damage",
    "tiers": {
      "S": [
        {
          "id": "ak-47",
          "name": "AK-47",
          "categoryId": "assault-rifle",
          "value": 72
        }
      ],
      "A": [
        {
          "id": "ak-47",
          "name": "AK-47",
          "categoryId": "assault-rifle",
          "value": 72
        }
      ],
      "B": [
        {
          "id": "ak-47",
          "name": "AK-47",
          "categoryId": "assault-rifle",
          "value": 72
        }
      ],
      "C": [
        {
          "id": "ak-47",
          "name": "AK-47",
          "categoryId": "assault-rifle",
          "value": 72
        }
      ],
      "D": [
        {
          "id": "ak-47",
          "name": "AK-47",
          "categoryId": "assault-rifle",
          "value": 72
        }
      ]
    }
  }
}
```

### Errors

| Status | Code | Message |
| --- | --- | --- |
| 400 | `VALIDATION_ERROR` | Validation error |
| 401 | `UNAUTHORIZED` | API key required |
| 403 | `FORBIDDEN` | Valid key, not permitted |
| 429 | `RATE_LIMITED` | Rate limit exceeded |
| 500 | `INTERNAL_ERROR` | Unexpected server error |

### Notes

- Requires **Builder** tier or higher.
- Valid stats: `damage`, `accuracy`, `range`, `fireRate`, `mobility`, `recoilControl`, `reloadSpeed`, `concealment`.
- Omit the stat parameter to rank by a composite score across all 8 stats.
- Tiers use percentile bucketing: S (90th+), A (75-90th), B (50-75th), C (25-50th), D (<25th).

### Example

```bash
curl --request GET \
  --url 'https://api.gunspec.io/v1/game/tier-list?stat=damage&category=rifle' \
  --header 'X-API-Key: your_key'
```

## Matchups

`GET /v1/game/matchups`

Auth: API key required  
Tier: Builder+

Returns a per-stat verdict between two firearms using their game-balance stats, plus the overall tally.

### Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `a` | string | yes | First firearm slug |
| `b` | string | yes | Second firearm slug |

### Response 200 (application/json)

| Field | Type | Description |
| --- | --- | --- |
| `data` | object | The response payload. |
| `data.a` | object | The firearm named by the `a` parameter. |
| `data.a.id` | string | Slug of the first firearm. |
| `data.a.name` | string | Display name, as the maker writes it. |
| `data.a.stats` | object | The editorial game stats, with the `game` prefix the column carries stripped. |
| `data.b` | object | The firearm named by the `b` parameter. |
| `data.b.id` | string | Slug of the second firearm. |
| `data.b.name` | string | Display name, as the maker writes it. |
| `data.b.stats` | object | The editorial game stats, with the `game` prefix the column carries stripped. |
| `data.verdicts` | object | The per-stat verdict, keyed by stat rather than listed. |
| `data.verdicts.damage` | string | Which firearm wins on damage: `a`, `b`, or `draw`. |
| `data.verdicts.accuracy` | string | Which firearm wins on accuracy. |
| `data.verdicts.range` | string | Which firearm wins on range. |
| `data.verdicts.fireRate` | string | Which firearm wins on rate of fire. |
| `data.verdicts.mobility` | string | Which firearm wins on mobility. |
| `data.verdicts.recoilControl` | string | Which firearm wins on recoil control. |
| `data.verdicts.reloadSpeed` | string | Which firearm wins on reload speed. |
| `data.verdicts.concealment` | string | Which firearm wins on concealment. |
| `data.aWins` | integer | How many statistics the first firearm wins. |
| `data.bWins` | integer | How many statistics the second firearm wins. |
| `data.draws` | integer | How many statistics are tied. |

```json
{
  "success": true,
  "data": {
    "a": {
      "id": "ak-47",
      "name": "AK-47",
      "stats": {
        "damage": 72,
        "accuracy": 64,
        "range": 58,
        "fireRate": 70,
        "mobility": 55,
        "recoilControl": 48,
        "reloadSpeed": 60,
        "concealment": 30
      }
    },
    "b": {
      "id": "m16a1",
      "name": "M16A1",
      "stats": {
        "damage": 72,
        "accuracy": 64,
        "range": 58,
        "fireRate": 70,
        "mobility": 55,
        "recoilControl": 48,
        "reloadSpeed": 60,
        "concealment": 30
      }
    },
    "verdicts": {
      "damage": "a",
      "accuracy": "b",
      "range": "draw",
      "fireRate": "a",
      "mobility": "b",
      "recoilControl": "b",
      "reloadSpeed": "a",
      "concealment": "b"
    },
    "aWins": 4,
    "bWins": 3,
    "draws": 1
  }
}
```

### Errors

| Status | Code | Message |
| --- | --- | --- |
| 400 | `VALIDATION_ERROR` | Validation error |
| 401 | `UNAUTHORIZED` | API key required |
| 403 | `FORBIDDEN` | Valid key, not permitted |
| 404 | `NOT_FOUND` | Resource not found |
| 429 | `RATE_LIMITED` | Rate limit exceeded |
| 500 | `INTERNAL_ERROR` | Unexpected server error |

### Notes

- Requires **Builder** tier or higher.
- Verdicts cover all 8 game stats: damage, accuracy, range, fireRate, mobility, recoilControl, reloadSpeed, concealment. Each value is `a`, `b` or `draw`.

### Example

```bash
curl --request GET \
  --url 'https://api.gunspec.io/v1/game/matchups?a=ak-47&b=m16a1' \
  --header 'X-API-Key: your_key'
```

## Role Roster

`GET /v1/game/role-roster`

Auth: API key required  
Tier: Builder+

Returns the firearms best suited to a gameplay role, scored against that role weighting of the game stats.

### Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `role` | string | yes | Gameplay role |
| `count` | integer | no | How many to return |

### Response 200 (application/json)

| Field | Type | Description |
| --- | --- | --- |
| `data` | object[] | The best-scoring firearms for the role, strongest first. |
| `data[].id` | string | Slug of the firearm. |
| `data[].name` | string | Display name, as the maker writes it. |
| `data[].roleScore` | number | Fit for this role, 0 to 100, from the role weighting of the game stats. |
| `data[].stats` | object | The editorial game stats, with the `game` prefix the column carries stripped. |
| `data[].stats.damage` | integer \| null | Editorial damage rating, 0-100. Not a measured figure. |
| `data[].stats.accuracy` | integer \| null | Editorial accuracy rating, 0-100. |
| `data[].stats.range` | integer \| null | Editorial range rating, 0-100. |
| `data[].stats.fireRate` | integer \| null | Editorial rate-of-fire rating, 0-100. |
| `data[].stats.mobility` | integer \| null | Editorial mobility rating, 0-100. |
| `data[].stats.recoilControl` | integer \| null | Editorial recoil-control rating, 0-100. |
| `data[].stats.reloadSpeed` | integer \| null | Editorial reload-speed rating, 0-100. |
| `data[].stats.concealment` | integer \| null | Editorial concealment rating, 0-100. |

```json
{
  "success": true,
  "data": [
    {
      "id": "m4a1",
      "name": "M4A1",
      "roleScore": 78.2,
      "stats": {
        "damage": 72,
        "accuracy": 64,
        "range": 58,
        "fireRate": 70,
        "mobility": 55,
        "recoilControl": 48,
        "reloadSpeed": 60,
        "concealment": 30
      }
    }
  ]
}
```

### Errors

| Status | Code | Message |
| --- | --- | --- |
| 400 | `VALIDATION_ERROR` | Validation error |
| 401 | `UNAUTHORIZED` | API key required |
| 403 | `FORBIDDEN` | Valid key, not permitted |
| 429 | `RATE_LIMITED` | Rate limit exceeded |
| 500 | `INTERNAL_ERROR` | Unexpected server error |

### Notes

- Requires **Builder** tier or higher.
- Valid roles: `sniper`, `assault`, `tank`, `support`, `stealth`, `speedster`.
- Each role uses different stat weights for scoring (e.g. sniper: range 0.30, accuracy 0.25, damage 0.25).
- Use this to auto-populate role-based loadout screens in your game.

### Example

```bash
curl --request GET \
  --url 'https://api.gunspec.io/v1/game/role-roster?role=assault&count=5' \
  --header 'X-API-Key: your_key'
```

## Stat Distribution

`GET /v1/game/stat-distribution`

Auth: API key required  
Tier: Studio+

Returns mean, median, standard deviation, percentiles, and a histogram for a single game stat across the catalog.

### Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `stat` | string | yes | Which stat to profile |

### Response 200 (application/json)

| Field | Type | Description |
| --- | --- | --- |
| `data` | object | The response payload. |
| `data.stat` | string | Which statistic this row is about, named as the field is: `weightEmptyG`, `damage`. |
| `data.count` | integer | How many records fall in this bucket. |
| `data.mean` | number | Arithmetic mean across the records counted. |
| `data.median` | number | Middle value of the stat across the catalog. |
| `data.stdDev` | number | Standard deviation across the records counted. |
| `data.min` | number | Lowest value of the stat across the catalog. |
| `data.max` | number | Highest value of the stat across the catalog. |
| `data.percentiles` | object | Percentile cut points for the stat. |
| `data.percentiles.p10` | number | 10th percentile. |
| `data.percentiles.p25` | number | 25th percentile. |
| `data.percentiles.p50` | number | 50th percentile, equal to `median`. |
| `data.percentiles.p75` | number | 75th percentile. |
| `data.percentiles.p90` | number | 90th percentile. |
| `data.histogram` | object[] | Firearm counts across ten fixed bands of width 10, from `0-10` to `90-100`. |
| `data.histogram[].bucket` | string | The band this bucket covers, `lo-hi`. Half-open, so a value equal to `hi` falls in the next bucket, except `90-100`, which includes 100. |
| `data.histogram[].count` | integer | How many records fall in this bucket. |

```json
{
  "success": true,
  "data": {
    "stat": "damage",
    "count": 842,
    "mean": 54.31,
    "median": 55,
    "stdDev": 17.62,
    "min": 8,
    "max": 98,
    "percentiles": {
      "p10": 30,
      "p25": 42,
      "p50": 55,
      "p75": 67,
      "p90": 78
    },
    "histogram": [
      {
        "bucket": "50-60",
        "count": 184
      }
    ]
  }
}
```

### Errors

| Status | Code | Message |
| --- | --- | --- |
| 400 | `VALIDATION_ERROR` | Validation error |
| 401 | `UNAUTHORIZED` | API key required |
| 403 | `FORBIDDEN` | Valid key, not permitted |
| 429 | `RATE_LIMITED` | Rate limit exceeded |
| 500 | `INTERNAL_ERROR` | Unexpected server error |

### Notes

- Requires **Studio** tier or higher.
- Valid stats: `damage`, `accuracy`, `range`, `fireRate`, `mobility`, `recoilControl`, `reloadSpeed`, `concealment`.
- Histogram uses 10-point buckets from 0 to 100.
- Useful for identifying stat clusters and balance issues.

### Example

```bash
curl --request GET \
  --url 'https://api.gunspec.io/v1/game/stat-distribution?stat=damage' \
  --header 'X-API-Key: your_key'
```
