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

# Developer API

> Connect your own services to a guild's Technified data with a guild API key.

The Technified API lets you wire your own services into a guild's data: Roblox game servers, custom dashboards, or internal tools. This reference covers the endpoints you can call with a **guild API key**. Dashboard-only routes that require a logged-in session are not listed here.

<Note>
  If you run the [Roblox integration](/roblox-integration/overview), you do not need to call this API yourself. The plugin already handles verification lookups, ban and mute checks, and sync. This API is for builders wiring Technified into their own systems.
</Note>

## Base URL

```
https://api.technified.xyz/api/v1
```

Every path in this reference is appended to that prefix.

## Authentication

You authenticate with a guild API key. A key is bound to one guild, so it can only read and write that guild's data.

### Get a key

<Steps>
  <Step title="Open the dashboard">
    Go to [technified.xyz/dashboard](https://technified.xyz/dashboard) and pick your server.
  </Step>

  <Step title="Create a key">
    Open **Settings > API Keys**, click **Create API Key**, and copy it right away. It is shown only once.
  </Step>
</Steps>

A key looks like `technified_<guildId>_<random>`. You can have up to 10 active keys per guild. Keep keys server-side. Never embed them in Roblox client scripts, browser code, or git. See [API Keys](/dashboard/settings/api-keys) for management.

### Send the key

The API accepts the key in any of three header formats. Use whichever your HTTP client makes easiest.

```http theme={null}
X-API-Key: technified_xxx_yyy
```

```http theme={null}
Authorization: ApiKey technified_xxx_yyy
```

```http theme={null}
Authorization: Bearer technified_xxx_yyy
```

### Which guild the call targets

Your key has a guild ID baked into it. How you point a request at that guild depends on the endpoint:

| Endpoint shape                                                          | How to set the guild                                          |
| ----------------------------------------------------------------------- | ------------------------------------------------------------- |
| Path contains `:guildId` (for example `/moderation/:guildId/...`)       | Put your guild ID in the path. It must match the key's guild. |
| No `:guildId` in the path (for example `/lookup/...`, `/bindings/list`) | Send the `X-Guild-ID` header.                                 |

If the guild in your key does not match the guild you are targeting, the API returns `403`.

## Scopes

Every key created from the dashboard is **scoped**: it can only call the endpoints you granted it. Scopes are `resource:action` pairs. Grant the smallest set your integration needs.

| Scope              | Grants                                                       |
| ------------------ | ------------------------------------------------------------ |
| `moderation:read`  | Ban/mute status, active punishment lists, moderation logs    |
| `moderation:write` | Create and lift Roblox bans and mutes                        |
| `lookup:read`      | Discord/Roblox lookups, reverse lookup, status               |
| `members:read`     | Member lists, verified users, verification links             |
| `verify:write`     | Create verification tokens and link/unlink accounts          |
| `sync:write`       | Role sync, group sync, nickname updates                      |
| `activity:write`   | Staff/Roblox activity, sessions and heartbeats (game plugin) |
| `server:write`     | Server Manager heartbeat, command poll and ack (game plugin) |

A `:write` scope implies the matching `:read` scope for the same resource.

<Note>
  Keys created before scoping keep full access to every endpoint. Editing such a key in the dashboard applies scopes to it. Keys installed by the [Roblox integration](/roblox-integration/overview) quick-install request every scope automatically, so the plugin keeps working.
</Note>

When a key is missing the scope an endpoint needs, the API returns `403` with an `insufficient_scope` detail:

```json theme={null}
{
  "status": "error",
  "code": 403,
  "message": "API key is missing the required scope: moderation:write",
  "details": { "required_scope": "moderation:write" }
}
```

### Check a key's scopes

```http theme={null}
GET /whoami
```

Returns the guild, prefix and granted scopes for the calling key, so a client can discover what it is allowed to do. `scopes` is `null` for a legacy full-access key.

<ResponseExample>
  ```json 200 theme={null}
  {
    "status": "success",
    "code": 200,
    "data": {
      "guild_id": "123456789012345678",
      "prefix": "a1b2c3d4e5",
      "scopes": ["moderation:read", "lookup:read"],
      "legacy": false
    }
  }
  ```
</ResponseExample>

## Key controls

Beyond scopes, each key can carry optional guards, all managed under **Settings > API Keys**:

* **Expiry**: a date after which the key is rejected with `401 API key has expired`.
* **Rate limit**: a per-key requests-per-minute cap, applied on top of the [per-category limits](/developer-api/rate-limits).
* **IP allowlist**: restrict the key to specific IPs or IPv4 CIDR ranges. Requests from any other address get `403`.

## Response shape

Every successful response uses this envelope:

```json theme={null}
{
  "status": "success",
  "code": 200,
  "message": "User is not banned",
  "data": { "banned": false }
}
```

Errors use a matching shape, with optional `details`:

```json theme={null}
{
  "status": "error",
  "code": 401,
  "message": "Invalid API key for this guild"
}
```

See [Errors](/developer-api/errors) for the full list of status codes.

## Quick example

Check whether a Roblox user is banned in your guild.

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.technified.xyz/api/v1/moderation/$GUILD_ID/ban-status/$ROBLOX_ID" \
    -H "X-API-Key: $TECHNIFIED_API_KEY"
  ```

  ```lua Roblox (server-side) theme={null}
  local HttpService = game:GetService("HttpService")
  local API_KEY = "technified_xxx_yyy"

  local function isBanned(guildId, robloxUserId)
      local ok, res = pcall(HttpService.RequestAsync, HttpService, {
          Url = string.format(
              "https://api.technified.xyz/api/v1/moderation/%s/ban-status/%d",
              guildId, robloxUserId
          ),
          Method = "GET",
          Headers = { ["X-API-Key"] = API_KEY },
      })
      if not ok or not res.Success then return false end
      return HttpService:JSONDecode(res.Body).data.banned == true
  end
  ```
</CodeGroup>

```json Response theme={null}
{
  "status": "success",
  "code": 200,
  "message": "User is not banned",
  "data": { "banned": false }
}
```

## Conventions

* Request and response bodies are JSON.
* Discord IDs are stringified snowflakes, for example `"123456789012345678"`.
* Roblox user and group IDs are numbers.
* Timestamps in stored records are Unix seconds unless noted otherwise.
* `:identifier` in moderation paths accepts a Roblox user ID.

## Where to go next

<CardGroup cols={2}>
  <Card title="Lookup" icon="magnifying-glass" href="/developer-api/lookup">
    Resolve verification links between Discord and Roblox.
  </Card>

  <Card title="Moderation" icon="gavel" href="/developer-api/moderation">
    Check ban and mute status, manage Roblox punishments, and read logs.
  </Card>

  <Card title="Members" icon="users" href="/developer-api/members">
    List members and verified users for a guild.
  </Card>

  <Card title="Bindings" icon="link" href="/developer-api/bindings">
    Read and manage role bindings.
  </Card>

  <Card title="Shield" icon="shield" href="/developer-api/shield">
    Check users against the Shield flagged list.
  </Card>

  <Card title="Rate limits" icon="gauge" href="/developer-api/rate-limits">
    Per-category quotas and the 429 response.
  </Card>

  <Card title="Errors" icon="triangle-exclamation" href="/developer-api/errors">
    Status codes and how to recover.
  </Card>
</CardGroup>
