Alert Triage API

The legacy Alert Triage API held one table that did two jobs: pattern rules that changed the action for a class of packages, and entries that suppressed one specific finding. In the new API those are two different resources — policy rules and alert resolutions — so the first step of any migration is deciding which job each legacy entry was doing.

  • Matches by pattern (ecosystem, version prefix, severity range, …) → policy rule
  • Suppresses one finding in one place, or was created from an alert you dismissed → alert resolution

Legacy Contract

GET /orgs/{org_slug}/triage/alerts returns { "results": [...], "nextPage": ... }, paginated with page and per_page (1–100, default 30) and sorted by created_at or updated_at via sort and direction. nextPage is null on the last page. Each entry carries the matcher fields listed in the translation table below, plus state, note, and timestamps.

POST /orgs/{org_slug}/triage/alerts is a batch under the alertTriage key: omit uuid to create an entry, provide it to update one. Returns { "result": "..." }, as does DELETE /orgs/{org_slug}/triage/alerts/{uuid}.

Translating Values

Legacy state to rule action:

Legacy stateNew actionNotes
blockerrorShown as Block in the dashboard
warnwarn
monitormonitor
ignoreignoreConsider an alert resolution instead when the entry targeted one specific finding
inheritNo rule needed; the baseline preset decides

Legacy matcher fields to selector fields:

Legacy fieldSelector
packageTypeartifact.type
packageNamespaceartifact.namespace
packageNameartifact.name
packageVersion (exact)artifact.version
packageVersion with a * suffix, e.g. 4.*"artifact.version": { "$prefix": "4." }
alertTypefinding.alertType
cvssScoreCmp, e.g. >=7.5"finding.cvss": { "$gte": 7.5 }
cveOrGhsaIdfinding.cveId or finding.ghsaId; use $or to match either
fixAvailable: "available" / "unavailable""finding.fixAvailable": true / false
kevs: "exist" / "none""finding.hasKEV": true / false
reachability: "reachable" / "unreachable""finding.reachability": "reachable" / "unreachable"
reachability: "other""finding.reachability": { "$in": ["maybe_reachable", "direct_dependency", "pending", "missing_support", "undeterminable_reachability", "unknown", "error"] }
Any field set to "*" or nullOmit it

patchAvailable has no equivalent and does not translate. The legacy field tested your patch entitlement, while the new finding.cvePatchStatus reports whether a Socket patch exists or is applied for the finding — a different question. If you relied on patchAvailable, decide what you actually want those rules to do (for many orgs that is finding.fixAvailable, possibly combined with finding.cvePatchStatus) and write them fresh rather than translating mechanically.

Legacy entries carrying an alertKey identified one specific alert instance. There is no selector field for it — recreate those as alert resolutions scoped to the repository, package, version, and alert type of the finding they were suppressing.

Example: A Pattern Rule Becomes a Policy Rule

A legacy entry monitoring unreachable critical CVEs in the lodash 4.x line:

{
  "alertTriage": [
    {
      "packageType": "npm",
      "packageName": "lodash",
      "packageVersion": "4.*",
      "alertType": "criticalCVE",
      "cvssScoreCmp": ">=7.5",
      "reachability": "unreachable",
      "state": "monitor",
      "note": "Unreachable in our services"
    }
  ]
}

becomes a rule on the policy that governs the relevant repositories:

curl -u "$SOCKET_API_TOKEN:" -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Monitor unreachable critical CVEs in lodash 4.x",
    "action": "monitor",
    "note": "Unreachable in our services",
    "position": "last",
    "vigil_selector": {
      "finding.alertType": "criticalCVE",
      "finding.cvss": { "$gte": 7.5 },
      "finding.reachability": "unreachable",
      "artifact.type": "npm",
      "artifact.name": "lodash",
      "artifact.version": { "$prefix": "4." }
    }
  }' \
  https://api.socket.dev/v0/orgs/$ORG/alert-policies/default/rules

Returns 201 with the stored rule:

{
  "id": "1b2c3d4e-5f60-4718-9a2b-3c4d5e6f7a8b",
  "alert_policy_id": "7d9e2f10-4a3b-4c5d-8e6f-1a2b3c4d5e6f",
  "rank": "a1",
  "name": "Monitor unreachable critical CVEs in lodash 4.x",
  "vigil_selector": {
    "finding.alertType": "criticalCVE",
    "finding.cvss": { "$gte": 7.5 },
    "finding.reachability": "unreachable",
    "artifact.type": "npm",
    "artifact.name": "lodash",
    "artifact.version": { "$prefix": "4." }
  },
  "action": "monitor",
  "note": "Unreachable in our services",
  "created_by": "0f8a3c1e-2b4d-4e5f-9a6b-7c8d9e0f1a2b",
  "updated_by": "0f8a3c1e-2b4d-4e5f-9a6b-7c8d9e0f1a2b",
  "created_at": "2026-08-06T09:15:02.000Z",
  "updated_at": "2026-08-06T09:15:02.000Z"
}

Placement is controlled by exactly one of position (first or last), before_rule_id, after_rule_id, or an explicit rank. Send none of them and the rule is placed first. Prefer position and the before/after forms over raw ranks. GET .../rules returns { "items": [ ... ] } in evaluation order, PUT .../rules/{rule_id} changes only the fields you send and moves the rule if you include a placement field, and DELETE .../rules/{rule_id} returns { "result": "..." }.

Example: A Suppressed Finding Becomes an Alert Resolution

A legacy entry that suppressed one specific CVE in one repository — an exact package version, a specific CVE, state ignore — was never really a rule. It becomes a resolution:

curl -u "$SOCKET_API_TOKEN:" -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "tolerable_risk",
    "comment": "Dev-only dependency, not shipped",
    "vigil_selector": {
      "finding.alertType": "criticalCVE",
      "finding.cveId": "CVE-2024-29041",
      "location.repo": "my-org/internal-tools",
      "artifact.type": "npm",
      "artifact.name": "lodash",
      "artifact.version": "4.17.20"
    }
  }' \
  https://api.socket.dev/v0/orgs/$ORG/alerts/resolutions

comment is the free-form note (up to 1024 characters); there is also reason_text (up to 256 characters), meant for a short label when reason is other. Both are optional.

Returns 201 with the resolution: its uuid, the selector, and the derived summary fields (alert_type, repo, repo_label, artifact_type, artifact_namespace, artifact_name, artifact_version), each null when the resolution is not limited to a single value for that dimension.

GET /orgs/{org_slug}/alerts/resolutions lists them with cursor pagination — pass the previous response's endCursor as startAfterCursor, with per_page (1–100, default 30) and direction. DELETE .../resolutions/{uuid} returns { "result": "..." }, and the alerts it was hiding reappear on the next refresh.

Related Pages


Did this page help you?