Changelog
SDK changelogs live in the SDK repositories. This page records what the docs site describes.
The machine contract is public: https://api.vulnify.io/openapi.json.
| Item | Value |
|---|---|
| OpenAPI | 3.0.0 |
| Document version | 0.3.0 |
| Contract | v1 (x-api-version) |
| Server | https://api.vulnify.io |
Schema tables in the API reference are generated from that document at build time. The repository keeps openapi/openapi.json as a fallback so the build does not require the API to be up.
What the contract adds, relative to the first version of these docs:
- Authenticate with
X-API-KeyorAuthorization: Bearer. The value is an API key (vln_live_…orvln_test_…), not a JWT. POST /v1/eventsandGET /v1/events/{id}share one response shape.finalDecisionisREVIEWwhile a review is pending,ALLOWafter approval, andBLOCKafter denial or expiry. The storeddecisiondoes not change. Resolving a review does not emit a new webhook.quotaExceeded,sandbox, andlgpdCategoriesare part of that body, including on GET.- Errors are 400, 401, 403, 404, 413, and 429. 413 means the JSON body is larger than 200 KB. GET does not return 413.
POST /v1/gateway/httpreturnsgateway.upstream, which is null when the call was not forwarded.upstream.statusis an integer or null.POST /v1/gateway/mcpreturnsgateway.protocol,tool,mappedAction, andallowed. It has noupstreamobject.- Idempotent replays of
POST /v1/events,POST /v1/gateway/http, andPOST /v1/gateway/mcpalways includefinalDecision, derived from the stored decision and the current review. TheIdempotency-Keywindow is 24 hours. - Webhook deliveries are in the OpenAPI
webhookssection:decision,anomaly, andtest. Each body includeseventId. DecisiondataincludesdecisionandfinalDecision. Headers includeX-Vulnify-Signature,X-Vulnify-Attempt,X-Vulnify-Event, andX-Vulnify-Delivery. The signature is HMAC-SHA256 of the timestamp, a dot, and the raw body, keyed by thewhsec_secret as UTF-8, with a 300 second tolerance.
GET /health still reports product version 0.3.0 and apiVersion v1. /health, /public/plans, /public/dlp-types, and /public/config are not in the OpenAPI document.
The committed snapshot matches the live document:
GET /v1/policies,POST /v1/policies/apply, andPOST /v1/policies/testare included. Apply requires an org-wideLIVEkey. See Policies and CLI and policies as code.- A test delivery
eventIdis described astest-followed by a UUID. POST /webhooks/resendis not in the document.POST /public/contactis the marketing-site contact form. It is in the document and is not a customer API. It is omitted from the reference navigation.
Node.js SDK
Section titled “Node.js SDK”@vulnify/sdk changelog. Package 0.3.0 on npm.
The vulnify CLI ships in this package: npx -p @vulnify/sdk vulnify. Commands are init, login, check, policies validate, policies pull, policies apply, and test. See CLI and policies as code.
finalDecision is required on check() and getEvent(). Idempotent replays include it. guard() uses decision only when a body omits the field.
verifyWebhook(secret, rawBody, headersOrSignature) checks the signature and returns a decision, anomaly, or test payload. It throws WebhookVerificationError. With request headers, it checks X-Vulnify-Event and X-Vulnify-Delivery against the body. verifyWebhookSignature() still returns a boolean and accepts only t={unix seconds},v1={64 lowercase hex}.
check() and getEvent() include optional finalDecision. It is REVIEW while a review is pending, ALLOW after approval, and BLOCK after denial or expiry. The stored decision does not change. Idempotent replays of older decisions may omit finalDecision. Obey finalDecision ?? decision. guard() uses that value on the initial check. With wait, it still polls review.status and runs the function when the status is APPROVED.
getEvent() returns the same decision body as check(), including quotaExceeded, sandbox, and lgpdCategories. lgpdCategories is the LGPD category union.
Default baseUrl is https://api.vulnify.io. Pass baseUrl (the README uses process.env.VULNIFY_BASE_URL) for another host. The constructor does not read that variable itself.
4xx responses other than 408 and 429 throw, including 413 when the body is over the API limit. failMode: 'open' no longer returns a degraded ALLOW for a request Vulnify rejected. 408, 429, 5xx, timeouts, and network errors still follow failMode.
0.2.0 was not published. That commit still treats some 4xx responses as outages. The ESM and CommonJS builds, and the production default baseUrl, shipped in 0.2.1.
Documents a production export check: ALLOW runs the export, REVIEW stops for a person, and BLOCK or an unreachable API does not run it.
First standalone release. baseUrl defaulted to http://localhost:3000.
Python SDK
Section titled “Python SDK”vulnify changelog. Package 0.4.0 on PyPI.
pip install "vulnify[cli]" installs the vulnify console script (PyYAML and jsonschema). The core install is unchanged. Commands match @vulnify/sdk 0.3.0. See CLI and policies as code.
verify_webhook_signature checks X-Vulnify-Signature over the raw body and raises WebhookVerificationError on failure. construct_webhook and construct_webhook_from_request verify and parse a decision, anomaly, or test delivery. parse_webhook in 0.3.0 required a test eventId of test- plus the delivery id. 0.3.1 accepts any id that starts with test-. That value is its own UUID, not the delivery id. Decision.final_decision stays optional.
Maps optional final_decision. It is REVIEW while a review is pending, ALLOW after approval, and BLOCK after denial or expiry. The stored decision does not change. Idempotent replays of older decisions may omit it (final_decision is None).
wait_for_review and guard(..., wait=) follow final_decision when it is present, and review status APPROVED when it is not. get_event returns the same decision body as check(), including final_decision, quota_exceeded, sandbox, and lgpd_categories.
Default base_url is https://api.vulnify.io. When base_url is omitted, VULNIFY_BASE_URL overrides it. An explicit base_url wins.
413 and every other HTTP 4xx except 408 and 429 raise VulnifyError immediately. They are not retried, and fail_mode cannot turn them into an allow. 408, 429, and 5xx stay retryable.
get_event and wait_for_review retry transient failures, then raise VulnifyError. They do not apply fail_mode. A resolved review leaves decision as REVIEW. In 0.2.0 the go signal was review["status"] == "APPROVED". 0.2.1 uses final_decision when the API sends it. Validation message arrays are joined. Retries wait a short backoff.
Same production export check as the Node.js package.
First standalone release of the vulnify package. base_url defaulted to http://localhost:3000.

