# API Clients endpoints (Client API: account)

> 19 FeatherPanel Client API: account endpoints from user/api-clients.php: methods, paths, auth, permissions, rate limits, parameters and responses.

Source: https://featherpanel.com/docs/api/reference/user/api-clients/

Defined in [`backend/app/routes/user/api-clients.php`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php). Authentication used here: **Signed-in user**, **Public**. Read [Authentication](https://featherpanel.com/docs/api/authentication/) for how to send credentials and [Rate limits and errors](https://featherpanel.com/docs/api/rate-limits-and-errors/) for the response envelope.

Paths, methods, permissions and rate limits come from the route file. Summaries, parameters and response codes come from the OpenAPI annotations on the controllers; endpoints without annotations show only what the route file declares.

## Endpoints

### GET `/api/user/api-clients`

- Auth: Signed-in user
- Route name: `user-api-clients`
- Controller: [`ApiClientController::getApiClients`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L27)

**Get API clients** Retrieve all API clients for the authenticated user with pagination and search functionality.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `page` | query | integer | no | Page number for pagination |
| `limit` | query | integer | no | Number of records per page |
| `search` | query | string | no | Search term to filter API clients by name |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `api_clients` | ApiClientList\[\] |  |
| `pagination` | ApiClientPagination |  |
| `search` | ApiClientSearch |  |

```bash
curl -X GET "$PANEL_URL/api/user/api-clients" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` API clients retrieved successfully · `400` Bad request - Invalid authentication token · `401` Unauthorized - User not authenticated · `500` Internal server error - Failed to retrieve API clients

### POST `/api/user/api-clients`

- Auth: Signed-in user
- Default rate limit: 10 / minute (`user-api-clients`)
- Route name: `user-api-client-create`
- Controller: [`ApiClientController::createApiClient`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L37)

**Create API client** Create a new API client for the authenticated user with automatically generated public and private keys.

Request body: [`ApiClientCreateRequest`](https://featherpanel.com/docs/api/schemas/#schema-apiclientcreaterequest) (application/json) · Response data: [`ApiClient`](https://featherpanel.com/docs/api/schemas/#schema-apiclient)

| Body field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes | API client name |
| `allowed_ips` | string | no | Allowed IPs/CIDR (newline or comma); omit or empty for no restriction |
| `notify_foreign_ip` | boolean | no | Email when the key is used from a non-allowed IP (requires allowed\_ips) |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `id` | integer | API client ID |
| `user_uuid` | string | User UUID |
| `name` | string | API client name |
| `public_key` | string | Public API key |
| `private_key` | string | Private API key (only shown on creation) |
| `created_at` | string (date-time) | Creation timestamp |
| `updated_at` | string (date-time) | Last update timestamp |
| `allowed_ips` | string | Allowed client IPs/CIDR (newline or comma separated); empty = no restriction |
| `notify_foreign_ip` | string | Email owner when a non-allowed IP attempts to use this key |

```bash
curl -X POST "$PANEL_URL/api/user/api-clients" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"name":"","allowed_ips":"","notify_foreign_ip":false}'
```

Plugin events: [`featherpanel:user:api_client:created`](https://featherpanel.com/docs/plugins/events/user/#user-api-key-created)

Responses: `201` API client created successfully · `400` Bad request - Invalid authentication token, missing required fields, or invalid name length · `401` Unauthorized - User not authenticated · `500` Internal server error - Failed to create API client

### POST `/api/user/api-clients/calagopus/create`

- Auth: Signed-in user
- Default rate limit: 10 / minute (`user-api-clients`)
- Route name: `user-api-client-calagopus-create`
- Controller: [`ApiClientController::calagopusCreate`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L49)

```bash
curl -X POST "$PANEL_URL/api/user/api-clients/calagopus/create" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

### GET `/api/user/api-clients/calagopus/find`

- Auth: Signed-in user
- Default rate limit: 30 / minute (`user-api-clients`)
- Route name: `user-api-client-calagopus-find`
- Controller: [`ApiClientController::calagopusFindByKeyStart`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L61)

```bash
curl -X GET "$PANEL_URL/api/user/api-clients/calagopus/find" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

### POST `/api/user/api-clients/calagopus/update-permissions`

- Auth: Signed-in user
- Default rate limit: 20 / minute (`user-api-clients`)
- Route name: `user-api-client-calagopus-update-permissions`
- Controller: [`ApiClientController::calagopusUpdatePermissions`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L73)

```bash
curl -X POST "$PANEL_URL/api/user/api-clients/calagopus/update-permissions" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

### GET `/api/user/api-clients/{id}`

- Auth: Signed-in user
- Route name: `user-api-client-get`
- Controller: [`ApiClientController::getApiClient`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L85)

**Get specific API client** Retrieve details of a specific API client by ID for the authenticated user.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes | API client ID |

Response data: [`ApiClient`](https://featherpanel.com/docs/api/schemas/#schema-apiclient)

| Response `data` field | Type | Description |
| --- | --- | --- |
| `id` | integer | API client ID |
| `user_uuid` | string | User UUID |
| `name` | string | API client name |
| `public_key` | string | Public API key |
| `private_key` | string | Private API key (only shown on creation) |
| `created_at` | string (date-time) | Creation timestamp |
| `updated_at` | string (date-time) | Last update timestamp |
| `allowed_ips` | string | Allowed client IPs/CIDR (newline or comma separated); empty = no restriction |
| `notify_foreign_ip` | string | Email owner when a non-allowed IP attempts to use this key |

```bash
curl -X GET "$PANEL_URL/api/user/api-clients/$ID" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` API client retrieved successfully · `400` Bad request - Invalid authentication token or API client ID · `401` Unauthorized - User not authenticated · `403` Forbidden - Access denied to API client · `404` Not found - API client not found · `500` Internal server error - Failed to retrieve API client

### PUT `/api/user/api-clients/{id}`

- Auth: Signed-in user
- Default rate limit: 10 / minute (`user-api-clients`)
- Route name: `user-api-client-update`
- Controller: [`ApiClientController::updateApiClient`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L100)

**Update API client** Update an existing API client for the authenticated user (name, allowed IPs/CIDR list, email alert for off-list IPs).

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes | API client ID |

Request body: [`ApiClientUpdateRequest`](https://featherpanel.com/docs/api/schemas/#schema-apiclientupdaterequest) (application/json) · Response data: [`ApiClient`](https://featherpanel.com/docs/api/schemas/#schema-apiclient)

| Body field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | no | API client name |
| `allowed_ips` | string | no | Allowed IPs/CIDR; empty/null clears restriction |
| `notify_foreign_ip` | boolean | no | Email when the key is used from a off-list IP |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `id` | integer | API client ID |
| `user_uuid` | string | User UUID |
| `name` | string | API client name |
| `public_key` | string | Public API key |
| `private_key` | string | Private API key (only shown on creation) |
| `created_at` | string (date-time) | Creation timestamp |
| `updated_at` | string (date-time) | Last update timestamp |
| `allowed_ips` | string | Allowed client IPs/CIDR (newline or comma separated); empty = no restriction |
| `notify_foreign_ip` | string | Email owner when a non-allowed IP attempts to use this key |

```bash
curl -X PUT "$PANEL_URL/api/user/api-clients/$ID" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"name":"","allowed_ips":"","notify_foreign_ip":false}'
```

Plugin events: [`featherpanel:user:api_client:updated`](https://featherpanel.com/docs/plugins/events/user/#user-api-key-updated)

Responses: `200` API client updated successfully · `400` Bad request - Invalid authentication token, API client ID, request data, or invalid name length · `401` Unauthorized - User not authenticated · `403` Forbidden - Access denied to API client · `404` Not found - API client not found · `500` Internal server error - Failed to update API client

### DELETE `/api/user/api-clients/{id}`

- Auth: Signed-in user
- Default rate limit: 10 / minute (`user-api-clients`)
- Route name: `user-api-client-delete`
- Controller: [`ApiClientController::deleteApiClient`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L117)

**Delete API client** Delete an API client for the authenticated user. This is a hard delete operation.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes | API client ID |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `message` | string | Success message |

```bash
curl -X DELETE "$PANEL_URL/api/user/api-clients/$ID" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Plugin events: [`featherpanel:user:api_client:deleted`](https://featherpanel.com/docs/plugins/events/user/#user-api-key-deleted)

Responses: `200` API client deleted successfully · `400` Bad request - Invalid authentication token or API client ID · `401` Unauthorized - User not authenticated · `403` Forbidden - Access denied to API client · `404` Not found - API client not found · `500` Internal server error - Failed to delete API client

### POST `/api/user/api-clients/{id}/regenerate`

- Auth: Signed-in user
- Default rate limit: 5 / minute (`user-api-clients`)
- Route name: `user-api-client-regenerate-keys`
- Controller: [`ApiClientController::regenerateApiKeys`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L134)

**Regenerate API keys** Regenerate both public and private API keys for an existing API client.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | yes | API client ID |

Response data: [`ApiClient`](https://featherpanel.com/docs/api/schemas/#schema-apiclient)

| Response `data` field | Type | Description |
| --- | --- | --- |
| `id` | integer | API client ID |
| `user_uuid` | string | User UUID |
| `name` | string | API client name |
| `public_key` | string | Public API key |
| `private_key` | string | Private API key (only shown on creation) |
| `created_at` | string (date-time) | Creation timestamp |
| `updated_at` | string (date-time) | Last update timestamp |
| `allowed_ips` | string | Allowed client IPs/CIDR (newline or comma separated); empty = no restriction |
| `notify_foreign_ip` | string | Email owner when a non-allowed IP attempts to use this key |

```bash
curl -X POST "$PANEL_URL/api/user/api-clients/$ID/regenerate" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Plugin events: [`featherpanel:user:api_client:updated`](https://featherpanel.com/docs/plugins/events/user/#user-api-key-updated)

Responses: `200` API keys regenerated successfully · `400` Bad request - Invalid authentication token or API client ID · `401` Unauthorized - User not authenticated · `403` Forbidden - Access denied to API client · `404` Not found - API client not found · `500` Internal server error - Failed to regenerate API keys

### GET `/api/user/api-clients/activities`

- Auth: Signed-in user
- Default rate limit: 30 / minute (`user-api-clients`)
- Route name: `user-api-client-activities`
- Controller: [`ApiClientController::getApiClientActivities`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L151)

**Get API client activities** Retrieve API client related activities for the authenticated user with pagination.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `page` | query | integer | no | Page number for pagination |
| `limit` | query | integer | no | Number of records per page |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `activities` | ApiClientActivity\[\] |  |
| `pagination` | ApiClientPagination |  |

```bash
curl -X GET "$PANEL_URL/api/user/api-clients/activities" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` API client activities retrieved successfully · `400` Bad request - Invalid authentication token · `401` Unauthorized - User not authenticated · `500` Internal server error - Failed to retrieve activities

### POST `/api/user/api-clients/validate`

- Auth: Public
- Default rate limit: 10 / minute (`user-api-clients-validate`)
- Route name: `user-api-client-validate`
- Controller: [`ApiClientController::validateApiClient`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L163)

**Validate API client** Validate an API client by public key. This endpoint does not require authentication and only reports whether the key belongs to a valid API client (\`valid\`); no owner data is returned (FP-19).

Request body: [`ApiClientValidationRequest`](https://featherpanel.com/docs/api/schemas/#schema-apiclientvalidationrequest) (application/json) · Response data: [`ApiClientValidationResponse`](https://featherpanel.com/docs/api/schemas/#schema-apiclientvalidationresponse)

| Body field | Type | Required | Description |
| --- | --- | --- | --- |
| `public_key` | string | yes | Public API key to validate |

| Response `data` field | Type | Description |
| --- | --- | --- |
| `valid` | boolean | Whether the API client is valid |

```bash
curl -X POST "$PANEL_URL/api/user/api-clients/validate" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"public_key":""}'
```

Responses: `200` API client validated successfully · `400` Bad request - Missing or empty public key · `404` Not found - Invalid API client or user not found · `500` Internal server error - Failed to validate API client

### GET `/api/user/api-clients/oauth2/metadata`

- Auth: Signed-in user
- Default rate limit: 30 / minute (`user-api-clients-oauth2`)
- Route name: `user-api-client-oauth2-metadata`
- Controller: [`ApiClientController::oauth2Metadata`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L176)

**Validate OAuth2 API consent request metadata** Validates OAuth2 request query parameters and returns normalized request metadata without creating a pending grant.

```bash
curl -X GET "$PANEL_URL/api/user/api-clients/oauth2/metadata" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` Metadata validated successfully · `400` Invalid request data · `403` Feature disabled for account

### GET `/api/user/api-clients/oauth2/authorize`

- Auth: Signed-in user
- Default rate limit: 30 / minute (`user-api-clients-oauth2`)
- Route name: `user-api-client-oauth2-authorize`
- Controller: [`ApiClientController::oauth2Authorize`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L188)

**Prepare OAuth2 API consent payload** Validates an OAuth2-style API key authorization request and returns a normalized payload for consent UI.

```bash
curl -X GET "$PANEL_URL/api/user/api-clients/oauth2/authorize" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` Authorization payload prepared successfully · `400` Invalid request data · `403` Feature disabled for account

### POST `/api/user/api-clients/oauth2/authorize/approve`

- Auth: Signed-in user
- Default rate limit: 30 / minute (`user-api-clients-oauth2`)
- Route name: `user-api-client-oauth2-approve`
- Controller: [`ApiClientController::oauth2Approve`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L200)

**Approve OAuth2 API authorization request** Approves a pending OAuth2 API authorization request, creates API credentials, and returns callback redirect URL.

```bash
curl -X POST "$PANEL_URL/api/user/api-clients/oauth2/authorize/approve" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` Authorization approved · `400` Invalid request token · `403` Unauthorized request

### POST `/api/user/api-clients/oauth2/authorize/deny`

- Auth: Signed-in user
- Default rate limit: 30 / minute (`user-api-clients-oauth2`)
- Route name: `user-api-client-oauth2-deny`
- Controller: [`ApiClientController::oauth2Deny`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L212)

**Deny OAuth2 API authorization request** Denies a pending OAuth2 API authorization request and returns callback redirect URL with access\_denied error.

```bash
curl -X POST "$PANEL_URL/api/user/api-clients/oauth2/authorize/deny" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` Authorization denied · `400` Invalid request token · `403` Unauthorized request

### POST `/api/user/api-clients/oauth2/token`

- Auth: Public
- Default rate limit: 30 / minute (`user-api-clients-oauth2`)
- Route name: `user-api-client-oauth2-token`
- Controller: [`ApiClientController::oauth2Token`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L224)

**Exchange OAuth2 authorization code** Returns stored OAuth2 authorization metadata for approved requests. Use only for server-to-server integrations.

```bash
curl -X POST "$PANEL_URL/api/user/api-clients/oauth2/token" \
  -H "Accept: application/json"
```

Responses: `200` Token exchanged · `400` Invalid code

### POST `/api/user/api-clients/oauth2/device`

- Auth: Public
- Default rate limit: 10 / minute (`user-api-clients-oauth2-device`)
- Route name: `user-api-client-oauth2-device`
- Controller: [`ApiClientController::oauth2DeviceStart`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L236)

**Start OAuth2 device authorization** Starts a serverless/device-code OAuth2 API consent grant that does not require a callback URL. The client polls /oauth2/device/token while the user visits the verification URI.

```bash
curl -X POST "$PANEL_URL/api/user/api-clients/oauth2/device" \
  -H "Accept: application/json"
```

Responses: `200` Device authorization started · `400` Invalid request data

### POST `/api/user/api-clients/oauth2/device/token`

- Auth: Public
- Default rate limit: 20 / minute (`user-api-clients-oauth2-device`)
- Route name: `user-api-client-oauth2-device-token`
- Controller: [`ApiClientController::oauth2DeviceToken`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L248)

**Poll OAuth2 device authorization** Polls a device authorization grant until the user approves or denies, or the grant expires.

```bash
curl -X POST "$PANEL_URL/api/user/api-clients/oauth2/device/token" \
  -H "Accept: application/json"
```

Responses: `200` Credentials issued or pending status · `400` Invalid or denied device code

### GET `/api/user/api-clients/oauth2/device/claim`

- Auth: Signed-in user
- Default rate limit: 30 / minute (`user-api-clients-oauth2-device`)
- Route name: `user-api-client-oauth2-device-claim`
- Controller: [`ApiClientController::oauth2DeviceClaim`](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/Controllers/User/User/ApiClientController.php)
- [route source](https://github.com/MythicalLTD/FeatherPanel/blob/15b94e9fc9df233123706b47c42728b81e48cb3d/backend/app/routes/user/api-clients.php#L260)

**Claim OAuth2 device authorization** Binds a pending device authorization to the logged-in user and returns the consent payload.

```bash
curl -X GET "$PANEL_URL/api/user/api-clients/oauth2/device/claim" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"
```

Responses: `200` Device authorization claimed · `400` Invalid user code · `403` Feature disabled for account
