Projects and nested resources
/platform/projects/* group — projects and every nested resource (workspaces, cases, reviews, versions, members, audit, quality, impact).
Every endpoint requires an organization context and the user/key must have permission on the specific project — accessing another organization's project returns 404.
Summary table (per block)
Dashboard and CRUD
| Method | Path | Permission |
|---|---|---|
| GET | /platform/dashboard | project:view |
| GET | /platform/projects | project:view |
| POST | /platform/projects | project:create |
| GET | /platform/projects/{project_id} | project:view |
| PATCH | /platform/projects/{project_id} | project:edit |
| GET | /platform/projects/{project_id}/overview | project:view |
| GET | /platform/projects/{project_id}/report | project:view |
| POST | /platform/projects/{project_id}/impact/{workspace_id} | project:view |
Content (project rules and decoders)
| Method | Path | Permission |
|---|---|---|
| GET | /platform/projects/{project_id}/rules | project:view |
| GET | /platform/projects/{project_id}/decoders | project:view |
Quality
| Method | Path | Permission |
|---|---|---|
| GET | /platform/projects/{project_id}/quality-gate | project:view |
| PATCH | /platform/projects/{project_id}/quality-gate | project:edit |
Test cases
| Method | Path | Permission |
|---|---|---|
| GET | /platform/projects/{project_id}/cases | project:view |
| POST | /platform/projects/{project_id}/cases | case:edit |
| PATCH | /platform/projects/{project_id}/cases/{case_id} | case:edit |
| DELETE | /platform/projects/{project_id}/cases/{case_id} | case:edit |
| POST | /platform/projects/{project_id}/cases/run | case:run |
| POST | /platform/projects/{project_id}/cases/{case_id}/run | case:run |
Workspaces (editable snapshots)
| Method | Path | Permission |
|---|---|---|
| GET | /platform/projects/{project_id}/workspaces | project:view |
| POST | /platform/projects/{project_id}/workspaces | workspace:create |
| GET | /platform/projects/{project_id}/workspaces/{workspace_id} | project:view |
| PATCH | /platform/projects/{project_id}/workspaces/{workspace_id} | workspace:create |
Reviews
| Method | Path | Permission |
|---|---|---|
| GET | /platform/projects/{project_id}/reviews | project:view |
| POST | /platform/projects/{project_id}/reviews | review:create |
| PATCH | /platform/projects/{project_id}/reviews/{review_id} | review:approve |
| GET | /platform/projects/{project_id}/reviews/{review_id}/comments | project:view |
| POST | /platform/projects/{project_id}/reviews/{review_id}/comments | review:comment |
Versions
| Method | Path | Permission |
|---|---|---|
| GET | /platform/projects/{project_id}/versions | project:view |
| POST | /platform/projects/{project_id}/versions | version:create |
| POST | /platform/projects/{project_id}/versions/{version_id}/publish | version:publish |
| POST | /platform/projects/{project_id}/versions/{version_id}/restore | version:publish |
Members
| Method | Path | Permission |
|---|---|---|
| GET | /platform/projects/{project_id}/members | project:view |
| POST | /platform/projects/{project_id}/members | member:manage |
| POST | /platform/projects/{project_id}/members/assign | member:manage |
Audit
| Method | Path | Permission |
|---|---|---|
| GET | /platform/audit | audit:view |
| GET | /platform/projects/{project_id}/audit | audit:view |
Git integrations
| Method | Path | Permission |
|---|---|---|
| GET | /platform/projects/{project_id}/git-bindings | project:view |
More Git bindings detail in Organization endpoints.
Projects
GET /platform/projects
Lists projects of the active organization.
Response 200: array of ProjectRecord.
[
{
"id": "prj_01H…",
"slug": "edge-rules",
"name": "Edge rules",
"description": "Edge team rules",
"decoders_xml": "<decoders>…</decoders>",
"rules_xml": "<group name=\"custom\">…</group>",
"default_log_format": "syslog",
"include_disk_defaults": true,
"include_disk_custom": true,
"active_baseline_id": "base_01H…",
"active_baseline_name": "baseline-4.10",
"case_count": 12,
"workspace_count": 3,
"created_at": "2026-01-15T10:00:00Z",
"updated_at": "2026-04-24T14:00:00Z"
}
]
POST /platform/projects
Creates a new project.
Request body (ProjectCreateRequest):
{
"name": "Edge rules",
"description": "Custom rules for the edge team",
"decoders_xml": "<decoders>\n</decoders>",
"rules_xml": "<group name=\"custom\">\n</group>",
"default_log_format": "syslog",
"include_disk_defaults": true,
"include_disk_custom": true,
"active_baseline_id": null
}
Validations:
name— 1–120 chars.description— 0–2000 chars.decoders_xml,rules_xml— up to 2 MB each.default_log_format—auto,syslog,json,eventchannel,plain.
Response 200: ProjectRecord.
GET /platform/projects/{project_id}
Fetches a specific project.
Response 200: ProjectRecord.
PATCH /platform/projects/{project_id}
Partial update. Send only the fields to change.
Request body (ProjectUpdateRequest) — all fields optional.
Response 200: ProjectRecord.
GET /platform/projects/{project_id}/overview
Consolidated panel: quality score, policy, semantic counts, versions and recent audit.
Response 200 (ProjectOverviewResponse):
{
"project": { "...": "ProjectRecord" },
"quality_score": 87,
"quality_gate_policy": { "...": "QualityGatePolicyRecord" },
"quality_gate_result": { "passed": true, "...": "..." },
"semantic_counts": {
"total_rules": 120, "total_decoders": 45,
"root_decoders": 12, "terminal_decoders": 33,
"correlation_rules": 8, "mitre_tagged_rules": 45,
"...": "..."
},
"recent_versions": [ "ProjectVersionRecord[]" ],
"recent_audit": [ "AuditEventRecord[]" ],
"diagnostics_by_severity": {"error": 0, "warning": 3, "info": 12},
"diagnostics_by_code": {"rule_overlap": 2, "decoder_unused": 1}
}
GET /platform/projects/{project_id}/report
Full report for export: validation + regression + scores.
Response 200: ProjectReportResponse.
POST /platform/projects/{project_id}/impact/{workspace_id}
Compares the current project state against a workspace's content (publish candidate). Returns per-case diffs.
Response 200 (ProjectImpactResponse):
{
"project": { "...": "ProjectRecord" },
"workspace": { "...": "WorkspaceRecord" },
"current_quality_score": 85,
"candidate_quality_score": 92,
"current_diagnostics_by_severity": {"error": 2, "warning": 5},
"candidate_diagnostics_by_severity": {"error": 0, "warning": 3},
"changed_cases": 4,
"improved_cases": 3,
"regressed_cases": 1,
"unchanged_cases": 15,
"cases": [
{
"case_id": "case_...",
"case_name": "SSH brute force",
"before_passed": false,
"after_passed": true,
"change_type": "improved",
"...": "..."
}
]
}
Content
GET /platform/projects/{project_id}/rules
Lists the project's rules (with metadata).
Response 200: array of RuleCatalogItem:
{
"rule_id": "100010",
"level": 5,
"description": "Suspicious login attempt",
"groups": ["authentication_failed", "local"],
"decoded_as": "sshd",
"source_file": "local_rules.xml",
"source_line": 15,
"dependency_count": 0,
"dependent_rule_count": 2,
"field_matcher_count": 3,
"uses_frequency": false,
"uses_correlation": false,
"noalert": false,
"mitre_ids": ["T1110"]
}
GET /platform/projects/{project_id}/decoders
Lists the project's decoders.
Response 200: array of DecoderCatalogItem:
{
"name": "sshd-custom",
"parent": "sshd",
"source_file": "local_decoders.xml",
"source_line": 8,
"order": ["srcip", "dstuser"],
"child_count": 0,
"referenced_rule_count": 4,
"reachable_from_rule": true,
"has_regex": true,
"chain_depth": 2,
"fts_fields": ["dstuser"]
}
Quality
GET /platform/projects/{project_id}/quality-gate
Returns the current policy: score thresholds, max diagnostics per severity, etc.
Response 200: QualityGatePolicyRecord.
PATCH /platform/projects/{project_id}/quality-gate
Updates the policy. Partial request with thresholds.
Response 200: QualityGatePolicyRecord.
Test cases
A case = event + expectation. Running it verifies whether the current ruleset behavior matches what's expected.
POST /platform/projects/{project_id}/cases
Creates a case.
Request body (CaseCreateRequest):
{
"name": "SSH brute force",
"description": "Failed password SSH must match rule 5716",
"event_text": "Jan 10 12:00:01 web01 sshd[1234]: Failed password for root",
"log_format": "syslog",
"location": "/var/log/auth.log",
"session_id": "ssh-correlation",
"expected_decoder": "sshd",
"expected_rule": "5716",
"expected_rule_ids": ["5716"],
"expected_fields": { "dstuser": "root", "srcip": "10.0.0.5" }
}
Limits:
event_text— up to 8 MB.expected_fields— up to 100 entries (key ≤ 255, value ≤ 1024).expected_rule_ids— up to 200 entries.
Response 200: CaseRecord.
PATCH /platform/projects/{project_id}/cases/{case_id}
Partial update. Optional fields.
DELETE /platform/projects/{project_id}/cases/{case_id}
Removes the case. Response 204 No Content.
POST /platform/projects/{project_id}/cases/run
Runs every case in the project.
Response 200 (CaseBatchRunResponse):
{
"total_cases": 20,
"passed_cases": 18,
"failed_cases": 2,
"results": [
{
"case": { "...": "CaseRecord" },
"passed": true,
"checks": [
{ "label": "Matched expected rule", "expected": "5716", "actual": "5716", "passed": true }
],
"analysis": { "...": "LogtestResponse" }
}
]
}
Emits webhooks: regression.completed, regression.passed or regression.failed.
POST /platform/projects/{project_id}/cases/{case_id}/run
Runs a single case.
Response 200: CaseRunResponse.
Workspaces
Workspace = isolated editing area with its own ruleset. Publishing turns it into a version.
GET /platform/projects/{project_id}/workspaces
Lists open workspaces.
Response 200: array of WorkspaceRecord.
POST /platform/projects/{project_id}/workspaces
Creates a workspace.
Request body (WorkspaceCreateRequest):
{
"name": "Refactor sshd",
"description": "Rework brute-force rules",
"decoders_xml": "<decoders>…</decoders>",
"rules_xml": "<group name=\"custom\">…</group>",
"event_text": "sample event",
"log_format": "syslog",
"session_id": null,
"include_disk_defaults": true,
"include_disk_custom": true
}
Response 200: WorkspaceRecord.
PATCH /platform/projects/{project_id}/workspaces/{workspace_id}
Updates content. Optionally accepts source_files[] when the workspace originates from Git (preserves per-file provenance).
Response 200: WorkspaceRecord.
Reviews
POST /platform/projects/{project_id}/reviews
Opens a review over a workspace.
Request body (ReviewCreateRequest): { title, workspace_id, reviewer_ids, notes }.
Response 200: ReviewRecord.
PATCH /platform/projects/{project_id}/reviews/{review_id}
Updates status (approved, changes_requested, rejected, closed). Permission: review:approve.
POST /platform/projects/{project_id}/reviews/{review_id}/comments
Adds a comment on the review.
Request body (ReviewCommentCreateRequest): { body: string }.
Webhooks emitted: review.created, review.approved, review.changes_requested, review.rejected.
Versions
Version = published, immutable snapshot. Typical cycle: create (draft) → validate (quality gate) → publish.
POST /platform/projects/{project_id}/versions
Creates a version.
Request body (ProjectVersionCreateRequest):
{
"name": "v2026.04",
"notes": "Fixes sshd brute force",
"source_workspace_id": "ws_01H…",
"source_review_id": "rev_01H…"
}
Response 200: ProjectVersionRecord with status="draft".
POST /platform/projects/{project_id}/versions/{version_id}/publish
Publishes the version. The server runs the quality gate and only promotes if it passes.
Response 200 (ProjectVersionPublishResponse):
{
"version": { "...": "ProjectVersionRecord" },
"published": true,
"quality_gate_result": {
"passed": true,
"failed_rules": [],
"...": "..."
}
}
Webhooks emitted: version.created, version.published, or publish.failed.
POST /platform/projects/{project_id}/versions/{version_id}/restore
Restores this version's content back to the active project.
Response 200: ProjectRecord.
Project members
POST /platform/projects/{project_id}/members
Creates a new user already attached to the project (analogous to /auth/organizations/{id}/members, but also adds the project link).
POST /platform/projects/{project_id}/members/assign
Links an existing organization user to the project.
Request body (ProjectMemberAssignRequest):
{ "user_id": "usr_...", "role": "engineer" }
Audit
GET /platform/audit
All audited events of the active organization.
Response 200: array of AuditEventRecord. Each event carries actor_*, action, resource_*, diff, created_at.
GET /platform/projects/{project_id}/audit
Same, filtered by project.
Shared structures
CaseRecord
{
"id": "string",
"project_id": "string",
"name": "string",
"description": "string",
"event_text": "string",
"log_format": "auto|syslog|json|eventchannel|plain",
"location": "string|null",
"session_id": "string",
"expected_decoder": "string|null",
"expected_rule": "string|null",
"expected_fields": {"key": "value"},
"expected_rule_ids": ["string"],
"created_at": "ISO 8601",
"updated_at": "ISO 8601"
}
WorkspaceRecord
Includes editable content + Git provenance (when applicable):
{
"id": "string", "project_id": "string",
"name": "string", "description": "string",
"decoders_xml": "…", "rules_xml": "…",
"event_text": "string", "log_format": "…",
"session_id": "string",
"include_disk_defaults": true, "include_disk_custom": true,
"source_files": [
{ "path": "rules/local.xml", "kind": "rules", "xml": "…", "sha": "…", "rule_ids": ["100010"], "decoder_names": [] }
],
"git_binding_id": "string|null",
"git_repo": "string|null",
"git_branch": "string|null",
"git_commit_sha": "string|null",
"created_at": "…", "updated_at": "…"
}
ProjectVersionRecord
{
"id": "string", "project_id": "string",
"source_workspace_id": "string|null",
"source_review_id": "string|null",
"name": "string", "notes": "string",
"status": "draft|published|archived",
"quality_score": 87,
"regression_passed": true,
"total_rules": 120, "total_decoders": 45,
"created_at": "…", "updated_at": "…", "published_at": "…"
}