Skip to content

API Reference

Complete REST API reference for integrating with RhythmX. All endpoints are served from https://<RHYTHMX_HOST>/api/.


Authentication

RhythmX uses two authentication methods depending on the endpoint type:

Method Usage Header
JWT Token Dashboard & admin endpoints Authorization: Bearer <token>
API Key External feed endpoints X-API-Key: smk_<key>
None Health endpoints, webhooks No authentication required

Obtaining a JWT Token

POST /api/login
Content-Type: application/json

{
  "username": "analyst@domain.local",
  "password": "password"
}

Response:

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "user": {
    "username": "analyst@domain.local",
    "role": "admin"
  }
}

Use the access_token in subsequent requests:

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...

Incidents API

Manage security incidents — create, update status, assign analysts, link external tickets.

List Incidents

GET /api/incidents

Query Parameters:

Parameter Type Default Description
status string Filter: OPEN, IN_PROGRESS, CLOSED, FALSE_POSITIVE
entity string Filter by entity name
analyst string Filter by assigned analyst
search string Free-text search on actor key or entity name
sort_by string status-priority Sort: last_alarm_time, created_at, risk_score
since string ISO 8601 timestamp — only incidents created after this time
updated_since string ISO 8601 timestamp — only incidents updated after this time
limit integer 100 Results per page (max 500)
offset integer 0 Pagination offset

Example — SOAR polling for new incidents:

GET /api/incidents?since=2026-03-13T00:00:00Z&status=OPEN&limit=50

Example — fetch recently updated incidents:

GET /api/incidents?updated_since=2026-03-13T03:00:00Z

Response:

{
  "success": true,
  "incidents": [
    {
      "incident_id": "INC-7601d999",
      "group_key": "jsmith",
      "actor_type": "user",
      "entity_name": "Primary Site",
      "status": "OPEN",
      "assigned_analyst": null,
      "first_alarm_time": "2026-03-12T18:26:28",
      "last_alarm_time": "2026-03-13T03:49:20",
      "created_at": "2026-03-12T18:26:28",
      "updated_at": "2026-03-13T03:49:20",
      "closed_at": null,
      "external_ticket_id": null,
      "external_ticket_url": null,
      "external_system": null,
      "investigation_notes": null,
      "resolution_notes": null,
      "risk_score": 82,
      "risk_level": "critical",
      "alarm_count": 156,
      "alarm_count_24h": 23,
      "alarm_count_7d": 89,
      "sigma_alert_count": 47,
      "threat_case_count": 3
    }
  ],
  "total": 12,
  "limit": 50,
  "offset": 0,
  "has_more": false
}


Get Incident Detail

GET /api/incidents/{incident_id}

Response:

{
  "success": true,
  "incident": {
    "incident_id": "INC-7601d999",
    "group_key": "jsmith",
    "actor_type": "user",
    "entity_name": "Primary Site",
    "status": "OPEN",
    "assigned_analyst": "analyst1",
    "investigation_notes": "Investigating lateral movement pattern",
    "resolution_notes": null,
    "external_ticket_id": "SEC-1234",
    "external_ticket_url": "https://jira.example.com/browse/SEC-1234",
    "external_system": "jira",
    "first_alarm_time": "2026-03-12T18:26:28",
    "last_alarm_time": "2026-03-13T03:49:20",
    "created_at": "2026-03-12T18:26:28",
    "updated_at": "2026-03-13T03:49:20",
    "closed_at": null
  }
}


Update Incident (General)

PATCH /api/incidents/{incident_id}
Content-Type: application/json

{
  "status": "IN_PROGRESS",
  "assigned_analyst": "analyst1",
  "investigation_notes": "Reviewing related threat cases",
  "resolution_notes": null,
  "external_ticket_id": "SEC-1234",
  "external_ticket_url": "https://jira.example.com/browse/SEC-1234",
  "external_system": "jira"
}

All fields are optional — include only the fields you want to update.


Update Incident Status

PATCH /api/incidents/{incident_id}/status
Content-Type: application/json

{
  "status": "CLOSED",
  "notes": "Resolved — confirmed benign admin activity"
}

Valid statuses: OPEN, IN_PROGRESS, CLOSED, FALSE_POSITIVE


Assign Incident

PATCH /api/incidents/{incident_id}/assign
Content-Type: application/json

{
  "analyst": "john.doe"
}

Update Incident Notes

PATCH /api/incidents/{incident_id}/notes
Content-Type: application/json

{
  "investigation_notes": "Checked LDAP logs — confirmed password spray from external IP",
  "resolution_notes": "Account locked, IP blocked at firewall"
}

PATCH /api/incidents/{incident_id}/external-ticket
Content-Type: application/json

{
  "ticket_id": "SEC-1234",
  "ticket_url": "https://jira.example.com/browse/SEC-1234",
  "system": "jira"
}

Bulk Status Update

PATCH /api/incidents/bulk-status
Content-Type: application/json

{
  "incident_ids": ["INC-7601d999", "INC-3e08d543", "INC-8b5d98b0"],
  "status": "CLOSED"
}

Promote Actor to Incident

Manually create an incident for an actor that doesn't meet auto-creation thresholds. Idempotent — returns existing incident if already created.

POST /api/incidents/promote
Content-Type: application/json

{
  "group_key": "john.doe",
  "actor_type": "user",
  "entity_name": "Primary Site",
  "first_alarm": "2026-02-25T10:00:00",
  "last_alarm": "2026-02-26T14:30:00"
}

Response (201 Created):

{
  "success": true,
  "incident": { "incident_id": "INC-a1b2c3d4", "..." : "..." },
  "created": true,
  "message": "Incident created for john.doe"
}


Get Incident History

Returns the audit trail of all changes (status changes, assignments, notes).

GET /api/incidents/{incident_id}/history

Response:

{
  "success": true,
  "history": [
    {
      "id": 1,
      "incident_id": "INC-7601d999",
      "field_changed": "status",
      "old_value": "OPEN",
      "new_value": "IN_PROGRESS",
      "changed_by": "analyst1",
      "changed_at": "2026-03-13T04:15:00",
      "notes": "Starting investigation"
    }
  ]
}


Incident Statistics

GET /api/incidents/stats?entity=Primary%20Site

Response:

{
  "success": true,
  "stats": {
    "total": 45,
    "OPEN": 12,
    "IN_PROGRESS": 8,
    "CLOSED": 20,
    "FALSE_POSITIVE": 5
  }
}


Cases API

Manage threat cases from the correlation engine (23 use cases).

List Active Cases

GET /api/cases/active?limit=50&entity_name=Primary%20Site

Query Parameters:

Parameter Type Default Description
page integer 1 Page number
limit integer 50 Results per page (max 500)
entity_name string Filter by entity

Response:

{
  "success": true,
  "cases": [
    {
      "case_id": "CASE-abc123",
      "entity_name": "Primary Site",
      "case_type": "lateral_movement",
      "status": "OPEN",
      "severity": "CRITICAL",
      "primary_user": "jsmith",
      "affected_computers": ["WS-101", "WS-102", "DC-01"],
      "alert_count": 47,
      "max_risk_score": 85,
      "first_alert_time": "2026-03-12T14:00:00",
      "last_alert_time": "2026-03-13T02:30:00",
      "created_at": "2026-03-12T14:05:00"
    }
  ],
  "pagination": {
    "total_records": 11,
    "total_pages": 1,
    "current_page": 1,
    "per_page": 50,
    "has_next": false,
    "has_previous": false
  }
}


Get Case Detail

GET /api/cases/{case_id}

Returns full case with alerts, risk breakdown, and MITRE coverage.


Search Cases

GET /api/cases/search?severity=CRITICAL&status=OPEN&case_type=lateral_movement&entity_name=Primary%20Site&limit=100

Query Parameters:

Parameter Type Description
status string OPEN, IN_PROGRESS, CLOSED
severity string CRITICAL, HIGH, MEDIUM, LOW
case_type string Correlation type (e.g., lateral_movement, password_spraying, ransomware_indicators)
entity_name string Filter by entity
assigned_analyst string Filter by analyst
page integer Page number (default 1)
limit integer Results per page (default 100)

Case Statistics

GET /api/cases/statistics?entity_name=Primary%20Site&timeframe=30d

Timeframe options: 1d, 7d, 30d, 90d, 180d, 365d, all

Response:

{
  "success": true,
  "summary": {
    "total": 45,
    "open": 11,
    "in_progress": 5,
    "closed": 29
  },
  "severity_breakdown": {
    "CRITICAL": 8,
    "HIGH": 15,
    "MEDIUM": 18,
    "LOW": 4
  },
  "entity_breakdown": [
    { "entity_name": "Primary Site", "count": 30 },
    { "entity_name": "Branch Office", "count": 15 }
  ]
}


Update Case Status

PUT /api/cases/{case_id}/status
Content-Type: application/json

{
  "status": "CLOSED",
  "assigned_analyst": "analyst1",
  "resolution_notes": "Confirmed benign admin activity"
}

Bulk Close Cases

PUT /api/cases/bulk-status
Content-Type: application/json

{
  "case_ids": ["CASE-abc123", "CASE-def456"],
  "status": "CLOSED",
  "notes": "Bulk close after review"
}

Trigger Correlation

Manually trigger the correlation engine (normally runs every 30 minutes).

POST /api/cases/correlate

Case Types

GET /api/cases/types

Returns all available correlation types with counts.


Export Cases

GET /api/cases/export?format=csv&entity_name=Primary%20Site&status=OPEN

Exports cases as CSV or JSON file download.


Ticket Integration API

Push incidents to Jira and ServiceNow.

Configuration

GET  /api/integrations/jira/config          — Get Jira configuration
PUT  /api/integrations/jira/config          — Update Jira configuration
POST /api/integrations/jira/test            — Test Jira connection
GET  /api/integrations/servicenow/config    — Get ServiceNow configuration
PUT  /api/integrations/servicenow/config    — Update ServiceNow configuration
POST /api/integrations/servicenow/test      — Test ServiceNow connection
GET  /api/integrations/status               — Get status of all integrations

Create Ticket

POST /api/incidents/{incident_id}/create-ticket
Content-Type: application/json

{
  "system": "jira",
  "incident_data": {
    "incidentId": "INC-7601d999",
    "groupKey": "jsmith",
    "actorType": "user",
    "entityName": "Primary Site",
    "riskScore": 82,
    "riskLevel": "critical",
    "severity": "Critical",
    "alarmCount": 156,
    "threatCaseCount": 3,
    "uniqueRules": ["Lateral Movement", "Credential Theft"],
    "firstAlarm": "2026-03-12T18:26:28",
    "lastAlarm": "2026-03-13T03:49:20",
    "mitreTactics": ["Lateral Movement", "Credential Access"],
    "mitreTechniques": ["T1021", "T1003"],
    "investigationNotes": "Active investigation"
  }
}

Response:

{
  "success": true,
  "ticket_id": "SEC-1234",
  "ticket_url": "https://jira.example.com/browse/SEC-1234",
  "system": "jira"
}

Preview Ticket

POST /api/incidents/{incident_id}/preview-ticket
Content-Type: application/json

{
  "incident_data": { "..." : "same fields as create" }
}

Returns the ticket summary, description, and priority mappings without creating.


Webhooks (Inbound)

Receive status updates from external ticketing systems. No authentication required — these endpoints are called by Jira/ServiceNow.

POST /api/webhooks/jira           — Receive Jira issue updates
POST /api/webhooks/servicenow     — Receive ServiceNow incident updates
GET  /api/webhooks/config         — Get webhook setup instructions

Jira Status Mapping:

Jira Status RhythmX Status
Open, To Do, New, Backlog OPEN
In Progress, Investigating IN_PROGRESS
Done, Closed, Resolved CLOSED
Won't Do, False Positive FALSE_POSITIVE

ServiceNow State Mapping:

ServiceNow State RhythmX Status
1 (New) OPEN
2-5 (In Progress, On Hold, Awaiting) IN_PROGRESS
6-7 (Resolved, Closed) CLOSED
8 (Canceled) FALSE_POSITIVE

False Positives API

Manage false positive rules that suppress matching alerts.

CRUD Operations

GET    /api/false-positives              — List all FP rules
POST   /api/false-positives              — Create FP rule
GET    /api/false-positives/{rule_id}    — Get single rule
PUT    /api/false-positives/{rule_id}    — Update rule
DELETE /api/false-positives/{rule_id}    — Delete rule

Create FP Rule

POST /api/false-positives
Content-Type: application/json

{
  "created_by": "analyst1",
  "fp_rulename": "Benign Admin RDP",
  "title": "Admin RDP sessions from jump server",
  "description": "Suppress RDP alerts from 10.0.0.50 to domain controllers",
  "computer_name": "DC-01",
  "ip_address": "10.0.0.50",
  "expiration_days": "90"
}

Preview Matching Alerts

Preview which alerts would be suppressed before creating the rule.

POST /api/false-positives/preview
Content-Type: application/json

{
  "rule_data": {
    "computer_name": "DC-01",
    "ip_address": "10.0.0.50"
  }
}

Delete Matching Alerts

Permanently delete all alerts that match a specific FP rule.

DELETE /api/false-positives/{rule_id}/delete-matches

Audit Log API

Query the activity audit trail. Admin role required.

Query Audit Logs

GET /api/audit/logs?category=AUTH,INCIDENT&username=analyst1&start_date=2026-03-01&limit=100

Query Parameters:

Parameter Type Description
category string Comma-separated: AUTH, INCIDENT, HUNT, INVESTIGATION, CASE, ALARM, CONFIG, USER_MGMT, FALSE_POSITIVE, EXPORT, ADMIN
action string Specific action (e.g., LOGIN_SUCCESS, STATUS_CHANGE)
username string Filter by username
resource_type string Filter by resource type
success string true or false
start_date string ISO date or YYYY-MM-DD
end_date string ISO date or YYYY-MM-DD
search string Free-text search in details
sort string timestamp, username, category, action
order string asc or desc
limit integer Max 1000 (default 100)
offset integer Pagination offset

Response:

{
  "success": true,
  "logs": [
    {
      "id": 1234,
      "timestamp": "2026-03-13T04:15:00.123",
      "username": "analyst1",
      "user_role": "admin",
      "category": "INCIDENT",
      "action": "STATUS_CHANGE",
      "resource_type": "incident",
      "resource_id": "INC-7601d999",
      "resource_name": "jsmith",
      "details": {
        "new_status": "IN_PROGRESS",
        "notes": "Starting investigation"
      },
      "success": true,
      "duration_ms": 45,
      "result_count": null
    }
  ],
  "total": 1500,
  "limit": 100,
  "offset": 0,
  "has_more": true
}

Audit Statistics

GET /api/audit/stats?days=7

Returns summary counts, activity by category, by user, by action, hourly/daily trends, and failed actions.

User Activity

GET /api/audit/user/{username}?days=7&limit=100

Export Audit Logs

GET /api/audit/export?format=csv&category=AUTH&start_date=2026-03-01

Downloads CSV or JSON file.

List Categories

GET /api/audit/categories

External Feed API

Read-only API for SOAR platforms and external SIEMs. Uses API key authentication — not JWT.

Full documentation: External Feed API

Endpoints

GET  /api/v1/feed/health                    — Health check (no auth)
GET  /api/v1/feed/incidents                 — List incidents
GET  /api/v1/feed/incidents/{incident_id}   — Get incident detail
GET  /api/v1/feed/cases                     — List cases
GET  /api/v1/feed/cases/{case_id}           — Get case detail

Authentication: X-API-Key: smk_your_key_here

Rate Limit: 60 requests/minute per key (configurable)


Health API

System health monitoring. No authentication required.

Endpoints

GET /api/health/summary      — Quick overview for dashboard
GET /api/health/logstash     — Detection pipeline metrics & EPS
GET /api/health/system       — CPU, memory, disk, load average
GET /api/health/services     — All systemd service statuses
GET /api/health/database     — MySQL connections, table sizes, retention
GET /api/health/storage      — Disk usage for log directories

Health Summary

GET /api/health/summary

Response:

{
  "overall_status": "healthy",
  "logstash": {
    "status": "running",
    "eps_current": 22000,
    "total_events": 1250000000,
    "last_received": "2026-03-13T04:30:00Z"
  },
  "system": {
    "cpu_percent": 35.2,
    "memory_percent": 62.1,
    "load_1m": 4.5
  },
  "services": {
    "critical_down": 0,
    "down_list": []
  },
  "disk": {
    "root_used_percent": 45.3
  },
  "database": {
    "status": "connected",
    "alert_count": 15000000
  }
}


Integration Configuration API

Configure platform integrations. Admin role required.

Syslog Forwarding (Alerts)

GET  /api/integrations-config/syslog          — Get alert syslog config
PUT  /api/integrations-config/syslog          — Update config & restart service
POST /api/integrations-config/syslog/test     — Test syslog connection
GET  /api/integrations-config/syslog/status   — Service status & health

Incident/Case Syslog Forwarding

GET  /api/integrations-config/incident-syslog          — Get incident syslog config
PUT  /api/integrations-config/incident-syslog          — Update config & restart service
POST /api/integrations-config/incident-syslog/test     — Test connection
GET  /api/integrations-config/incident-syslog/status   — Service status & health

PUT Body:

{
  "host": "192.168.1.50",
  "port": 514,
  "protocol": "tcp",
  "hostname": "RhythmX",
  "poll_interval": 60
}

LogRhythm SQL Server

GET  /api/integrations-config/logrhythm-sql          — Get configuration
PUT  /api/integrations-config/logrhythm-sql          — Update & restart services
POST /api/integrations-config/logrhythm-sql/test     — Test SQL connection
GET  /api/integrations-config/logrhythm-sql/status   — Connection & sync status

Error Responses

All endpoints return consistent error format:

{
  "success": false,
  "error": "Description of what went wrong"
}

HTTP Status Codes:

Code Meaning
200 Success
201 Created (promote incident)
400 Bad request (missing/invalid parameters)
401 Unauthorized (invalid or expired token/key)
403 Forbidden (insufficient role)
404 Resource not found
429 Rate limit exceeded (external feed API)
500 Internal server error

Incremental Polling (SOAR Integration)

For SOAR platforms that poll RhythmX on a schedule, use timestamp-based filtering to fetch only new or changed data:

Polling for New Incidents

GET /api/incidents?since=2026-03-13T00:00:00Z&status=OPEN&limit=100
  1. On first poll, omit since to get all current incidents
  2. Record the created_at of the most recent incident
  3. On subsequent polls, pass that timestamp as since

Polling for Updated Incidents

GET /api/incidents?updated_since=2026-03-13T03:00:00Z

Use updated_since to detect status changes, analyst assignments, and note updates since last poll.

Polling via External Feed API

The External Feed API offers the same capability with API key auth:

GET /api/v1/feed/incidents?since=2026-03-13T00:00:00Z&status=OPEN
X-API-Key: smk_your_key_here

See External Feed API for full details.