# Queue Agent Actions

The **Queue Agent Actions** endpoints log an extension into or out of one queue, pause it with or without a reason, and unpause it. Each request changes only the selected extension's membership; it does not replace or rebuild the other queue members.

## Endpoints

<table id="bkmrk-actionendpoint-login"> <thead><tr><th>Action</th><th>Endpoint</th></tr></thead> <tbody> <tr><td>Login</td><td>`POST /queues/{queueId}/agents/{agentId}/login`</td></tr> <tr><td>Logout</td><td>`POST /queues/{queueId}/agents/{agentId}/logout`</td></tr> <tr><td>Pause</td><td>`POST /queues/{queueId}/agents/{agentId}/pause`</td></tr> <tr><td>Unpause</td><td>`POST /queues/{queueId}/agents/{agentId}/unpause`</td></tr> </tbody></table>

## Authentication and Identifiers

These endpoints require a writable full tenant or global API key. Read-only keys are rejected. The `tenant` query parameter is required and must exactly match the tenant code or tenant name; wildcard tenant selection is not accepted.

<table id="bkmrk-valuerequireddescrip"> <thead><tr><th>Value</th><th>Required</th><th>Description</th></tr></thead> <tbody> <tr><td>`queueId`</td><td>Yes</td><td>The queue's internal ID (`qu_id`), not its dialable queue number.</td></tr> <tr><td>`agentId`</td><td>Yes</td><td>The extension's internal ID (`ex_id`), not its extension number.</td></tr> <tr><td>`tenant`</td><td>Yes</td><td>Exact tenant code or tenant name.</td></tr> <tr><td>`key`</td><td>No, if using headers</td><td>The API key can be sent with `X-API-Key`, `Authorization: Bearer`, or the `key` query parameter.</td></tr> </tbody></table>

## Request Body

Login, logout, and unpause do not need a request body. A pause request accepts an optional JSON body:

```
{
  "reason": "Lunch"
}
```

The reason can contain up to 80 characters. Omit the body, send an empty object, or use an empty reason to pause without a reason. `pausereason` is accepted as a compatibility alias for `reason`; if both names are supplied, their values must match. A pause reason cannot be sent to the other actions.

## Examples

### Log In

```
curl -X POST \
  -H "X-API-Key: TENANT_API_KEY" \
  "https://pbx.example.com/pbx/openapi.php/queues/25/agents/101/login?tenant=CANISTRACCI"
```

### Pause Without a Reason

```
curl -X POST \
  -H "X-API-Key: TENANT_API_KEY" \
  "https://pbx.example.com/pbx/openapi.php/queues/25/agents/101/pause?tenant=CANISTRACCI"
```

### Pause With a Reason

```
curl -X POST \
  -H "X-API-Key: TENANT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reason":"Lunch"}' \
  "https://pbx.example.com/pbx/openapi.php/queues/25/agents/101/pause?tenant=CANISTRACCI"
```

### Unpause and Log Out

```
curl -X POST \
  -H "X-API-Key: TENANT_API_KEY" \
  "https://pbx.example.com/pbx/openapi.php/queues/25/agents/101/unpause?tenant=CANISTRACCI"

curl -X POST \
  -H "X-API-Key: TENANT_API_KEY" \
  "https://pbx.example.com/pbx/openapi.php/queues/25/agents/101/logout?tenant=CANISTRACCI"
```

## Response

```
{
  "object": "queue_agent_action",
  "action": "pause",
  "status": "paused",
  "changed": true,
  "queue": {
    "id": 25,
    "number": "700",
    "name": "Support"
  },
  "agent": {
    "id": 101,
    "number": "100",
    "name": "Reception",
    "peer": "101"
  },
  "members": [
    {
      "membername": "100",
      "interface": "Local/AG-000-NF-101@fromotherpbx/n",
      "state_interface": "Custom:101",
      "member_device": "101",
      "penalty": 0,
      "paused": true,
      "pause_reason": "Lunch"
    }
  ],
  "pbx_refresh": "confirmed",
  "warnings": []
}
```

`changed` is `false` when the requested state was already active. Login and logout are idempotent. Pause and unpause are also idempotent after the agent is logged in; attempting either operation for an extension that is not a member of the queue returns HTTP 409.

`pbx_refresh` reports whether the live Asterisk refresh was confirmed. If the database action succeeds but the refresh cannot be confirmed, the request still returns the saved state with `pbx_refresh` set to `failed` and an explanation in `warnings`. Retrying the same action is safe and requests another refresh.

## Behavior

- Login uses the queue's Agent Identification, Allow Call Optimization, and Ring Offline settings when constructing the member.
- A changed state writes the matching `LOGIN`, `LOGOUT`, `PAUSE`, or `UNPAUSE` queue log event and an activity audit entry.
- Unpause clears the stored pause reason.
- The final database state is checked before a successful response is returned.

## Relevant Errors

<table id="bkmrk-http-statuscodedescr"> <thead><tr><th>HTTP status</th><th>Code</th><th>Description</th></tr></thead> <tbody> <tr><td>400</td><td>`exact_tenant_required`</td><td>The tenant was omitted, does not exactly match the authenticated tenant, or uses a wildcard.</td></tr> <tr><td>400</td><td>`invalid_pause_reason`</td><td>The pause reason is invalid or longer than 80 characters.</td></tr> <tr><td>400</td><td>`conflicting_pause_reason`</td><td>`reason` and `pausereason` contain different values.</td></tr> <tr><td>400</td><td>`pause_reason_not_allowed`</td><td>A reason was sent to login, logout, or unpause.</td></tr> <tr><td>404</td><td>`queue_not_found`</td><td>The queue does not exist in the selected tenant.</td></tr> <tr><td>409</td><td>`agent_not_logged_in`</td><td>Pause or unpause was requested before the extension was logged into the queue.</td></tr> <tr><td>409</td><td>`agent_peer_unavailable`</td><td>The extension does not have a valid queue member device.</td></tr> <tr><td>409</td><td>`queue_agent_state_changed`</td><td>A concurrent change prevented the requested final state from being confirmed; retry the request.</td></tr> <tr><td>500</td><td>`queue_agent_update_failed`</td><td>The membership database operation failed.</td></tr> </tbody></table>