Developers
Developer docs
Ask Vulnify whether an agent action is allowed before you run it.
Quickstart
- Sign in, open Dashboard → Open demo sandbox (or register your own agents and resources).
- Open API Keys and create a key. It is shown once.
- Call the API before your agent performs a sensitive action:
curl -X POST https://YOUR_API_HOST/v1/events \
-H "Authorization: Bearer $VULNIFY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"agent":"SalesBot","action":"EXPORT_DATA","resource":"Customer Database","destination":"EXTERNAL_EMAIL","recordsAffected":12000}'{
"id": "0f6c1b1e-...",
"decision": "BLOCK",
"evaluatedDecision": "BLOCK",
"monitored": false,
"riskLevel": "CRITICAL",
"riskScore": 100,
"reasons": [
"Export operation",
"Customer PII",
"External destination",
"Large data volume (12,000 records)",
"Policy matched: Block external export of customer PII"
],
"policy": { "id": "a1b2...", "name": "Block external export of customer PII" },
"review": null
}Authentication
Send your organization API key as a bearer token: Authorization: Bearer vln_live_... (or X-API-Key). Keys are scoped to one organization, stored only as a hash, and can be revoked at any time from the API Keys page. Keep them server-side; never ship them to browsers.
POST /v1/events
Evaluates one agent action and records it in Security Events and the Audit Log.
| Field | Type | Description |
|---|---|---|
agent / agentId | string | Agent name or UUID as registered in Vulnify. One is required. |
action | enum | READ_DATA, WRITE_DATA, DELETE_DATA, EXPORT_DATA or SEND_EMAIL. |
resource / resourceId | string | Resource name or UUID. One is required. |
destination | enum | INTERNAL, EXTERNAL_EMAIL or EXTERNAL_API. Optional. |
recordsAffected | integer | Number of records touched. Optional. |
The response contains decision (what you must obey: ALLOW, REVIEW or BLOCK), evaluatedDecision, monitored, riskScore (0-100), riskLevel, reasons, policy and review.
Handling decisions
- ALLOW: proceed.
- REVIEW: do not proceed automatically; a human must approve (see Human review).
- BLOCK: do not perform the action. Log the reasons and tell the user why.
If Vulnify is unreachable, decide your failure mode. We recommend fail closed for destructive or export actions and fail open only for low-risk reads.
Human review
A REVIEW decision creates a pending review (valid for 24 hours). Approvers resolve it in the Reviews screen with an optional note; every approval or denial is written to the audit log with the reviewer. Poll the event to learn the outcome:
// decision === "REVIEW" -> a human must approve. The response carries:
"review": { "status": "PENDING", "expiresAt": "2026-09-26T14:00:00Z" }
// Poll until it is resolved (APPROVED | DENIED | EXPIRED):
curl https://YOUR_API_HOST/v1/events/EVENT_ID \
-H "Authorization: Bearer $VULNIFY_API_KEY"Monitor mode
Roll out without risk. In Settings you can switch the organization to Monitor only (or set individual policies to Monitor). Vulnify then evaluates and records every action but returns ALLOW to the agent, with monitored: true and evaluatedDecision showing what would have happened. Review the "would be blocked" count on the dashboard, then switch enforcement on.
Node SDK
npm install @vulnify/sdk
import { Vulnify, VulnifyBlockedError } from '@vulnify/sdk';
const vulnify = new Vulnify({
apiKey: process.env.VULNIFY_API_KEY!,
baseUrl: 'https://YOUR_API_HOST',
failMode: 'closed', // 'open' allows the action if Vulnify is unreachable
timeoutMs: 3000,
});
try {
// Third argument: wait for a human when the decision is REVIEW.
await vulnify.guard(
{ agent: 'SalesBot', action: 'EXPORT_DATA', resource: 'Customer Database',
destination: 'EXTERNAL_EMAIL', recordsAffected: 12000 },
() => exportCustomers(),
{ timeoutMs: 5 * 60_000, pollMs: 2000 },
);
} catch (err) {
if (err instanceof VulnifyBlockedError) {
console.warn(err.result.decision, err.result.reasons);
} else throw err;
}Configuration errors (invalid API key, unknown agent or resource, invalid payload) always throw, so they are never silently ignored by failMode.
API keys and scopes
Create keys in API Keys. Each key can be limited to one environment, one agent, a set of source IPs and an expiry date:
vln_live_...production keys;vln_test_...sandbox keys: their events are evaluated normally but kept out of dashboards and usage (sandbox: true).- A key bound to an agent can only report events for that agent (403 otherwise) and may omit the agent field.
- An IP allowlist rejects requests from other addresses (403). Expired or revoked keys return 401.
Idempotency
Send an Idempotency-Key header (any unique string, up to 200 characters). Retrying with the same key returns the original decision (with the header Idempotent-Replay: true) and never creates a second event, even when retries run concurrently. Keys are remembered for 24 hours. The SDKs do this for you.
Sensitive content (DLP)
Optionally send content (up to 100,000 characters). Vulnify scans it in memory for CPF, CNPJ, payment cards (Luhn), emails, API keys and private keys. The response lists the types in dlpFindings and the risk score rises by 25. The content itself is never stored: only the detected types are kept.
POST /v1/events { ..., "content": "Ana Souza, CPF 529.982.247-25" }
{
"decision": "ALLOW",
"riskScore": 30,
"dlpFindings": ["CPF"],
"reasons": ["Read operation", "Sensitive data detected in content: CPF"]
}Agent permissions
Permissions grant actions on kinds of data (for example READ_DATA on FINANCIAL). With enforcement on, an action outside the agent's permissions is BLOCKED with the reason "Missing permission", and every action of a paused or disabled agent is blocked. Manage them under Agents → Permissions.
Python SDK and adapters
from vulnify import Vulnify, VulnifyBlockedError
vulnify = Vulnify(api_key=os.environ["VULNIFY_API_KEY"], base_url="https://YOUR_API_HOST")
vulnify.guard(export_customers, agent="SalesBot", action="EXPORT_DATA",
resource="Customer Database", destination="EXTERNAL_EMAIL",
records_affected=12000, wait={"timeout": 300})The Node SDK ships adapters for OpenAI/Anthropic tool calls (guardedTools), LangChain (guardLangChainTool), MCP servers (guardMcpHandler) and any function (guardFunction). See the examples folder in the repository.
An interactive OpenAPI reference is served by the API at /docs-api (and the JSON spec at /docs-api-json) in non-production environments.
How risk is scored
Scores are rule-based and explainable, capped at 100. Levels: 0-24 LOW, 25-49 MEDIUM, 50-74 HIGH, 75-100 CRITICAL. LOW and MEDIUM are allowed, HIGH needs review, CRITICAL is blocked, unless a policy says otherwise.
| Factor | Points |
|---|---|
| Read / Write / Delete / Export | +5 / +15 / +30 / +30 |
| Sensitive resource (PII, financial, employee, sensitive) | +25 |
| External destination | +25 |
| More than 100 / 1,000 / 10,000 records | +10 / +20 / +30 |
Policies (Block / Review / Allow) are evaluated after the score. A matching Block or Review policy always wins; an Allow policy is an explicit override.
Errors and limits
400invalid payload (unknown fields are rejected).401missing, invalid or revoked API key.404unknown agent, resource or event in your organization.403API key bound to another agent, or source IP not allowed.413body larger than 200 KB.429rate limit exceeded (1,200 requests per minute per IP by default).

