# Wazuh REST API 4.14 - Complete Reference Guide

> Wazuh 4.14 REST API - agent, manager, cluster, rules, decoders, SCA, vulnerability endpoints, auth, filtering, Python SDK, and Postman

Source: https://opennix.org/en/docs/wazuh/development/wazuh-api-reference/


The Wazuh 4.14 REST API provides programmatic access to every platform capability: agent management, alert retrieval, rule and decoder administration, cluster monitoring, and security management through RBAC. The API runs on port 55000 of the Wazuh Manager server and uses JWT authentication.

## Authentication

### Obtaining a JWT Token

All API requests require a JWT token obtained through the authentication endpoint:

```bash
TOKEN=$(curl -sk -u wazuh-wui:YOUR_PASSWORD \
  -X POST "https://localhost:55000/security/user/authenticate?raw=true")
```

The `raw=true` parameter returns the token string without a JSON wrapper.

### Using the Token

Pass the token in the `Authorization` header:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/agents?limit=5"
```

### Token Expiration

The JWT token is valid for 15 minutes (900 seconds) by default. To change the expiration, use the security configuration endpoint:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  -X PUT "https://localhost:55000/security/config" \
  -H "Content-Type: application/json" \
  -d '{"auth_token_exp_timeout": 3600}'
```

### Python SDK - Authentication

```python
import requests
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

WAZUH_API = "https://localhost:55000"
CREDENTIALS = ("wazuh-wui", "YOUR_PASSWORD")

def get_token() -> str:
    """Obtain a JWT token from the Wazuh API."""
    response = requests.post(
        f"{WAZUH_API}/security/user/authenticate?raw=true",
        auth=CREDENTIALS,
        verify=False,
    )
    response.raise_for_status()
    return response.text

def api_request(method: str, endpoint: str, **kwargs) -> dict:
    """Execute an authenticated API request."""
    token = get_token()
    headers = {"Authorization": f"Bearer {token}"}
    response = requests.request(
        method,
        f"{WAZUH_API}{endpoint}",
        headers=headers,
        verify=False,
        **kwargs,
    )
    response.raise_for_status()
    return response.json()
```

## Pagination, Filtering, and Sorting

### Pagination

All list endpoints support pagination:

| Parameter | Description | Default | Maximum |
|---|---|---|---|
| `offset` | Number of items to skip | 0 | - |
| `limit` | Number of items to return | 500 | 100000 |

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/agents?offset=0&limit=10"
```

### Filtering

The API supports filtering via query parameters:

```bash
# Filter agents by status
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/agents?status=active"

# Filter by multiple parameters
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/agents?status=active&os.platform=ubuntu"
```

### Search

The `search` parameter performs a full-text search:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/agents?search=web-server"
```

### Sorting

The `sort` parameter controls result ordering:

```bash
# Sort by name (ascending)
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/agents?sort=+name"

# Sort by ID (descending)
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/agents?sort=-id"
```

### Field Selection

The `select` parameter limits returned fields:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/agents?select=id,name,status,os.name"
```

## Endpoints: Agents

### GET /agents

Retrieve the agent list with filtering support:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/agents?status=active&limit=5" | jq '.data.affected_items[] | {id, name, status}'
```

Response:

```json
{
  "data": {
    "affected_items": [
      {"id": "001", "name": "web-server-01", "status": "active"},
      {"id": "002", "name": "db-server-01", "status": "active"}
    ],
    "total_affected_items": 2,
    "total_failed_items": 0,
    "failed_items": []
  }
}
```

### GET /agents/{agent_id}

Detailed agent information:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/agents/001" | jq '.data.affected_items[0]'
```

### DELETE /agents

Remove agents (supports bulk deletion):

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  -X DELETE "https://localhost:55000/agents?agents_list=005,006&status=disconnected&older_than=7d"
```

### PUT /agents/{agent_id}/restart

Restart an agent:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  -X PUT "https://localhost:55000/agents/001/restart"
```

### PUT /agents/group/{group_id}

Assign agents to a group:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  -X PUT "https://localhost:55000/agents/group/web-servers" \
  -H "Content-Type: application/json" \
  -d '{"agents_list": ["001", "002"]}'
```

### Python SDK - Agent Operations

```python
# List active agents
agents = api_request("GET", "/agents", params={"status": "active", "limit": 100})
for agent in agents["data"]["affected_items"]:
    print(f"Agent {agent['id']}: {agent['name']} ({agent['status']})")

# Restart an agent
api_request("PUT", "/agents/001/restart")

# Get agent OS information
agent_info = api_request("GET", "/agents/001", params={"select": "os.name,os.version,os.platform"})
```

## Endpoints: Manager

### GET /manager/info

Wazuh Manager server information:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/manager/info" | jq '.data.affected_items[0]'
```

### GET /manager/status

Status of all Wazuh daemons:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/manager/status" | jq '.data.affected_items[0]'
```

### GET /manager/configuration

Current manager configuration:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/manager/configuration?section=global"
```

### GET /manager/logs

Manager logs:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/manager/logs?limit=20&sort=-timestamp"
```

### GET /manager/stats

Event processing statistics:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/manager/stats?date=$(date +%Y-%m-%d)"
```

## Endpoints: Cluster

### GET /cluster/status

Cluster status:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/cluster/status"
```

### GET /cluster/nodes

List cluster nodes:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/cluster/nodes" | jq '.data.affected_items[] | {name, type, version}'
```

### GET /cluster/healthcheck

Cluster health check:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/cluster/healthcheck"
```

### GET /cluster/{node_id}/info

Specific node information:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/cluster/node01/info"
```

## Endpoints: Rules

### GET /rules

List rules:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/rules?limit=10&level=12-15" | jq '.data.affected_items[] | {id, level, description}'
```

### GET /rules/{rule_id}

Rule details:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/rules/5710"
```

### GET /rules/groups

List rule groups:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/rules/groups"
```

### GET /rules/files

List rule files:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/rules/files?status=custom"
```

### PUT /rules/files/{filename}

Update a custom rule file:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  -X PUT "https://localhost:55000/rules/files/local_rules.xml" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @local_rules.xml
```

## Endpoints: Decoders

### GET /decoders

List decoders:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/decoders?limit=10&search=sshd"
```

### GET /decoders/{decoder_name}

Specific decoder information:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/decoders/sshd"
```

### GET /decoders/files

List decoder files:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/decoders/files?status=custom"
```

### PUT /decoders/files/{filename}

Update a custom decoder file:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  -X PUT "https://localhost:55000/decoders/files/local_decoder.xml" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @local_decoder.xml
```

## Endpoints: SCA (Security Configuration Assessment)

### GET /sca/{agent_id}

SCA results for an agent:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/sca/001" | jq '.data.affected_items[] | {policy_id, pass, fail, score}'
```

### GET /sca/{agent_id}/checks/{policy_id}

Detailed check results for a policy:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/sca/001/checks/cis_ubuntu22-04" \
  | jq '.data.affected_items[] | select(.result == "failed") | {id, title, result}'
```

### Python SDK - SCA Report

```python
def get_sca_report(agent_id: str) -> list[dict]:
    """Generate an SCA compliance report for an agent."""
    policies = api_request("GET", f"/sca/{agent_id}")
    report = []
    for policy in policies["data"]["affected_items"]:
        total = policy["pass"] + policy["fail"] + policy.get("invalid", 0)
        report.append({
            "policy": policy["policy_id"],
            "score": f"{policy['score']}%",
            "passed": policy["pass"],
            "failed": policy["fail"],
            "total": total,
        })
    return report
```

## Endpoints: Vulnerabilities

### GET /vulnerability/{agent_id}

Detected vulnerabilities on an agent:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/vulnerability/001?limit=10&severity=Critical" \
  | jq '.data.affected_items[] | {cve, name, severity, version}'
```

### GET /vulnerability/{agent_id}/summary/{field}

Vulnerability summary by field:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/vulnerability/001/summary/severity"
```

### Python SDK - Vulnerability Report

```python
def get_vulnerability_summary(agent_id: str) -> dict:
    """Get vulnerability summary grouped by severity."""
    vulns = api_request(
        "GET",
        f"/vulnerability/{agent_id}",
        params={"limit": 500},
    )

    summary = {"Critical": 0, "High": 0, "Medium": 0, "Low": 0}
    for vuln in vulns["data"]["affected_items"]:
        severity = vuln.get("severity", "Low")
        summary[severity] = summary.get(severity, 0) + 1

    return summary
```

## Endpoints: Syscollector (System Inventory)

### GET /syscollector/{agent_id}/os

Operating system information:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/syscollector/001/os"
```

### GET /syscollector/{agent_id}/packages

Installed packages:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/syscollector/001/packages?limit=20&sort=-size"
```

### GET /syscollector/{agent_id}/ports

Open ports:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/syscollector/001/ports?state=listening"
```

### GET /syscollector/{agent_id}/processes

Running processes:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/syscollector/001/processes?limit=20&sort=-resident_size"
```

### GET /syscollector/{agent_id}/netiface

Network interfaces:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/syscollector/001/netiface"
```

### GET /syscollector/{agent_id}/hardware

Hardware information:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/syscollector/001/hardware"
```

Wazuh 4.14 introduces extended syscollector fields, including detailed CPU, RAM, and disk subsystem data. Existing fields remain backward-compatible.

## Endpoints: Security and RBAC

### GET /security/users

List API users:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/security/users"
```

### POST /security/users

Create a user:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  -X POST "https://localhost:55000/security/users" \
  -H "Content-Type: application/json" \
  -d '{"username": "analyst", "password": "SecureP@ss123!"}'
```

### GET /security/roles

List RBAC roles:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/security/roles"
```

### POST /security/roles

Create a role:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  -X POST "https://localhost:55000/security/roles" \
  -H "Content-Type: application/json" \
  -d '{"name": "read-only-analyst", "rule": {"FIND": {"r^agent": ["read"]}}}'
```

### POST /security/user/{user_id}/roles

Assign a role to a user:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  -X POST "https://localhost:55000/security/user/100/roles?role_ids=2"
```

### GET /security/policies

List RBAC policies:

```bash
curl -sk -H "Authorization: Bearer ${TOKEN}" \
  "https://localhost:55000/security/policies"
```

## Error Codes

The Wazuh API uses standard HTTP codes alongside its own error codes.

### HTTP Codes

| Code | Description |
|---|---|
| 200 | Successful request |
| 400 | Bad request (invalid parameters) |
| 401 | Unauthorized (invalid token) |
| 403 | Forbidden (insufficient RBAC permissions) |
| 404 | Resource not found |
| 405 | Method not allowed |
| 429 | Rate limit exceeded |
| 500 | Internal server error |

### Wazuh Error Codes

| Code | Description | Resolution |
|---|---|---|
| 1000 | Wazuh Internal Error | Check manager logs |
| 1001 | Error in API call | Verify request parameters |
| 1002 | Resource not found | Confirm the resource exists |
| 1003 | Permission denied | Review RBAC roles and policies |
| 1017 | Invalid credentials | Verify username and password |
| 1760 | Agent already belongs to a group | Agent is already in the specified group |

### Error Handling in Python

```python
import requests

def safe_api_request(method: str, endpoint: str, **kwargs) -> dict:
    """Execute an API request with error handling."""
    try:
        result = api_request(method, endpoint, **kwargs)
        if result.get("error", 0) != 0:
            error_msg = result.get("message", "Unknown error")
            raise RuntimeError(f"Wazuh API error: {error_msg}")
        return result
    except requests.exceptions.ConnectionError:
        raise RuntimeError("Cannot connect to Wazuh API")
    except requests.exceptions.HTTPError as e:
        if e.response.status_code == 401:
            raise RuntimeError("Authentication failed - check credentials")
        elif e.response.status_code == 403:
            raise RuntimeError("Access denied - check RBAC permissions")
        raise
```

## Postman Collection

To test the API with Postman, set up a collection with the following structure.

### Environment Variables

```json
{
  "wazuh_url": "https://localhost:55000",
  "wazuh_user": "wazuh-wui",
  "wazuh_password": "YOUR_PASSWORD",
  "wazuh_token": ""
}
```

### Pre-request Script (automatic token refresh)

```javascript
const authUrl = pm.environment.get("wazuh_url") + "/security/user/authenticate?raw=true";

pm.sendRequest({
    url: authUrl,
    method: "POST",
    header: {
        "Authorization": "Basic " + btoa(
            pm.environment.get("wazuh_user") + ":" +
            pm.environment.get("wazuh_password")
        )
    }
}, function(err, response) {
    if (!err) {
        pm.environment.set("wazuh_token", response.text());
    }
});
```

### Recommended Collection Structure

```
Wazuh API v4.14/
├── Authentication/
│   └── POST Authenticate
├── Agents/
│   ├── GET List Agents
│   ├── GET Agent Details
│   ├── PUT Restart Agent
│   └── DELETE Remove Agents
├── Manager/
│   ├── GET Info
│   ├── GET Status
│   └── GET Logs
├── Rules/
│   ├── GET List Rules
│   ├── GET Rule Details
│   └── PUT Update Rules File
├── Decoders/
│   ├── GET List Decoders
│   └── PUT Update Decoders File
├── SCA/
│   ├── GET Policies
│   └── GET Checks
├── Vulnerability/
│   └── GET Agent Vulnerabilities
├── Syscollector/
│   ├── GET OS Info
│   ├── GET Packages
│   ├── GET Ports
│   └── GET Processes
└── Security/
    ├── GET Users
    ├── POST Create User
    ├── GET Roles
    └── POST Assign Role
```

## API Limits and Constraints

| Parameter | Value |
|---|---|
| Maximum `limit` | 100000 records |
| Default token lifetime | 900 seconds (15 minutes) |
| Rate limiting | Configurable in API settings |
| Maximum request body size | 10 MB |
| Concurrent connections | Server configuration dependent |

## Troubleshooting

### API Unreachable

1. Check the API daemon status:

```bash
/var/ossec/bin/wazuh-control status | grep wazuh-apid
```

2. Verify port 55000 is open:

```bash
ss -tlnp | grep 55000
```

3. Review API logs:

```bash
tail -f /var/ossec/logs/api.log
```

### 401 Authentication Error

- Confirm the user exists: `GET /security/users`
- Verify the password is correct
- Check that the token has not expired (default lifetime is 15 minutes)

### 403 Authorization Error

- Review assigned roles: `GET /security/users/{user_id}/roles`
- Confirm the RBAC policy permits the requested action
- For debugging, temporarily use the `wazuh` user with full permissions

### Slow API Responses

- Use `select` to limit returned fields
- Reduce `limit` for paginated requests
- Apply filters to narrow the result set
- Check the manager server load

For building custom integrations with the API, see the [Custom Integration Development](/docs/wazuh/development/wazuh-custom-integrations/) section. An overview of built-in integrations is available in the [Integrations](/docs/wazuh/integrations/) section.

