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.