Wazuh REST API 4.14 - Complete Reference Guide
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:
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:
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:
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
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 |
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/agents?offset=0&limit=10"Filtering
The API supports filtering via query parameters:
# 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:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/agents?search=web-server"Sorting
The sort parameter controls result ordering:
# 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:
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:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/agents?status=active&limit=5" | jq '.data.affected_items[] | {id, name, status}'Response:
{
"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:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/agents/001" | jq '.data.affected_items[0]'DELETE /agents
Remove agents (supports bulk deletion):
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:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
-X PUT "https://localhost:55000/agents/001/restart"PUT /agents/group/{group_id}
Assign agents to a group:
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
# 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:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/manager/info" | jq '.data.affected_items[0]'GET /manager/status
Status of all Wazuh daemons:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/manager/status" | jq '.data.affected_items[0]'GET /manager/configuration
Current manager configuration:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/manager/configuration?section=global"GET /manager/logs
Manager logs:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/manager/logs?limit=20&sort=-timestamp"GET /manager/stats
Event processing statistics:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/manager/stats?date=$(date +%Y-%m-%d)"Endpoints: Cluster
GET /cluster/status
Cluster status:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/cluster/status"GET /cluster/nodes
List cluster nodes:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/cluster/nodes" | jq '.data.affected_items[] | {name, type, version}'GET /cluster/healthcheck
Cluster health check:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/cluster/healthcheck"GET /cluster/{node_id}/info
Specific node information:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/cluster/node01/info"Endpoints: Rules
GET /rules
List rules:
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:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/rules/5710"GET /rules/groups
List rule groups:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/rules/groups"GET /rules/files
List rule files:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/rules/files?status=custom"PUT /rules/files/{filename}
Update a custom rule file:
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.xmlEndpoints: Decoders
GET /decoders
List decoders:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/decoders?limit=10&search=sshd"GET /decoders/{decoder_name}
Specific decoder information:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/decoders/sshd"GET /decoders/files
List decoder files:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/decoders/files?status=custom"PUT /decoders/files/{filename}
Update a custom decoder file:
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.xmlEndpoints: SCA (Security Configuration Assessment)
GET /sca/{agent_id}
SCA results for an agent:
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:
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
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 reportEndpoints: Vulnerabilities
GET /vulnerability/{agent_id}
Detected vulnerabilities on an agent:
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:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/vulnerability/001/summary/severity"Python SDK - Vulnerability Report
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 summaryEndpoints: Syscollector (System Inventory)
GET /syscollector/{agent_id}/os
Operating system information:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/syscollector/001/os"GET /syscollector/{agent_id}/packages
Installed packages:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/syscollector/001/packages?limit=20&sort=-size"GET /syscollector/{agent_id}/ports
Open ports:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/syscollector/001/ports?state=listening"GET /syscollector/{agent_id}/processes
Running processes:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/syscollector/001/processes?limit=20&sort=-resident_size"GET /syscollector/{agent_id}/netiface
Network interfaces:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/syscollector/001/netiface"GET /syscollector/{agent_id}/hardware
Hardware information:
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:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/security/users"POST /security/users
Create a user:
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:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
"https://localhost:55000/security/roles"POST /security/roles
Create a role:
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:
curl -sk -H "Authorization: Bearer ${TOKEN}" \
-X POST "https://localhost:55000/security/user/100/roles?role_ids=2"GET /security/policies
List RBAC policies:
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
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")
raisePostman Collection
To test the API with Postman, set up a collection with the following structure.
Environment Variables
{
"wazuh_url": "https://localhost:55000",
"wazuh_user": "wazuh-wui",
"wazuh_password": "YOUR_PASSWORD",
"wazuh_token": ""
}Pre-request Script (automatic token refresh)
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 RoleAPI 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
- Check the API daemon status:
/var/ossec/bin/wazuh-control status | grep wazuh-apid- Verify port 55000 is open:
ss -tlnp | grep 55000- Review API logs:
tail -f /var/ossec/logs/api.log401 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
wazuhuser with full permissions
Slow API Responses
- Use
selectto limit returned fields - Reduce
limitfor 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 section. An overview of built-in integrations is available in the Integrations section.