API Reference
Attestd exposes REST endpoints for vulnerability checks, product catalog, CVE detail lookup, usage quota, and webhook management. All responses are JSON unless noted.
Base URL
https://api.attestd.ioAuthentication
Pass your API key in the Authorization header as a Bearer token.
Authorization: Bearer YOUR_API_KEYGet an API key from the developer portal. Use Authorization: Bearer atst_... on every request.
GET /v1/check
Returns the current risk assessment for a product version.
Query parameters
| Parameter | Description |
|---|---|
product | Required. Product slug (e.g. nginx, log4j, openssh). See Quickstart for the full list. |
version | Required. Version string in any standard format (e.g. 1.24.0, 2.14.1, 8.0p1). |
include | Optional. Pass include=cves to receive a per-CVE breakdown in the cves array. Omit for the default compact response. |
Example request
curl "https://api.attestd.io/v1/check?product=nginx&version=1.20.0" \
-H "Authorization: Bearer YOUR_API_KEY"Example with include=cves
Pass include=cves to receive per-CVE detail records in the cves array. See Response Fields for subfield semantics.
curl "https://api.attestd.io/v1/check?product=log4j&version=2.14.1&include=cves" \
-H "Authorization: Bearer YOUR_API_KEY"{
"product": "log4j",
"version": "2.14.1",
"supported": true,
"risk_state": "critical",
"risk_factors": [
"active_exploitation",
"remote_code_execution",
"no_authentication_required",
"internet_exposed_service",
"patch_available"
],
"actively_exploited": true,
"remote_exploitable": true,
"authentication_required": false,
"patch_available": true,
"fixed_version": "2.25.4",
"confidence": 0.5,
"cve_ids": ["CVE-2021-44228", "CVE-2021-45046", "CVE-2021-45105"],
"max_epss": 0.99999,
"cves": [
{
"cve_id": "CVE-2021-44228",
"cvss_score": 10.0,
"actively_exploited": true,
"remote_exploitable": true,
"epss_score": 0.99999,
"epss_percentile": 1.0
},
{
"cve_id": "CVE-2021-45046",
"cvss_score": 9.0,
"actively_exploited": true,
"remote_exploitable": true,
"epss_score": 0.97123,
"epss_percentile": 0.998
}
],
"last_updated": "2026-07-08T10:58:13.230818Z",
"supply_chain": null,
"typosquat": null
}Responses
200 OK(supported product){
"product": "nginx",
"version": "1.20.0",
"supported": true,
"risk_state": "high",
"risk_factors": [
"remote_code_execution",
"no_authentication_required",
"internet_exposed_service",
"patch_available"
],
"actively_exploited": false,
"remote_exploitable": true,
"authentication_required": false,
"patch_available": true,
"fixed_version": "1.20.1",
"confidence": 0.88,
"cve_ids": [
"CVE-2021-23017"
],
"cves": null,
"max_epss": null,
"supply_chain": null,
"supply_chain_monitored": false,
"typosquat": null,
"last_updated": "2026-02-23T18:21:30Z"
}200 OK(product not in coverage){
"supported": false,
"typosquat": {
"detected": true,
"kind": "hallucination",
"resembles": "jscodeshift",
"likely_intended": ["jscodeshift"],
"confidence": 0.9,
"ecosystem": "npm"
}
}POST /v1/check/batch
Check up to 100 product versions in a single request. Each item in the batch is billed as one API call. If the batch would exceed your quota, a 429 is returned before any results are delivered and no calls are billed.
Request body
| Field | Description |
|---|---|
items | Required. Array of { product, version } objects. Minimum 1, maximum 100. |
items[].product | Product slug. Same format as the GET /v1/check product parameter. |
items[].version | Version string. Same format as the GET /v1/check version parameter. |
The optional include=cves query parameter works the same as on GET /v1/check and applies to every item in the batch.
Example request
curl -X POST "https://api.attestd.io/v1/check/batch" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "product": "log4j", "version": "2.14.1" },
{ "product": "nginx", "version": "1.27.4" }
]
}'Response
Each entry in results has a product, version, and result field. The result object is identical in shape to a GET /v1/check response. Results are returned in the same order as the input items.
{
"results": [
{
"product": "log4j",
"version": "2.14.1",
"result": {
"product": "log4j",
"version": "2.14.1",
"supported": true,
"risk_state": "critical",
"risk_factors": [
"active_exploitation",
"remote_code_execution",
"no_authentication_required",
"internet_exposed_service",
"patch_available"
],
"actively_exploited": true,
"remote_exploitable": true,
"authentication_required": false,
"patch_available": true,
"fixed_version": "2.17.1",
"confidence": 0.94,
"cve_ids": ["CVE-2021-44228", "CVE-2021-45046", "CVE-2021-45105"],
"cves": null,
"max_epss": null,
"supply_chain": null,
"typosquat": null,
"last_updated": "2026-02-23T18:21:30Z"
}
},
{
"product": "nginx",
"version": "1.27.4",
"result": {
"product": "nginx",
"version": "1.27.4",
"supported": true,
"risk_state": "none",
"risk_factors": [],
"actively_exploited": false,
"remote_exploitable": false,
"authentication_required": false,
"patch_available": false,
"fixed_version": null,
"confidence": 0.90,
"cve_ids": [],
"cves": null,
"max_epss": null,
"supply_chain": null,
"typosquat": null,
"last_updated": "2026-04-10T09:15:00Z"
}
}
],
"count": 2
}Team-tier accounts can register HTTPS endpoints for supply_chain.compromise events. See Supply chain webhooks for payload shape, signature verification, and delivery semantics.
GET /v1/webhooks
List active webhook subscriptions for the authenticated account. Returns 403 if the API key is not on the Team plan.
curl "https://api.attestd.io/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY"[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://hooks.example.com/attestd",
"events": ["supply_chain.compromise"],
"created_at": "2026-07-08T12:00:00Z"
}
]POST /v1/webhooks
Create a subscription. Body fields: url (HTTPS), secret (16 to 64 characters), events (array; currently supply_chain.compromise only). Returns 201 on success, 400 on validation failure, 403 if not Team tier.
curl -X POST "https://api.attestd.io/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://hooks.example.com/attestd",
"secret": "your-signing-secret-min-16-chars",
"events": ["supply_chain.compromise"]
}'{
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://hooks.example.com/attestd",
"events": ["supply_chain.compromise"],
"created_at": "2026-07-08T12:00:00Z"
}DELETE /v1/webhooks/{id}
Soft-delete a subscription and cancel pending deliveries. Returns 204 on success, 404 if the subscription is not found or not owned by the account.
curl -X DELETE "https://api.attestd.io/v1/webhooks/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer YOUR_API_KEY"GET /v1/products
Returns the full list of products Attestd covers: CVE-tracked software and monitored supply chain packages. Requires a valid API key. The CVE product slugs match the Products catalog.
Example request
curl "https://api.attestd.io/v1/products" \
-H "Authorization: Bearer YOUR_API_KEY"Response
Three top-level fields: cve_products (slug and display_name for each CVE product), supply_chain_packages (package name, ecosystem, and optional display_name), and total (combined count). Arrays are truncated in the example below.
{
"cve_products": [
{ "slug": "nginx", "display_name": "nginx" },
{ "slug": "log4j", "display_name": "Log4j" },
{ "slug": "postgresql", "display_name": "PostgreSQL" }
],
"supply_chain_packages": [
{ "package": "langchain", "ecosystem": "pypi", "display_name": "LangChain" },
{ "package": "react", "ecosystem": "npm", "display_name": "React" }
],
"total": 265416
}GET /v1/cve/{cve_id}
Returns full details for a single CVE: CVSS, EPSS, KEV status, and affected Attestd product slugs. Requires a valid API key. Returns 404 when the CVE is not in Attestd's database. Returns 400 on a malformed CVE id.
Example request
curl "https://api.attestd.io/v1/cve/CVE-2021-44228" \
-H "Authorization: Bearer YOUR_API_KEY"Response
Fields include cve_id, description, cvss_score, cvss_vector, actively_exploited, remote_exploitable, authentication_required, affected_products, epss_score, epss_percentile, source_published_at, and last_checked_at.
{
"cve_id": "CVE-2021-44228",
"description": "Apache Log4j2 JNDI injection allows remote code execution.",
"cvss_score": 10.0,
"cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H",
"actively_exploited": true,
"remote_exploitable": true,
"authentication_required": false,
"affected_products": ["log4j"],
"epss_score": 0.97568,
"epss_percentile": 0.99976,
"source_published_at": "2021-12-10T00:00:00Z",
"last_checked_at": "2026-07-08T04:00:00Z"
}GET /v1/usage
Returns API call quota for the authenticated key: calls used this month, included cap, billing period start and end, and overage estimate. Returns 401 without a valid API key.
Example request
curl "https://api.attestd.io/v1/usage" \
-H "Authorization: Bearer YOUR_API_KEY"Response
Compare key_calls_this_month against included_calls to monitor quota. account_calls_this_month aggregates usage across all keys on the account.
{
"tier": "solo",
"key_calls_this_month": 1200,
"account_calls_this_month": 1200,
"included_calls": 250000,
"billing_period_start": "2026-07-01T00:00:00Z",
"billing_period_end": "2026-08-01T00:00:00Z",
"overage_calls": 0,
"estimated_overage_usd": 0.0
}Supply chain signals
For monitored PyPI and npm packages, the 200 OK response includes a supply_chain object with integrity data (compromised, sources, advisory_url, etc.). For CVE-only products (nginx, PostgreSQL, etc.), supply_chain is null.
See the Supply Chain Integrity guide for the full list of monitored packages and field semantics.
| Status | Meaning |
|---|---|
400 | Missing or invalid query parameters (product or version omitted) |
401 | Missing or invalid API key |
422 | Version string could not be parsed |
429 | Rate limit exceeded (see Retry-After header) |
500 | Internal server error (transient, safe to retry with backoff) |
HTTP/1.1 429 Too Many Requests
Retry-After: 60
{
"detail": "Rate limit exceeded"
}| Tier | Monthly limit | Per-minute limit |
|---|---|---|
| Free | 5,000 calls | 60/min |
| Solo | 250k/month | None |
| Team | 2M/month | None |
| Platform | Unlimited (contract) | None |
Monthly limits reset on your billing anniversary. Free tier returns 429 when the monthly cap or the 60/min per-minute limit is reached. Solo returns 429 at 250,000 calls. Team returns 429 at 2,000,000 calls. Platform has no cap under contract. The 429 response includes a Retry-After header with seconds to wait.