---
title: "Get identity, GET /me"
description: "Returns the identity attached to the API key you presented. Includes key metadata, granted scopes, and, for reseller keys, the current billing state and permissions."
---

# Get identity

`/me` is the introspection endpoint. It answers the question "who am I to this panel?" from the point of view of the API key that made the request. It is the first call most new integrations make, because it lets you confirm three things at once: the key was accepted, the panel recognizes it, and the scopes you expected are actually granted.

The response shape depends on the type of key you use. An **admin key** gets a compact object with the key's granted scopes and null billing and permissions fields (there is no reseller behind an admin key). A **reseller key** gets the reseller's `reg_user_id`, member group name, the current billing snapshot (credits balance or slot usage), the group-level permissions that gate every write, and the trial-quota window. This is the same data the panel UI shows the reseller in their own dashboard, expressed in a form your code can act on.

Both variants include a `key` object with the key's numeric id, its `pk_live_<prefix>` (the safe half you can share in bug reports), and the list of granted scopes.

## Endpoint

`GET https://<your-panel-domain>/panel-api/v1/me`

## Authentication

Bearer token in the `Authorization` header. Any valid, enabled key works, regardless of scope. See [Authentication](/docs/?page=panel-api-authentication).

## Required scope

None. Every authenticated key can call `/me`. This is deliberate. Introspection has to work before the caller knows what scopes they have.

## Response

Two shapes, distinguished by the `type` field.

### Admin key

| Field | Type | Description |
| ----- | ---- | ----------- |
| `type` | string | Fixed value `"admin"`. |
| `reg_user_id` | null | Admins have no `reg_user_id`. |
| `member_group_id` | null | Admins have no member group. |
| `member_group_name` | null | Admins have no member group. |
| `billing` | null | Admins have no billing state. |
| `permissions` | null | Admins are not gated by member-group permissions. |
| `key` | object | See "Key object" below. |

```json
{
  "type": "admin",
  "reg_user_id": null,
  "member_group_id": null,
  "member_group_name": null,
  "billing": null,
  "permissions": null,
  "key": {
    "id": 1974,
    "prefix": "pk_live_examplekey00",
    "scopes": [
      "lines:read",
      "lines:write",
      "packages:read",
      "bouquets:read",
      "streams:read",
      "vods:read",
      "resellers:read",
      "resellers:write",
      "subresellers:write"
    ]
  }
}
```

### Reseller key

| Field | Type | Description |
| ----- | ---- | ----------- |
| `type` | string | Fixed value `"reseller"`. |
| `reg_user_id` | int | The reseller's numeric id in your panel. Same value you would use as `member_id` from an admin key. |
| `member_group_id` | int | Id of the member group this reseller belongs to. |
| `member_group_name` | string | Human-readable name of the member group. |
| `billing` | object | Snapshot of the reseller's billing state. See "Billing object" below. |
| `permissions` | object | Group-level permissions that gate writes. See "Permissions object" below. |
| `key` | object | See "Key object" below. |

```json
{
  "type": "reseller",
  "reg_user_id": 42,
  "member_group_id": 4,
  "member_group_name": "RESELLER",
  "billing": {
    "mode": "credits",
    "credits": 0.25,
    "max_users": null,
    "active_users": null,
    "billing_expires": null
  },
  "permissions": {
    "allow_change_pass": false,
    "edit_isplock": true,
    "trial_quota": {
      "total_allowed": 100,
      "period": "day",
      "consumed_in_window": 0,
      "window_seconds": 86400
    }
  },
  "key": {
    "id": 1976,
    "prefix": "pk_live_examplekey00",
    "scopes": [
      "lines:read",
      "lines:write",
      "packages:read",
      "bouquets:read",
      "streams:read",
      "vods:read",
      "subresellers:write"
    ]
  }
}
```

### Key object

Present on both variants.

| Field | Type | Description |
| ----- | ---- | ----------- |
| `id` | int | Numeric id of the API key row. |
| `prefix` | string | The `pk_live_<12chars>` public half of the token. Safe to log or paste in support tickets. |
| `scopes` | string[] | List of scopes granted to this key. See [Authentication](/docs/?page=panel-api-authentication) for the full catalog. |

### Billing object (reseller keys only)

| Field | Type | Description |
| ----- | ---- | ----------- |
| `mode` | string | Either `"credits"` or `"users"`. Decides how new lines are paid for. |
| `credits` | number or null | Current credit balance (only set when `mode == "credits"`). |
| `max_users` | int or null | Slot cap for active non-trial lines (only set when `mode == "users"`). |
| `active_users` | int or null | Currently active non-trial lines counted against `max_users` (only set when `mode == "users"`). |
| `billing_expires` | int or null | UTC Unix epoch when the reseller's subscription expires. `null` means no expiry configured. Past values block create and renew for this reseller with `402 billing_expired`. |

### Permissions object (reseller keys only)

| Field | Type | Description |
| ----- | ---- | ----------- |
| `allow_change_pass` | bool | If false, the reseller cannot set a custom password on create or reset. Attempting to do so returns `403 password_change_not_allowed`. |
| `edit_isplock` | bool | If false, the reseller cannot toggle the per-line ISP lock. Attempting to do so returns `403 isplock_not_allowed`. |
| `trial_quota.total_allowed` | int | Maximum trials the reseller can create inside the rolling window. `0` means unlimited. |
| `trial_quota.period` | string | Either `"day"` or `"month"`. Names the size of the rolling window. |
| `trial_quota.consumed_in_window` | int | Trials already created in the current window. |
| `trial_quota.window_seconds` | int | Length of the rolling window in seconds (`86400` or `2592000`). |

## Examples

### cURL

```bash
curl -X GET "https://<your-panel-domain>/panel-api/v1/me" \
  -H "Authorization: Bearer <your-api-key>"
```

### PHP SDK

```php
require __DIR__ . '/api-panel-php-sdk-1.0.0/autoload.php';
use XtreamAI\PanelApi\PanelApiClient;

$client = new PanelApiClient(baseUrl: 'https://<your-panel-domain>', token: '<your-api-key>');
$identity = $client->me->get();
echo $identity->type . "\n";
foreach ($identity->key->scopes as $scope) {
    echo " - " . $scope . "\n";
}
```

### Python SDK

```python
from xtream_ai_panel_api import PanelApiClient

client = PanelApiClient(base_url="https://<your-panel-domain>", token="<your-api-key>")
identity = client.me.get()
print(identity.type)
for scope in identity.key.scopes:
    print(f" - {scope}")
```

## Errors

| HTTP | Error slug | When it happens | How to fix |
| ---- | ---------- | --------------- | ---------- |
| 401 | `invalid_key` | The `Authorization` header is missing, malformed, points to an unknown key, or the key is disabled, expired, deleted, or its IP allow-list excludes the caller. | Verify the token you copied from the panel. Reissue if the key was rotated. |
| 404 | `not_found` | Only on reseller keys, and only in the very rare case where the reseller row was deleted after the key was issued. | Rotate the key from an admin account. |
| 429 | `rate_limited` | You exceeded the per-key or per-IP rate limit. | Back off (see the `Retry-After` header) and lower the call frequency. Cache the result of `/me` per key, it does not change often. |
| 503 | `api_disabled` | An admin has turned the Panel API off for this panel (via the global or tenant kill switch). | Ask the admin to re-enable it. |

## See also

- [Authentication](/docs/?page=panel-api-authentication)
- [Errors, retries and idempotency](/docs/?page=panel-api-errors)
- [Panel API overview](/docs/?page=panel-api-overview)
