Policies
These three routes are the policies-as-code API. The CLI calls them. Send an API key the same way as the other /v1/ routes. See Authentication.
GET /v1/policies and POST /v1/policies/test accept any non-revoked key of the organization, LIVE or TEST, bound to an agent or not. POST /v1/policies/apply accepts only an org-wide LIVE key (agentId null). Anything else is HTTP 403:
{ "error": "forbidden", "message": "policies:apply requires an org-wide LIVE key" }--dry-run is the same route, so it needs that key too. The rate limit on each route is 60 requests per minute per key. HTTP 429 is {"error":"rate_limited"}. A body over 200 KB is HTTP 413 on the two POST routes.
Policy files use Policy files. spec.action in YAML is the action family (EXPORT), and the API name is metadata.name. The tables below are generated from https://api.vulnify.io/openapi.json.
GET /v1/policies
Section titled “GET /v1/policies”Returns apiVersion vulnify.io/v1 and the organization’s policies sorted by name in Unicode code point order. Each item is a policy plus id and updatedAt.
Policies sorted by name
| Field | Type | Required | Description |
|---|---|---|---|
apiVersion | vulnify.io/v1 | yes | |
policies | array of object | yes | Organization policies sorted by name. |
policies[] | object | no | One policy. name is unique per organization. action is the action family (for example EXPORT), not an event action such as EXPORT_DATA. Omitted enabled defaults to true. Omitted mode defaults to ENFORCE. Omitted resource, null and ANY match every classification. |
policies[].name | string (min length 1, max length 120) | yes | |
policies[].description | string (max length 500) | no | |
policies[].enabled | boolean (default true) | no | |
policies[].action | ANY | READ | WRITE | DELETE | EXPORT | yes | |
policies[].resource | ANY | PUBLIC | INTERNAL | SENSITIVE | CUSTOMER_PII | FINANCIAL | EMPLOYEE | null | no | Resource classification. ANY and null match every classification. |
policies[].condition | object | no | Every field that is set must match. minRecords means recordsAffected is greater than or equal to the value. maxRecords means recordsAffected is less than or equal to the value. Groups may nest up to 32 levels, with at most 20000 conditions in one group. minRecords and maxRecords are integers from 0 through 9007199254740991. agentIds holds at most 8000 ids. allOf matches when every nested condition matches. anyOf matches when at least one does. An empty allOf matches. An empty anyOf does not. dlpTypes and lgpdCategories are accepted here and are not part of the policies-as-code YAML schema. |
policies[].condition.action | string (min length 1, max length 64) | no | Event action (READ_DATA, WRITE_DATA, DELETE_DATA, EXPORT_DATA, SEND_EMAIL) or an action family. Matched against the event action and its family. |
policies[].condition.destination | EXTERNAL | INTERNAL | no | EXTERNAL matches an external destination. INTERNAL matches an internal one. |
policies[].condition.destinationContains | string (max length 100) | no | Case-insensitive substring of the destination. |
policies[].condition.containsSensitiveData | boolean | no | |
policies[].condition.minRecords | integer (0–9007199254740991) | no | |
policies[].condition.maxRecords | integer (0–9007199254740991) | no | |
policies[].condition.minRiskScore | integer (0–100) | no | |
policies[].condition.outsideBusinessHours | boolean | no | Monday to Friday 09:00-18:00 in the organization time zone, inverted. |
policies[].condition.agentIds | array of string (max items 8000) | no | |
policies[].condition.dlpTypes | array of CPF | CNPJ | RG | CNH | PIX_KEY | PHONE_BR | CEP | CREDIT_CARD | EMAIL | HEALTH_DATA | API_KEY | PRIVATE_KEY | no | |
policies[].condition.lgpdCategories | array of IDENTIFICATION | CONTACT | LOCATION | FINANCIAL | HEALTH | COMPANY | CREDENTIALS | no | |
policies[].condition.allOf | array of JSON value (max items 20000) | no | |
policies[].condition.anyOf | array of JSON value (max items 20000) | no | |
policies[].decision | ALLOW | REVIEW | BLOCK | yes | |
policies[].mode | ENFORCE | MONITOR (default "ENFORCE") | no | |
policies[].approverRoles | array of OWNER | ADMIN | MEMBER (unique) | no | Roles that may approve a REVIEW raised by this policy. Empty means owners and admins. |
policies[].id | string (uuid) | yes | |
policies[].updatedAt | string (date-time) | yes |
| Status | Meaning |
|---|---|
401 | Missing or invalid credentials |
403 | Caller IP is not in the API key allowlist. |
429 | 60 requests per minute per API key. |
POST /v1/policies/apply
Section titled “POST /v1/policies/apply”The match key is the policy name. prune: true deletes organization policies whose names are missing from policies. dryRun: true returns the plan and writes nothing. The call runs in one transaction. Each create, update, and delete appends an audit entry with metadata.source policies-as-code and the key prefix, and invalidates the decision cache.
HTTP 400 is {"error":"validation_error","fields":{...}}. Field paths look like policies[0].name. Duplicate names in the payload are a validation error, as is an unknown action, decision, mode, or role.
| Field | Type | Required | Description |
|---|---|---|---|
policies | array of object | yes | |
policies[] | object | no | One policy. name is unique per organization. action is the action family (for example EXPORT), not an event action such as EXPORT_DATA. Omitted enabled defaults to true. Omitted mode defaults to ENFORCE. Omitted resource, null and ANY match every classification. |
policies[].name | string (min length 1, max length 120) | yes | |
policies[].description | string (max length 500) | no | |
policies[].enabled | boolean (default true) | no | |
policies[].action | ANY | READ | WRITE | DELETE | EXPORT | yes | |
policies[].resource | ANY | PUBLIC | INTERNAL | SENSITIVE | CUSTOMER_PII | FINANCIAL | EMPLOYEE | null | no | Resource classification. ANY and null match every classification. |
policies[].condition | object | no | Every field that is set must match. minRecords means recordsAffected is greater than or equal to the value. maxRecords means recordsAffected is less than or equal to the value. Groups may nest up to 32 levels, with at most 20000 conditions in one group. minRecords and maxRecords are integers from 0 through 9007199254740991. agentIds holds at most 8000 ids. allOf matches when every nested condition matches. anyOf matches when at least one does. An empty allOf matches. An empty anyOf does not. dlpTypes and lgpdCategories are accepted here and are not part of the policies-as-code YAML schema. |
policies[].condition.action | string (min length 1, max length 64) | no | Event action (READ_DATA, WRITE_DATA, DELETE_DATA, EXPORT_DATA, SEND_EMAIL) or an action family. Matched against the event action and its family. |
policies[].condition.destination | EXTERNAL | INTERNAL | no | EXTERNAL matches an external destination. INTERNAL matches an internal one. |
policies[].condition.destinationContains | string (max length 100) | no | Case-insensitive substring of the destination. |
policies[].condition.containsSensitiveData | boolean | no | |
policies[].condition.minRecords | integer (0–9007199254740991) | no | |
policies[].condition.maxRecords | integer (0–9007199254740991) | no | |
policies[].condition.minRiskScore | integer (0–100) | no | |
policies[].condition.outsideBusinessHours | boolean | no | Monday to Friday 09:00-18:00 in the organization time zone, inverted. |
policies[].condition.agentIds | array of string (max items 8000) | no | |
policies[].condition.dlpTypes | array of CPF | CNPJ | RG | CNH | PIX_KEY | PHONE_BR | CEP | CREDIT_CARD | EMAIL | HEALTH_DATA | API_KEY | PRIVATE_KEY | no | |
policies[].condition.lgpdCategories | array of IDENTIFICATION | CONTACT | LOCATION | FINANCIAL | HEALTH | COMPANY | CREDENTIALS | no | |
policies[].condition.allOf | array of JSON value (max items 20000) | no | |
policies[].condition.anyOf | array of JSON value (max items 20000) | no | |
policies[].decision | ALLOW | REVIEW | BLOCK | yes | |
policies[].mode | ENFORCE | MONITOR (default "ENFORCE") | no | |
policies[].approverRoles | array of OWNER | ADMIN | MEMBER (unique) | no | Roles that may approve a REVIEW raised by this policy. Empty means owners and admins. |
prune | boolean (default false) | no | Delete organization policies whose names are missing from policies. |
dryRun | boolean (default false) | no | Return the change plan and write nothing. |
Change plan. dryRun true writes nothing.
| Field | Type | Required | Description |
|---|---|---|---|
dryRun | boolean | yes | |
changes | array of object | yes | |
changes[] | object | no | |
changes[].name | string | yes | |
changes[].op | create | update | delete | unchanged | yes |
| Status | Meaning |
|---|---|
400 | Invalid policy spec, duplicate name, or unknown action, decision, mode or role. |
401 | Missing or invalid credentials |
403 | The key is not an org-wide LIVE key. A source IP outside the key allowlist is also forbidden. |
413 | JSON body larger than 200 KB |
429 | 60 requests per minute per API key. |
POST /v1/policies/test
Section titled “POST /v1/policies/test”Evaluates cases with the decision path (permissions, risk, policies, and monitor mode). When policies is omitted, the enabled stored policies are used. When policies is set, those specs are evaluated instead. The call writes no security event and no audit entry. At most 200 cases. input.metadata is accepted and not used. pass is null when expect is omitted.
| Field | Type | Required | Description |
|---|---|---|---|
policies | array of object | no | When set, these policies are evaluated instead of the stored ones. Omitted uses the enabled stored policies. |
policies[] | object | no | One policy. name is unique per organization. action is the action family (for example EXPORT), not an event action such as EXPORT_DATA. Omitted enabled defaults to true. Omitted mode defaults to ENFORCE. Omitted resource, null and ANY match every classification. |
policies[].name | string (min length 1, max length 120) | yes | |
policies[].description | string (max length 500) | no | |
policies[].enabled | boolean (default true) | no | |
policies[].action | ANY | READ | WRITE | DELETE | EXPORT | yes | |
policies[].resource | ANY | PUBLIC | INTERNAL | SENSITIVE | CUSTOMER_PII | FINANCIAL | EMPLOYEE | null | no | Resource classification. ANY and null match every classification. |
policies[].condition | object | no | Every field that is set must match. minRecords means recordsAffected is greater than or equal to the value. maxRecords means recordsAffected is less than or equal to the value. Groups may nest up to 32 levels, with at most 20000 conditions in one group. minRecords and maxRecords are integers from 0 through 9007199254740991. agentIds holds at most 8000 ids. allOf matches when every nested condition matches. anyOf matches when at least one does. An empty allOf matches. An empty anyOf does not. dlpTypes and lgpdCategories are accepted here and are not part of the policies-as-code YAML schema. |
policies[].condition.action | string (min length 1, max length 64) | no | Event action (READ_DATA, WRITE_DATA, DELETE_DATA, EXPORT_DATA, SEND_EMAIL) or an action family. Matched against the event action and its family. |
policies[].condition.destination | EXTERNAL | INTERNAL | no | EXTERNAL matches an external destination. INTERNAL matches an internal one. |
policies[].condition.destinationContains | string (max length 100) | no | Case-insensitive substring of the destination. |
policies[].condition.containsSensitiveData | boolean | no | |
policies[].condition.minRecords | integer (0–9007199254740991) | no | |
policies[].condition.maxRecords | integer (0–9007199254740991) | no | |
policies[].condition.minRiskScore | integer (0–100) | no | |
policies[].condition.outsideBusinessHours | boolean | no | Monday to Friday 09:00-18:00 in the organization time zone, inverted. |
policies[].condition.agentIds | array of string (max items 8000) | no | |
policies[].condition.dlpTypes | array of CPF | CNPJ | RG | CNH | PIX_KEY | PHONE_BR | CEP | CREDIT_CARD | EMAIL | HEALTH_DATA | API_KEY | PRIVATE_KEY | no | |
policies[].condition.lgpdCategories | array of IDENTIFICATION | CONTACT | LOCATION | FINANCIAL | HEALTH | COMPANY | CREDENTIALS | no | |
policies[].condition.allOf | array of JSON value (max items 20000) | no | |
policies[].condition.anyOf | array of JSON value (max items 20000) | no | |
policies[].decision | ALLOW | REVIEW | BLOCK | yes | |
policies[].mode | ENFORCE | MONITOR (default "ENFORCE") | no | |
policies[].approverRoles | array of OWNER | ADMIN | MEMBER (unique) | no | Roles that may approve a REVIEW raised by this policy. Empty means owners and admins. |
cases | array of object (max items 200) | yes | |
cases[] | object | no | |
cases[].name | string (min length 1, max length 200) | yes | |
cases[].input | object | yes | action is an event action. resource is the resource name registered in the organization, not the policy resource classification. metadata is accepted and not used. |
cases[].input.agent | string (min length 1, max length 100) | yes | Agent name. |
cases[].input.action | READ_DATA | WRITE_DATA | DELETE_DATA | EXPORT_DATA | SEND_EMAIL | yes | |
cases[].input.resource | string (min length 1, max length 100) | yes | Resource name. |
cases[].input.destination | INTERNAL | EXTERNAL_EMAIL | EXTERNAL_API | no | |
cases[].input.recordsAffected | integer (0–100000000) | no | |
cases[].input.containsSensitiveData | boolean | no | |
cases[].input.metadata | object | no | Accepted and not used by the policy engine. |
cases[].expect | object | no | |
cases[].expect.decision | ALLOW | REVIEW | BLOCK | yes | |
cases[].expect.policy | string (min length 1, max length 120) | no | Expected matched policy name. |
One result per case. Nothing is stored.
| Field | Type | Required | Description |
|---|---|---|---|
results | array of object | yes | |
results[] | object | no | |
results[].name | string | yes | |
results[].decision | ALLOW | REVIEW | BLOCK | yes | |
results[].matchedPolicy | string or null | yes | |
results[].riskScore | integer (0–100) | yes | |
results[].riskLevel | LOW | MEDIUM | HIGH | CRITICAL | yes | |
results[].reasons | array of string | yes | |
results[].pass | boolean or null | yes | Null when expect was omitted. |
| Status | Meaning |
|---|---|
400 | Invalid policy spec, duplicate name, or unknown action, decision, mode or role. |
401 | Missing or invalid credentials |
403 | Caller IP is not in the API key allowlist. |
413 | JSON body larger than 200 KB |
429 | 60 requests per minute per API key. |

