Get an event
GET /v1/events/{id} reads a decision and its review status. Use it to poll a REVIEW. The body is the same as POST /v1/events, including finalDecision, quotaExceeded, and sandbox.
Resolving a review does not emit a new webhook. decision stays at the value recorded when the event was created. While the review is pending, finalDecision is REVIEW. After approval it is ALLOW. After denial or expiry it is BLOCK.
curl "https://api.vulnify.io/v1/events/EVENT_ID" \ -H "Authorization: Bearer $VULNIFY_API_KEY"const decision = await vulnify.getEvent(eventId);decision = vulnify.get_event(event_id)X-API-Key may replace the bearer header.
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string |
The same decision body as POST /v1/events, including quotaExceeded, sandbox and finalDecision
| Field | Type | Required | Description |
|---|---|---|---|
id | string (uuid) | yes | |
decision | ALLOW | REVIEW | BLOCK | yes | Decision recorded on the event. It does not change when a review is resolved. |
finalDecision | ALLOW | REVIEW | BLOCK | yes | Effective outcome. Equals `decision` when there is no review. REVIEW while a review is pending. ALLOW after approval, BLOCK after denial or expiry. Always present, including an idempotent replay of a response stored before this field existed: the replay derives it from the stored decision and the current review. |
evaluatedDecision | ALLOW | REVIEW | BLOCK | yes | What full enforcement would have decided. Differs from `decision` in monitor mode. |
monitored | boolean | yes | |
riskLevel | LOW | MEDIUM | HIGH | CRITICAL | yes | |
riskScore | integer (0–100) | yes | |
reasons | array of string | yes | |
policy | object or null | yes | |
policy.id | string (uuid) | yes | |
policy.name | string | yes | |
dlpFindings | array of string | yes | Sensitive-data types found in `content`. |
lgpdCategories | array of IDENTIFICATION | CONTACT | LOCATION | FINANCIAL | HEALTH | COMPANY | CREDENTIALS | yes | LGPD categories derived from `dlpFindings`. |
review | object or null | yes | Null when the event has no human review. |
review.status | PENDING | APPROVED | DENIED | EXPIRED | yes | |
review.expiresAt | string or null (date-time) | yes | |
review.decidedAt | string or null (date-time) | yes | |
review.note | string or null | yes | |
quotaExceeded | boolean | yes | Plan quota is over the limit. The decision is still made. |
sandbox | boolean | yes | True when the event was created with a TEST key. |
| Header | Description |
|---|---|
X-Request-Id | Request id for support and log correlation (a caller-sent plain id is kept). |
x-api-version | Machine API contract (v1). |
x-vulnify-version | API build (SemVer, see /changelog). |
| Status | Meaning |
|---|---|
400 | Validation error, or agent/resource was not identified |
401 | Missing, invalid, revoked or expired API key |
403 | API key is bound to another agent, or the caller IP is not in the key allowlist |
404 | Unknown agent, resource, event or gateway route |
429 | Rate limit exceeded |
This route does not return 413. There is no Idempotency-Key and no Idempotent-Replay header.
Node.js getEvent throws on any non-OK status. It does not retry and it does not apply failMode. Python get_event retries timeouts, network errors, 408, 429, and 5xx, then raises VulnifyError. It does not apply fail_mode. See Errors.
The id comes from the id field of the create response. A fallback decision produced when the API was unreachable has id: null and cannot be fetched.
@vulnify/sdk 0.2.3 requires finalDecision on getEvent, and the result includes quotaExceeded and sandbox. vulnify 0.3.0 copies finalDecision to final_decision (still optional on Decision) and copies quotaExceeded and sandbox. The machine contract requires finalDecision, quotaExceeded, and sandbox on this body, including an idempotent replay of finalDecision.

