External Feed API
The External Feed API is a read-only REST API that allows MSSP partners, customer SOC teams, SOAR platforms, and external SIEMs to pull security data from RhythmX. API keys authenticate requests and control access scope — master keys see all entities, scoped keys see only their entity.
How It Works
flowchart LR
A["MSSP Partner<br>or Customer SOC"] -->|"X-API-Key header"| B["API Key<br>Authentication"]
B --> C{"Master Key?"}
C -->|"Yes (entity_name=*)"| D["All Entities<br>or filter by ?entity_name="]
C -->|"No (entity_name=CustomerA)"| E["CustomerA Only"]
D --> F["JSON Response<br><i>Paginated</i>"]
E --> F
style A fill:#4a148c,stroke:#9c27b0,color:#fff
style B fill:#b71c1c,stroke:#f05545,color:#fff
style C fill:#e65100,stroke:#ff9800,color:#fff
style D fill:#0d47a1,stroke:#42a5f5,color:#fff
style E fill:#0d47a1,stroke:#42a5f5,color:#fff
style F fill:#1b5e20,stroke:#4c8c4a,color:#fff
Base URL
https://<your-rhythmx-host>/api/v1/feed
All endpoints are prefixed with /api/v1/feed.
Authentication
Include your API key in the X-API-Key header with every request.
curl -H "X-API-Key: smk_your_api_key_here" \
https://rhythmx.example.com/api/v1/feed/health
Key Types
| Key Type | entity_name in DB |
Behavior |
|---|---|---|
| Master Key | * |
Sees all entities. Pass ?entity_name=X to filter, or omit for all. |
| Scoped Key | CustomerA |
Only sees CustomerA data. Cannot access other entities. |
Key Properties
- Non-retrievable — plaintext key shown only once at creation
- Revocable — can be disabled or deleted anytime
- Expirable — optional expiration date
- Rate-limited — 120 requests per minute per API key (configurable via
FEED_RATE_LIMITenv var)
Rate Limiting
All external feed endpoints are rate-limited per API key to prevent abuse:
| Setting | Default | Configurable |
|---|---|---|
| Requests per minute | 120 | FEED_RATE_LIMIT in .env.production |
| Scope | Per API key | Each key has its own limit |
| Response when exceeded | 429 Too Many Requests |
Includes Retry-After header |
Example error when rate limit is exceeded:
{
"error": "Rate limit exceeded",
"retry_after": 30
}
Common Parameters
These parameters are available on all list endpoints:
| Parameter | Type | Description |
|---|---|---|
entity_name |
string | Filter by entity (master keys only — scoped keys ignore this) |
since |
string | ISO 8601 timestamp — only return records created/updated after this time |
limit |
integer | Results per page (default: 50, max: 500) |
offset |
integer | Pagination offset (default: 0) |
Incremental Polling (since parameter)
The since parameter enables efficient incremental polling — consumers only pull data that has changed since their last request. Supported on all endpoints that return time-based data.
Accepted formats:
?since=2026-03-20T10:30:00Z (ISO 8601 with timezone)
?since=2026-03-20T10:30:00 (ISO 8601 without timezone — treated as UTC)
?since=2026-03-20 (date only — from midnight UTC)
Example — poll every 5 minutes for new alerts:
# First call — get everything from the last hour
curl -H "X-API-Key: smk_abc12345..." \
"https://rhythmx.example.com/api/v1/feed/alerts?since=2026-03-20T09:30:00Z"
# Subsequent calls — only get what's new since last poll
curl -H "X-API-Key: smk_abc12345..." \
"https://rhythmx.example.com/api/v1/feed/alerts?since=2026-03-20T09:35:00Z"
Endpoints supporting since:
| Endpoint | Time column filtered |
|---|---|
/incidents |
updated_at |
/cases |
updated_at |
/alerts |
system_time |
/alerts/stats |
system_time |
/risks/top-users |
system_time |
/risks/top-computers |
system_time |
/risks/top-rules |
system_time |
/mitre/tactics |
system_time |
/mitre/techniques |
system_time |
Response Format
All endpoints return this structure:
{
"success": true,
"data": [ ... ],
"pagination": {
"total": 150,
"limit": 50,
"offset": 0,
"has_more": true
},
"timestamp": "2026-03-20T10:30:00Z"
}
Endpoints
Health Check
GET /api/v1/feed/health
Returns the API service status.
Example:
curl -H "X-API-Key: smk_abc12345..." \
https://rhythmx.example.com/api/v1/feed/health
Response:
{
"status": "ok",
"service": "external_feed_api"
}
List Incidents
GET /api/v1/feed/incidents
Returns security incidents. Each incident represents a group of related alarms for an actor (user or computer).
Parameters:
| Parameter | Type | Description |
|---|---|---|
entity_name |
string | (Optional) Filter by entity/site. Master keys only — scoped keys ignore this. |
status |
string | OPEN, IN_PROGRESS, CLOSED, FALSE_POSITIVE |
since |
string | ISO 8601 — incidents updated after this time |
limit |
integer | Results per page (default: 50) |
offset |
integer | Pagination offset |
Example:
# All entities
curl -H "X-API-Key: smk_abc12345..." \
"https://rhythmx.example.com/api/v1/feed/incidents?status=OPEN&limit=20"
# Specific entity
curl -H "X-API-Key: smk_abc12345..." \
"https://rhythmx.example.com/api/v1/feed/incidents?entity_name=Primary%20Site&status=OPEN"
Response:
{
"success": true,
"data": [
{
"incident_id": "INC-a1b2c3d4",
"group_key": "jsmith",
"actor_type": "user",
"entity_name": "Primary Site",
"status": "OPEN",
"assigned_analyst": null,
"first_alarm_time": "2026-03-02T08:15:00Z",
"last_alarm_time": "2026-03-02T14:20:00Z",
"created_at": "2026-03-02T14:22:00Z",
"updated_at": "2026-03-02T14:22:00Z",
"closed_at": null,
"external_ticket_id": null,
"external_system": null
}
],
"pagination": {
"total": 12,
"limit": 20,
"offset": 0,
"has_more": false
},
"timestamp": "2026-03-20T10:30:00Z"
}
Get Incident Detail
GET /api/v1/feed/incidents/{incident_id}
Returns full details for a single incident including all fields.
Example:
curl -H "X-API-Key: smk_abc12345..." \
https://rhythmx.example.com/api/v1/feed/incidents/INC-a1b2c3d4
List Cases
GET /api/v1/feed/cases
Returns threat cases — correlated attack patterns detected by the analytics engine.
Parameters:
| Parameter | Type | Description |
|---|---|---|
entity_name |
string | (Optional) Filter by entity/site. Master keys only — scoped keys ignore this. |
status |
string | OPEN, IN_PROGRESS, CLOSED, FALSE_POSITIVE |
severity |
string | CRITICAL, HIGH, MEDIUM, LOW |
case_type |
string | e.g., LATERAL_MOVEMENT, RANSOMWARE_INDICATORS, BRUTE_FORCE, CREDENTIAL_THEFT, PERSISTENCE, PRIVILEGE_ESCALATION, RECONNAISSANCE |
since |
string | ISO 8601 — cases updated after this time |
limit |
integer | Results per page (default: 50) |
offset |
integer | Pagination offset |
Example:
curl -H "X-API-Key: smk_abc12345..." \
"https://rhythmx.example.com/api/v1/feed/cases?severity=CRITICAL&case_type=RANSOMWARE_INDICATORS"
Response:
{
"success": true,
"data": [
{
"case_id": "CASE-x1y2z3",
"entity_name": "Primary Site",
"case_type": "RANSOMWARE_INDICATORS",
"status": "OPEN",
"severity": "CRITICAL",
"primary_user": "admin",
"affected_computers": "DC01,WS-PC42",
"alert_count": 47,
"max_risk_score": 95,
"first_alert_time": "2026-03-19T03:10:00Z",
"last_alert_time": "2026-03-19T04:45:00Z",
"created_at": "2026-03-19T04:46:00Z",
"updated_at": "2026-03-19T04:46:00Z"
}
],
"pagination": {
"total": 3,
"limit": 50,
"offset": 0,
"has_more": false
},
"timestamp": "2026-03-20T10:30:00Z"
}
Get Case Detail
GET /api/v1/feed/cases/{case_id}
Returns full details for a single threat case.
Example:
curl -H "X-API-Key: smk_abc12345..." \
https://rhythmx.example.com/api/v1/feed/cases/CASE-x1y2z3
List Alerts
GET /api/v1/feed/alerts
Returns RhythmX detection alerts — individual rule matches from the detection engine.
Parameters:
| Parameter | Type | Description |
|---|---|---|
entity_name |
string | (Optional) Filter by entity/site. Master keys only — scoped keys ignore this. |
rule_level |
string | informational, low, medium, high, critical |
since |
string | ISO 8601 — alerts with system_time after this |
limit |
integer | Results per page (default: 50, max: 500) |
offset |
integer | Pagination offset |
Example:
curl -H "X-API-Key: smk_abc12345..." \
"https://rhythmx.example.com/api/v1/feed/alerts?rule_level=critical&limit=10"
Response:
{
"success": true,
"data": [
{
"id": 154832,
"title": "Mimikatz Command Line Usage",
"description": "Detects Mimikatz command line arguments",
"rule_level": "critical",
"tags": "attack.credential_access,attack.t1003",
"tactics": "credential_access",
"techniques": "T1003",
"computer_name": "DC01",
"user_id": "admin",
"ip_address": "10.0.5.42",
"entity_name": "Primary Site",
"system_time": "2026-03-19T14:22:00Z",
"risk": 95,
"image_path": "C:\\Windows\\Temp\\mimi.exe",
"command_line": "sekurlsa::logonpasswords",
"count": 1,
"first_seen": "2026-03-19T14:22:00Z",
"last_seen": "2026-03-19T14:22:00Z"
}
],
"pagination": {
"total": 5,
"limit": 10,
"offset": 0,
"has_more": false
},
"timestamp": "2026-03-20T10:30:00Z"
}
Get Alert Detail
GET /api/v1/feed/alerts/{alert_id}
Returns full details for a single alert including raw log data.
Alert Statistics
GET /api/v1/feed/alerts/stats
Returns aggregate alert statistics.
Parameters:
| Parameter | Type | Description |
|---|---|---|
entity_name |
string | (Optional) Filter by entity/site. Master keys only — scoped keys ignore this. |
Example:
curl -H "X-API-Key: smk_abc12345..." \
https://rhythmx.example.com/api/v1/feed/alerts/stats
Response:
{
"success": true,
"data": {
"total_alerts": 45832,
"by_level": {
"critical": 127,
"high": 1893,
"medium": 12450,
"low": 28100,
"informational": 3262
},
"by_entity": [
{ "entity_name": "Primary Site", "count": 28000 },
{ "entity_name": "Branch Office", "count": 17832 }
],
"top_rules": [
{ "title": "Remote Access Tool Execution", "rule_level": "high", "count": 4521 },
{ "title": "Suspicious PowerShell Command", "rule_level": "medium", "count": 3102 }
]
},
"timestamp": "2026-03-20T10:30:00Z"
}
SOC Metrics Overview
GET /api/v1/feed/metrics/overview
Returns high-level SOC metrics — total counts across incidents, cases, and alerts.
Parameters:
| Parameter | Type | Description |
|---|---|---|
entity_name |
string | (Optional) Filter by entity/site. Master keys only — scoped keys ignore this. |
Example:
curl -H "X-API-Key: smk_abc12345..." \
https://rhythmx.example.com/api/v1/feed/metrics/overview
Response:
{
"success": true,
"data": {
"total_incidents": 342,
"open_incidents": 28,
"in_progress_incidents": 12,
"total_cases": 89,
"open_cases": 15,
"critical_cases": 3,
"total_alerts": 45832,
"critical_alerts": 127,
"high_alerts": 1893
},
"timestamp": "2026-03-20T10:30:00Z"
}
Severity Breakdown
GET /api/v1/feed/metrics/severity
Returns incident and case counts broken down by status and severity.
Parameters:
| Parameter | Type | Description |
|---|---|---|
entity_name |
string | (Optional) Filter by entity/site. Master keys only — scoped keys ignore this. |
Response:
{
"success": true,
"data": {
"incidents_by_status": {
"OPEN": 28,
"IN_PROGRESS": 12,
"CLOSED": 285,
"FALSE_POSITIVE": 17
},
"cases_by_severity": {
"CRITICAL": 3,
"HIGH": 22,
"MEDIUM": 41,
"LOW": 23
},
"cases_by_type": {
"LATERAL_MOVEMENT": 12,
"BRUTE_FORCE": 18,
"CREDENTIAL_THEFT": 8,
"PERSISTENCE": 15,
"RANSOMWARE_INDICATORS": 3
}
},
"timestamp": "2026-03-20T10:30:00Z"
}
Mean Time to Respond (MTTR)
GET /api/v1/feed/metrics/mttr
Returns average time from incident creation to closure.
Parameters:
| Parameter | Type | Description |
|---|---|---|
entity_name |
string | (Optional) Filter by entity/site. Master keys only — scoped keys ignore this. |
Response:
{
"success": true,
"data": {
"overall_mttr_minutes": 142,
"closed_incidents": 285,
"by_status": {
"CLOSED": { "avg_minutes": 125, "count": 268 },
"FALSE_POSITIVE": { "avg_minutes": 45, "count": 17 }
}
},
"timestamp": "2026-03-20T10:30:00Z"
}
Trends
GET /api/v1/feed/metrics/trends
Returns daily incident and case creation counts over time.
Parameters:
| Parameter | Type | Description |
|---|---|---|
entity_name |
string | (Optional) Filter by entity/site. Master keys only — scoped keys ignore this. |
days |
integer | Number of days to look back (default: 30, max: 90) |
Example:
curl -H "X-API-Key: smk_abc12345..." \
"https://rhythmx.example.com/api/v1/feed/metrics/trends?days=7"
Response:
{
"success": true,
"data": {
"daily": [
{ "date": "2026-03-19", "incidents": 5, "cases": 2 },
{ "date": "2026-03-18", "incidents": 8, "cases": 3 },
{ "date": "2026-03-17", "incidents": 3, "cases": 1 },
{ "date": "2026-03-16", "incidents": 12, "cases": 4 },
{ "date": "2026-03-15", "incidents": 6, "cases": 2 },
{ "date": "2026-03-14", "incidents": 4, "cases": 1 },
{ "date": "2026-03-13", "incidents": 7, "cases": 3 }
]
},
"timestamp": "2026-03-20T10:30:00Z"
}
MITRE ATT&CK Tactics
GET /api/v1/feed/mitre/tactics
Returns alert counts grouped by MITRE ATT&CK tactic.
Parameters:
| Parameter | Type | Description |
|---|---|---|
entity_name |
string | (Optional) Filter by entity/site. Master keys only — scoped keys ignore this. |
limit |
integer | Results per page (default: 50, max: 500) |
offset |
integer | Pagination offset (default: 0) |
Response:
{
"success": true,
"data": [
{ "tactic": "credential_access", "count": 4521 },
{ "tactic": "lateral_movement", "count": 3102 },
{ "tactic": "execution", "count": 2890 },
{ "tactic": "persistence", "count": 2145 },
{ "tactic": "defense_evasion", "count": 1876 }
],
"pagination": {
"total": 11,
"limit": 50,
"offset": 0,
"has_more": false
},
"timestamp": "2026-03-20T10:30:00Z"
}
MITRE ATT&CK Techniques
GET /api/v1/feed/mitre/techniques
Returns alert counts grouped by MITRE ATT&CK technique.
Parameters:
| Parameter | Type | Description |
|---|---|---|
entity_name |
string | (Optional) Filter by entity/site. Master keys only — scoped keys ignore this. |
limit |
integer | Results per page (default: 50, max: 500) |
offset |
integer | Pagination offset (default: 0) |
Response:
{
"success": true,
"data": [
{ "technique": "T1003", "count": 2341 },
{ "technique": "T1059", "count": 1892 },
{ "technique": "T1021", "count": 1654 },
{ "technique": "T1053", "count": 1230 },
{ "technique": "T1078", "count": 987 }
],
"pagination": {
"total": 45,
"limit": 50,
"offset": 0,
"has_more": false
},
"timestamp": "2026-03-20T10:30:00Z"
}
List Entities
GET /api/v1/feed/entities
Returns all entities (sites/customers) with their incident, case, and alert counts.
Parameters:
| Parameter | Type | Description |
|---|---|---|
limit |
integer | Results per page (default: 50, max: 500) |
offset |
integer | Pagination offset (default: 0) |
Response:
{
"success": true,
"data": [
{
"entity_name": "Primary Site",
"incident_count": 215,
"case_count": 52,
"alert_count": 28000
},
{
"entity_name": "Branch Office",
"incident_count": 127,
"case_count": 37,
"alert_count": 17832
}
],
"pagination": {
"total": 2,
"limit": 50,
"offset": 0,
"has_more": false
},
"timestamp": "2026-03-20T10:30:00Z"
}
Entity Summary
GET /api/v1/feed/entities/{entity_name}/summary
Returns a detailed summary for a specific entity.
Example:
curl -H "X-API-Key: smk_abc12345..." \
"https://rhythmx.example.com/api/v1/feed/entities/Primary%20Site/summary"
Response:
{
"success": true,
"data": {
"entity_name": "Primary Site",
"incidents": {
"total": 215,
"open": 18,
"in_progress": 8,
"closed": 180,
"false_positive": 9
},
"cases": {
"total": 52,
"critical": 2,
"high": 12,
"medium": 25,
"low": 13
},
"alerts": {
"total": 28000,
"critical": 82,
"high": 1200
},
"top_rules": [
{ "title": "Remote Access Tool Execution", "count": 2800 },
{ "title": "Suspicious PowerShell Command", "count": 1950 }
],
"top_users": [
{ "user_id": "admin", "alert_count": 450, "total_risk": 12500 },
{ "user_id": "svc_backup", "alert_count": 320, "total_risk": 8900 }
],
"top_computers": [
{ "computer_name": "DC01", "alert_count": 890, "total_risk": 24000 },
{ "computer_name": "WS-PC42", "alert_count": 650, "total_risk": 18000 }
]
},
"timestamp": "2026-03-20T10:30:00Z"
}
Top Risky Users
GET /api/v1/feed/risks/top-users
Returns users with the highest cumulative risk scores.
Parameters:
| Parameter | Type | Description |
|---|---|---|
entity_name |
string | (Optional) Filter by entity/site. Master keys only — scoped keys ignore this. |
limit |
integer | Results per page (default: 50, max: 500) |
offset |
integer | Pagination offset (default: 0) |
Response:
{
"success": true,
"data": [
{ "user_id": "admin", "entity_name": "Primary Site", "total_risk": 12500, "alert_count": 450 },
{ "user_id": "svc_backup", "entity_name": "Primary Site", "total_risk": 8900, "alert_count": 320 },
{ "user_id": "jsmith", "entity_name": "Branch Office", "total_risk": 6200, "alert_count": 180 }
],
"pagination": {
"total": 85,
"limit": 50,
"offset": 0,
"has_more": true
},
"timestamp": "2026-03-20T10:30:00Z"
}
Top Risky Computers
GET /api/v1/feed/risks/top-computers
Returns computers with the highest cumulative risk scores.
Parameters:
| Parameter | Type | Description |
|---|---|---|
entity_name |
string | (Optional) Filter by entity/site. Master keys only — scoped keys ignore this. |
limit |
integer | Results per page (default: 50, max: 500) |
offset |
integer | Pagination offset (default: 0) |
Response:
{
"success": true,
"data": [
{ "computer_name": "DC01", "entity_name": "Primary Site", "total_risk": 24000, "alert_count": 890 },
{ "computer_name": "WS-PC42", "entity_name": "Primary Site", "total_risk": 18000, "alert_count": 650 },
{ "computer_name": "EXCH01", "entity_name": "Branch Office", "total_risk": 9500, "alert_count": 420 }
],
"pagination": {
"total": 42,
"limit": 50,
"offset": 0,
"has_more": false
},
"timestamp": "2026-03-20T10:30:00Z"
}
Top Triggered Rules
GET /api/v1/feed/risks/top-rules
Returns the most frequently triggered detection rules.
Parameters:
| Parameter | Type | Description |
|---|---|---|
entity_name |
string | (Optional) Filter by entity/site. Master keys only — scoped keys ignore this. |
limit |
integer | Results per page (default: 50, max: 500) |
offset |
integer | Pagination offset (default: 0) |
Response:
{
"success": true,
"data": [
{ "title": "Remote Access Tool Execution", "rule_level": "high", "count": 4521, "description": "Detects execution of known remote access tools" },
{ "title": "Suspicious PowerShell Command", "rule_level": "medium", "count": 3102, "description": "Detects suspicious PowerShell command line patterns" },
{ "title": "Mimikatz Command Line Usage", "rule_level": "critical", "count": 127, "description": "Detects Mimikatz command line arguments" }
],
"pagination": {
"total": 156,
"limit": 50,
"offset": 0,
"has_more": true
},
"timestamp": "2026-03-20T10:30:00Z"
}
Entity Filtering (Master Keys)
Master keys (entity_name=*) can filter by entity on any endpoint:
# All entities
curl -H "X-API-Key: smk_master_key..." \
"https://rhythmx.example.com/api/v1/feed/incidents"
# Specific entity
curl -H "X-API-Key: smk_master_key..." \
"https://rhythmx.example.com/api/v1/feed/incidents?entity_name=Primary%20Site"
# Scoped keys ignore the entity_name parameter
curl -H "X-API-Key: smk_customer_key..." \
"https://rhythmx.example.com/api/v1/feed/incidents"
# ^ Always returns only that customer's data
Rate Limiting
API keys have a configurable rate limit (default: 60 requests per minute). When exceeded, the API returns 429 Too Many Requests.
Error Codes
| Code | Meaning |
|---|---|
200 |
Success |
400 |
Bad request (missing required parameter) |
401 |
Invalid, expired, or disabled API key |
404 |
Resource not found |
429 |
Rate limit exceeded |
500 |
Internal server error |
Error Response:
{
"error": "Invalid or disabled API key"
}
Quick Reference
| Endpoint | Method | Description |
|---|---|---|
/api/v1/feed/health |
GET | Service health check |
/api/v1/feed/incidents |
GET | List incidents |
/api/v1/feed/incidents/{id} |
GET | Incident detail |
/api/v1/feed/cases |
GET | List threat cases |
/api/v1/feed/cases/{id} |
GET | Case detail |
/api/v1/feed/alerts |
GET | List RhythmX alerts |
/api/v1/feed/alerts/{id} |
GET | Alert detail |
/api/v1/feed/alerts/stats |
GET | Alert statistics |
/api/v1/feed/metrics/overview |
GET | SOC overview metrics |
/api/v1/feed/metrics/severity |
GET | Severity/status breakdown |
/api/v1/feed/metrics/mttr |
GET | Mean time to respond |
/api/v1/feed/metrics/trends |
GET | Daily incident/case trends |
/api/v1/feed/mitre/tactics |
GET | MITRE ATT&CK tactics |
/api/v1/feed/mitre/techniques |
GET | MITRE ATT&CK techniques |
/api/v1/feed/entities |
GET | List entities with counts |
/api/v1/feed/entities/{name}/summary |
GET | Entity detail summary |
/api/v1/feed/risks/top-users |
GET | Top risky users |
/api/v1/feed/risks/top-computers |
GET | Top risky computers |
/api/v1/feed/risks/top-rules |
GET | Top triggered rules |
API Key Management
API keys are managed by administrators through the Integration Admin interface in System Settings.
| Field | Description |
|---|---|
| Label | Human-readable label for the key |
| Description | Purpose of the key |
| Entity Name | Entity to scope to, or * for master key |
| Scopes | Permissions granted (default: all read scopes) |
| Rate Limit | Requests per minute (default: 60) |
| Expires At | Optional expiration date |
| Enabled | Whether the key is active |