API Reference
Table of contents
Base URL and authentication
https://kief.dev/api/vekt
All requests must include an Authorization header with your API key:
Authorization: Bearer vkt_live_xxxxxxxxxxxxxxxxxxxx
Get an API key at kief.dev/vekt.
Rate limiting
Every response includes rate limit headers:
| Header | Description |
|---|---|
X-RateLimit-Limit |
Maximum scans allowed in the current period |
X-RateLimit-Remaining |
Scans remaining in the current period |
X-RateLimit-Reset |
Unix timestamp when the limit resets |
Example headers:
X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 3753
X-RateLimit-Reset: 1743465600
When X-RateLimit-Remaining reaches 0, the API returns 429 Too Many Requests until the period resets. On paid plans with overage enabled, requests continue and overages are billed at $0.005 per scan.
POST /scan
Submit a lockfile for scanning. Returns a list of findings.
Request
Content type: application/json
POST /scan
Authorization: Bearer <api-key>
Content-Type: application/json
Request body:
{
"lockfile_type": "package-lock.json",
"content": "<raw lockfile content as a string>"
}
| Field | Type | Required | Description |
|---|---|---|---|
lockfile_type |
string | Yes | Filename of the lockfile format (see supported lockfile types) |
content |
string | Yes | Raw text content of the lockfile |
Content type: multipart/form-data
You can also upload the lockfile as a file:
POST /scan
Authorization: Bearer <api-key>
Content-Type: multipart/form-data
Form fields:
| Field | Type | Required | Description |
|---|---|---|---|
lockfile |
file | Yes | The lockfile to scan. The filename is used to detect the lockfile type. |
The uploaded filename must match a supported lockfile name exactly (e.g., package-lock.json, Cargo.lock).
Maximum request size: 10 MB.
Response
HTTP 200 with a JSON array of findings. An empty array means no findings were detected.
[
{
"package": "lodash",
"version": "4.17.15",
"ecosystem": "npm",
"malicious": false,
"security_holder": false,
"vulns": [
{
"id": "GHSA-jf85-cpcp-j695",
"summary": "Prototype Pollution in lodash",
"threat_level": "Vulnerability",
"aliases": ["CVE-2019-10744"],
"url": "https://osv.dev/vulnerability/GHSA-jf85-cpcp-j695"
}
]
},
{
"package": "malicious-pkg",
"version": "2.1.0",
"ecosystem": "npm",
"malicious": true,
"security_holder": false,
"vulns": [
{
"id": "MAL-2024-0123",
"summary": "Malicious code that steals npm tokens",
"threat_level": "Malicious",
"aliases": [],
"url": "https://osv.dev/vulnerability/MAL-2024-0123"
}
]
}
]
Response fields
| Field | Type | Description |
|---|---|---|
package |
string | Package name |
version |
string | Package version |
ecosystem |
string | Ecosystem identifier (e.g., npm, PyPI, crates.io) |
malicious |
boolean | true if any finding is a confirmed malicious package |
security_holder |
boolean | true if the package is an inert registry security-placeholder |
vulns |
array | List of individual vulnerability or advisory findings |
vulns[].id |
string | Advisory identifier (e.g., GHSA-xxxx-yyyy-zzzz, CVE-2024-XXXXX, MAL-2024-XXXX) |
vulns[].summary |
string | Human-readable description of the finding |
vulns[].threat_level |
string | "Malicious", "Vulnerability", or "SecurityHolder" |
vulns[].aliases |
array | Alternative IDs for the same advisory (e.g., CVE alias for a GHSA) |
vulns[].url |
string | Link to the full advisory |
Example: curl with JSON body
curl -s -X POST https://kief.dev/api/vekt/scan \
-H "Authorization: Bearer vkt_live_xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"lockfile_type": "package-lock.json",
"content": "'"$(cat package-lock.json | jq -Rs .)"'"
}'
Example: curl with file upload
curl -s -X POST https://kief.dev/api/vekt/scan \
-H "Authorization: Bearer vkt_live_xxxxxxxxxxxxxxxxxxxx" \
-F "[email protected]"
Example: pipe a lockfile
cat Cargo.lock | \
jq -Rs '{"lockfile_type": "Cargo.lock", "content": .}' | \
curl -s -X POST https://kief.dev/api/vekt/scan \
-H "Authorization: Bearer vkt_live_xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d @-
Example response (clean scan)
curl -s -X POST https://kief.dev/api/vekt/scan \
-H "Authorization: Bearer vkt_live_xxxxxxxxxxxxxxxxxxxx" \
-F "[email protected]"
[]
An empty array means all packages in the lockfile are clean.
Error responses
All error responses use the following format:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable description of the problem"
}
}
| Status | Code | Description |
|---|---|---|
| 400 | BAD_REQUEST |
The request body is malformed, the lockfile_type is not recognized, or the content cannot be parsed as the specified format |
| 401 | UNAUTHORIZED |
The Authorization header is missing or the API key is invalid |
| 413 | PAYLOAD_TOO_LARGE |
The request body exceeds the 10 MB limit |
| 429 | RATE_LIMITED |
You have exceeded your scan quota for the current period. Check X-RateLimit-Reset for when the limit resets. |
| 500 | INTERNAL_ERROR |
An unexpected server error occurred. Retry with exponential backoff. |
400 example
{
"error": {
"code": "BAD_REQUEST",
"message": "Unknown lockfile_type: 'lock.json'. See https://kief.dev/vekt/docs/supported-lockfiles for supported formats."
}
}
401 example
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid API key. Obtain a key at https://kief.dev/vekt."
}
}
429 example
{
"error": {
"code": "RATE_LIMITED",
"message": "Scan quota exceeded. 5000 scans used of 5000 allowed. Limit resets at 2026-04-01T00:00:00Z."
}
}
Status codes
| Code | Meaning |
|---|---|
| 200 | Scan completed. Response body contains the findings array (may be empty). |
| 400 | Bad request -- check the request format or lockfile type. |
| 401 | Authentication required -- check your API key. |
| 413 | Lockfile too large -- maximum 10 MB per request. |
| 429 | Rate limit exceeded -- check X-RateLimit-Reset and retry after. |
| 500 | Server error -- safe to retry. |