LSGridSign in

Version 1

LSGrid API

Read your server's moderation logs, shifts, CAD and who's in game from your own Discord bot, website or tool. The API is read-only: it can't change anything on LSGrid.

Getting a key

In your server on LSGrid, open Settings, then API keys, and make a key. Only the owner and Administrators can. Each key belongs to one server and can read all of it, so treat it like a password:

Making requests

Send the key in the Authorization header. Every endpoint is a GET under https://lsgrid.xyz/api/v1 and answers in JSON. Times are Unix seconds.

curl https://lsgrid.xyz/api/v1/server \
  -H "Authorization: Bearer lcg_your_key_here"

In JavaScript:

const r = await fetch("https://lsgrid.xyz/api/v1/moderation?limit=10", {
  headers: { Authorization: `Bearer ${process.env.LCGRID_KEY}` },
});
const { logs } = await r.json();

The API doesn't send CORS headers, so a browser can't call it directly. That's on purpose: a key in a web page is a key anyone can copy.

Limits

Each key can make 120 requests a minute. Every reply says where you are with X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (seconds until the count starts again). Over the limit you get a 429 with a Retry-After header. Live game data refreshes every 10 seconds, so polling /players faster than that only returns the same answer.

Errors

Anything that isn't a success comes back with an error code you can check and a sentence you can show:

{
  "error": {
    "code": "unauthorized",
    "message": "Send a valid API key as Authorization: Bearer lcg_..."
  }
}

Endpoints

GET /api/v1/server

The server the key belongs to, with its member count and CAD departments.

{
  "server": {
    "id": "2670461625",
    "name": "Westview County RP",
    "created_at": 1793441722,
    "members": 10,
    "erlc_connected": true,
    "discord_connected": true,
    "departments": [
      {
        "id": 1,
        "name": "Westview Police",
        "short": "WPD",
        "color": "#5b8def",
        "kind": "police"
      }
    ]
  }
}

GET /api/v1/moderation

Moderation logs, newest first. Deleted and hidden logs aren't included.

{
  "logs": [
    {
      "id": 31,
      "type": "ban",
      "player": {
        "roblox_id": "1500087109",
        "name": "xXDriftKingXx",
        "display_name": "Drift"
      },
      "reason": "Fail RP, ramming civilians",
      "evidence": [
        "https://..."
      ],
      "by": {
        "id": "900000000000000101",
        "name": "Marcus Reed"
      },
      "created_at": 1794540000,
      "edited_at": null
    }
  ],
  "next": "?before=31&limit=50"
}

GET /api/v1/shifts

Staff shifts, newest first.

{
  "shifts": [
    {
      "id": 26,
      "user": {
        "id": "900000000000000104",
        "name": "Jordan Hayes"
      },
      "started_at": 1794540939,
      "ended_at": null,
      "on_break": false,
      "break_seconds": 0
    }
  ],
  "next": null
}

GET /api/v1/cad/calls

CAD calls, newest first.

{
  "calls": [
    {
      "id": 8,
      "number": 302,
      "kind": "Traffic stop",
      "priority": 3,
      "status": "active",
      "location": "Highway 1 northbound",
      "postal": "306",
      "details": "Grey sedan, no plates",
      "caller": "",
      "departments": [
        1
      ],
      "units": [
        "1A-21"
      ],
      "created_by": "Dispatch",
      "created_at": 1794540800,
      "updated_at": 1794540900,
      "closed_at": null
    }
  ]
}

GET /api/v1/cad/units

Units signed on to the CAD right now.

{
  "units": [
    {
      "user": {
        "id": "900000000000000101",
        "name": "Marcus Reed"
      },
      "callsign": "1A-12",
      "department_id": 1,
      "status": "enroute",
      "call_id": 6,
      "roblox": {
        "id": "1500087101",
        "name": "MarcusReed"
      },
      "signed_on_at": 1794539000,
      "updated_at": 1794540950
    }
  ]
}

GET /api/v1/players

Who's in the FiveM server right now, and how many are waiting in the queue. Needs the server's FiveM key connected in LSGrid. It uses the same snapshot as the dashboard, so it never adds load to FiveM.

{
  "players": [
    {
      "roblox_id": "1500087101",
      "name": "MarcusReed",
      "team": "Police",
      "callsign": "1A-12",
      "staff": false
    }
  ],
  "count": 1,
  "queue": 0
}

Changes

We add fields and endpoints without warning, so ignore fields you don't know. Anything that would break a working bot, like removing or renaming a field, only happens in a new version under a new address, and the changelog says so first.

Fair use

Use the API for your own server and community, within the Terms. Don't use it to collect data about players for anything else, and don't share what it returns publicly unless your server's members know. We may revoke keys that are abused.

Help

Questions or a bug: support@lcgrid.xyz.