Dry-Run Policy and Resolution Writes
Add ?dry_run=true to a policy, rule, or resolution write to check the request without saving anything. A dry-run returns the same body that a normal write would return. Socket does not create, update, or delete the policy, rule, or resolution, and matching alerts stay on the open list.
This is most useful before you confirm the migration. Until then, a real policy or rule write returns 409. A dry-run of the same request still works. Resolutions can be created for real before and after the cutover; dry-run is optional there.
Which Writes Support dry_run
dry_run| Endpoint | Operation |
|---|---|
POST /orgs/{org_slug}/alert-policies | Create a policy |
PUT /orgs/{org_slug}/alert-policies/{policy_id} | Update a policy |
DELETE /orgs/{org_slug}/alert-policies/{policy_id} | Delete a policy |
POST /orgs/{org_slug}/alert-policies/{policy_id}/rules | Create a rule |
PUT /orgs/{org_slug}/alert-policies/{policy_id}/rules/{rule_id} | Update a rule |
DELETE /orgs/{org_slug}/alert-policies/{policy_id}/rules/{rule_id} | Delete a rule |
POST /orgs/{org_slug}/alerts/resolutions | Create a resolution |
Resolution delete has no dry-run. Neither do any GETs, translate, or the legacy security-policy and triage writes.
Auth and token restrictions match a real write: alert-policy:create / :update / :delete for policy and rule endpoints, alert-resolution:create for a resolution. A repository-restricted token still gets 403 on policy writes, and still cannot create an organization-wide or multi-repo resolution. Each call uses 1 unit of quota.
Success Is 200, Not 201
200, Not 201A dry-run create returns HTTP 200 with dry_run: true on the body, not 201. The body still includes the id or uuid a real write would have produced, but that identifier does not exist. GET it and you get 404. A 201 means it was created. A 200 with dry_run: true means nothing was saved.
A dry-run delete returns { "dry_run": true }, not { "result": "success" }.
A dry-run update returns 200 with the updated body and dry_run: true.
Errors are the same as a real write. A duplicate policy name is still 409. An unknown policy or rule is still 404. A malformed body is still 400. Until you confirm the migration, a real policy or rule write still returns 409. A dry-run is the exception: it returns 200 instead.
Query Values
| Value | Effect |
|---|---|
omitted, false, 0, no, or empty | Real write |
true, 1, or yes (any case, surrounding space ignored) | Dry-run |
anything else (ture, on, maybe) | 400: dry_run must be true, 1, yes, false, 0, or no |
repeated values that disagree (true and false) | 400: dry_run has conflicting values |
Example: Creating a Policy
This works before you confirm the migration. The policy is not created.
curl -u "$SOCKET_API_TOKEN:" -X POST \
-H "Content-Type: application/json" \
-d '{
"name": "Production",
"description": "Stricter handling for production services",
"baseline": "balanced"
}' \
"https://api.socket.dev/v0/orgs/$ORG/alert-policies?dry_run=true"{
"id": "7d9e2f10-4a3b-4c5d-8e6f-1a2b3c4d5e6f",
"name": "Production",
"description": "Stricter handling for production services",
"apply_method": "labeled_repos",
"repo_label_id": "3c4d5e6f-7a8b-4c9d-0e1f-2a3b4c5d6e7f",
"repository_ids": [],
"baseline": "balanced",
"created_by": "0f8a3c1e-2b4d-4e5f-9a6b-7c8d9e0f1a2b",
"updated_by": "0f8a3c1e-2b4d-4e5f-9a6b-7c8d9e0f1a2b",
"created_at": "2026-08-20T14:02:11.000Z",
"updated_at": "2026-08-20T14:02:11.000Z",
"dry_run": true
}GET /orgs/$ORG/alert-policies/7d9e2f10-4a3b-4c5d-8e6f-1a2b3c4d5e6f returns 404. After you confirm the migration, the same POST without dry_run returns 201 and creates the policy.
Example: Creating a Policy Rule from Translate
If translate turned a triage rule into a policy rule, send that body with ?dry_run=true. Use the Default policy, or another policy id if the rule belongs there. Until you confirm the migration, posting the same body without dry_run still returns 409.
curl -u "$SOCKET_API_TOKEN:" -X POST \
-H "Content-Type: application/json" \
-d '{
"name": "in [email protected]",
"action": "monitor",
"note": null,
"vigil_selector": {
"artifact.type": "npm",
"artifact.name": "react",
"artifact.version": "19.2.8"
}
}' \
"https://api.socket.dev/v0/orgs/$ORG/alert-policies/default/rules?dry_run=true"{
"id": "1b2c3d4e-5f60-4718-9a2b-3c4d5e6f7a8b",
"alert_policy_id": "7d9e2f10-4a3b-4c5d-8e6f-1a2b3c4d5e6f",
"rank": "a0",
"name": "in [email protected]",
"vigil_selector": {
"artifact.type": "npm",
"artifact.name": "react",
"artifact.version": "19.2.8"
},
"action": "monitor",
"note": null,
"created_by": "0f8a3c1e-2b4d-4e5f-9a6b-7c8d9e0f1a2b",
"updated_by": "0f8a3c1e-2b4d-4e5f-9a6b-7c8d9e0f1a2b",
"created_at": "2026-08-20T14:03:44.000Z",
"updated_at": "2026-08-20T14:03:44.000Z",
"dry_run": true
}Example: Creating a Resolution
You can create resolutions before you confirm the migration. Dry-run is optional; use it if you want to check the request first without saving it.
curl -u "$SOCKET_API_TOKEN:" -X POST \
-H "Content-Type: application/json" \
-d '{
"reason": "other",
"comment": "accepted risk",
"vigil_selector": {
"finding.alertType": "criticalCVE",
"artifact.type": "npm",
"artifact.name": "lodash"
}
}' \
"https://api.socket.dev/v0/orgs/$ORG/alerts/resolutions?dry_run=true"{
"uuid": "9e0f1a2b-3c4d-4e5f-8a6b-7c8d9e0f1a2b",
"reason": "other",
"reason_text": null,
"comment": "accepted risk",
"vigil_selector": {
"finding.alertType": "criticalCVE",
"artifact.type": "npm",
"artifact.name": "lodash"
},
"alert_type": "criticalCVE",
"repo": null,
"repo_label": null,
"artifact_type": "npm",
"artifact_namespace": null,
"artifact_name": "lodash",
"artifact_version": null,
"resolved_by": null,
"created_at": "2026-08-20T14:04:18.000Z",
"updated_at": "2026-08-20T14:04:18.000Z",
"dry_run": true
}GET /orgs/$ORG/alerts/resolutions/9e0f1a2b-3c4d-4e5f-8a6b-7c8d9e0f1a2b returns 404. Matching alerts stay on the open list. A dry-run does not hide them.
Example: Deleting a Policy
curl -u "$SOCKET_API_TOKEN:" -X DELETE \
"https://api.socket.dev/v0/orgs/$ORG/alert-policies/$POLICY_ID?dry_run=true"{ "dry_run": true }The policy is still there. The same URL without dry_run returns { "result": "success" } and then GET is 404.
Related Pages
- Updating API Integrations — when to switch your scripts, and which endpoints replace which.
- Translating Alert Triage Payloads — convert a
POST /triage/alertsbody into the new requests. - Policies — policy and rule writes after you confirm the migration.
- Resolve Alerts — creating a resolution, including before the cutover.
- Migrating to Policies — confirming the migration is what makes policy and rule writes actually save.
Updated about 22 hours ago