docs / embed

Platform Embed Integration

Verify software before the agent acts on it. Embed Attestd at the action boundary in an agent pipeline, sandbox, or automation platform. Same mental model every time: before install, execute, recommend, deploy, expose, or upgrade. Prototype with a Free or Solo key. Move to Platform when you need embedding rights, volume, or a contract SLA.

action boundaries

Six moments to call Attestd

You already secure agent behaviour. Attestd gives you the software-integrity signal without you building vulnerability normalisation, supply-chain monitoring, and package-name integrity. Call it at these boundaries.

MomentWhat to verify
Before installAgent or IDE about to run pip/npm/install. Reject typosquats and compromised packages before anything lands on disk.
Before executeSandbox or automation about to run a binary or script. Verify the version that will execute.
Before recommendAssistant about to suggest a dependency. Check the name and version before the user copies it into a lockfile.
Before deployCI/CD about to ship to production. Fail on critical risk_state or supply_chain.compromised.
Before exposeProvisioner about to open ingress or attach a public endpoint. Pair with actively_exploited and remote_exploitable.
Before upgradeAutomation about to bump a version pin or roll a fleet. Verify the target version before the change runs.
architecture

Synchronous gate at the action boundary

Your handler calls GET /v1/check (or the SDK equivalent) before the irreversible action, then branches on structured fields. Do not ask an LLM to interpret the response. Branch on booleans and risk_state.

text
Your platform request handler
         │
         ▼
attestd.check(product, version)   ← before the irreversible action
         │
         ├─ risk_state: critical | high          → block
         ├─ supply_chain.compromised: true       → block
         ├─ typosquat.detected: true             → reject + surface resembles
         ├─ outside_coverage / unsupported       → apply your fallback policy
         └─ risk_state: none (and clean SC)      → allow

Use a synchronous gate for before install, execute, recommend, deploy, expose, and upgrade. Use an async side-channel (Team webhooks on supply_chain.compromise) for continuous monitoring after admission. Webhooks do not replace the pre-action check.

For name integrity, treat typosquat.detected: true as a hard reject of the requested name. Prefer resembles / likely_intended. Outside coverage is unknown risk, not a clearance.

latency

Latency expectations

Attestd does not publish formal p50 / p95 SLOs on self-serve tiers. Observed behaviour for a single /v1/check from a warm client is typically well under one second. Batch requests of up to 100 items stay in a similar range because synthesis is precomputed. Under rate limit pressure you receive 429 with Retry-After rather than a slow queue.

ConditionWhat to expect
Single check, cache missTypically under 1 s end-to-end. Precomputed risk_state; no on-request NVD fan-out.
SDK cache hit (runtime)Local memory only. Does not bill. Default TTL is 5 minutes.
Batch ≤ 100 itemsOne HTTP round trip. Each item bills as one call if the request succeeds.
429 / 5xxFail fast. Retry 429 using Retry-After. Retry 500 with exponential backoff.

For production embeds, use cache_policy="runtime" so repeated checks of the same product@version within five minutes do not consume quota. See Best Practices.

batch api

Batch behaviour

POST /v1/check/batch accepts 1 to 100 { product, version } items. Quota is checked before any results are returned. If the batch would exceed your remaining allowance, the API returns 429 and bills nothing.

bash
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.20.0" },
      { "product": "litellm", "version": "1.82.7" }
    ]
  }'
RuleDetail
Max size100 items per request.
BillingOne call per item on success. No partial billing on 429.
Per-minute (Free)60/min. Solo / Team / Platform have no per-minute cap.
Monthly capsFree 1,000; Solo 10,000; Team 100,000; Platform unlimited under contract.
SDK coalesceAsyncClient with batch_window_ms coalesces concurrent check() calls into one batch.

Full request and response shapes: API Reference.

failure semantics

When the API is unavailable

Decide fail-open vs fail-closed before you ship. Security-sensitive gates (agent install, sandbox admit, production deploy) usually fail closed. Non-blocking enrichment can fail open and log.

StatusMeaningRecommended action
400Missing or invalid product / version paramsFix the request. Do not retry.
401Missing or invalid API keyFix credentials. Do not retry.
422Version string could not be parsedNormalize the version. Do not retry as-is.
429Rate limit or monthly quota exceededRespect Retry-After. Back off. Upgrade tier if persistent.
500Transient internal errorRetry with exponential backoff. Then apply fail-open / fail-closed.
python
import os
import attestd
from attestd import AttestdAPIError, AttestdUnsupportedProductError

# fail_closed=True blocks when Attestd is unreachable or returns 5xx.
# fail_closed=False (fail-open) allows the action and logs a warning.
FAIL_CLOSED = os.environ.get("ATTESTD_FAIL_CLOSED", "true").lower() == "true"

client = attestd.Client(
    api_key=os.environ["ATTESTD_API_KEY"],
    cache_policy="runtime",  # 5-minute TTL; cache hits do not bill
)

def gate(product: str, version: str) -> None:
    try:
        result = client.check(product, version)
    except AttestdUnsupportedProductError as e:
        if e.typosquat and e.typosquat.detected:
            raise PermissionError(
                f"name integrity failed for {product}: "
                f"prefer {e.typosquat.resembles}"
            )
        # Outside coverage: treat as unknown risk.
        if FAIL_CLOSED:
            raise PermissionError(f"outside coverage: {product}")
        return
    except AttestdAPIError as e:
        # 429, 5xx, timeout, network. Decide per your policy.
        if FAIL_CLOSED:
            raise PermissionError(f"attestd unavailable: {e}") from e
        return

    if result.risk_state in ("critical", "high"):
        raise PermissionError(f"{product}@{version} risk_state={result.risk_state}")
    if result.supply_chain and result.supply_chain.compromised:
        raise PermissionError(f"{product}@{version} supply chain compromised")

Network timeouts and DNS failures should follow the same FAIL_CLOSED path as 500.

provenance

supply_chain.provenance

npm only. Nested under supply_chain. Values:

ValueMeaning
trueThis version has a valid attestation against the package provenance baseline.
falseThe package has a provenance baseline, but this version lacks attestation. Alert condition.
nullNo baseline known. Absence of attestation is not a signal.

Recommended default: treat false as a warning in sandbox / agent UIs. Reserve hard blocks for supply_chain.compromised: true, risk_state: critical|high, and typosquat hits. Field semantics: Response Fields.

data freshness

How fresh is the data

SourceCadence
NVD + CISA KEVIngested every 6 hours. Responses may be up to cache_ttl_seconds (default 1 hour) stale due to in-memory caching.
Supply chainOSV and registry sources checked on each monitoring run. last_updated on the response is the package-level freshness clock.
EPSSDaily FIRST.org snapshot. max_epss / per-CVE epss may be null for CVEs published after the latest snapshot.

For time-sensitive decisions, read last_updated on the check response (and the X-Attestd-Knowledge-Age header when present). There is no guaranteed fixed lag from OSV publish to API availability; treat last_updated as the authority for that package.

sla

SLA availability

Free, Solo, and Team do not include a published availability or accuracy SLA. Risk assessments are bounded by upstream NVD, CISA KEV, OSV, and registry completeness.

Platform arrangements can include availability commitments, invoicing, and commercial embedding terms. Volume is unlimited under contract. Start the conversation from the pricing page:

sample integrations

Three working patterns

1. Agent security gateway (before install / execute)

Call before an agent installs or executes a package. Blocks on critical / high CVE risk, supply chain compromise, and name integrity failures.

python
"""Agent security gateway: call before an agent installs or executes a package."""
import os
import attestd
from attestd import AttestdUnsupportedProductError

class SecurityGatewayError(Exception):
    pass

client = attestd.Client(
    api_key=os.environ["ATTESTD_API_KEY"],
    cache_policy="runtime",
)

def allow_install(product: str, version: str) -> None:
    """Raise SecurityGatewayError if the package must not be installed."""
    try:
        result = client.check(product, version)
    except AttestdUnsupportedProductError as e:
        if e.typosquat and e.typosquat.detected:
            raise SecurityGatewayError(
                f"hallucinated or typosquat name '{product}'. "
                f"prefer {e.typosquat.resembles} "
                f"(likely_intended={list(e.typosquat.likely_intended)})"
            )
        raise SecurityGatewayError(
            f"no Attestd coverage for '{product}'. treat as unknown risk"
        )

    if result.supply_chain and result.supply_chain.compromised:
        raise SecurityGatewayError(
            f"{product}@{version} supply_chain.compromised=true "
            f"sources={result.supply_chain.sources}"
        )

    if result.risk_state in ("critical", "high"):
        raise SecurityGatewayError(
            f"{product}@{version} risk_state={result.risk_state} "
            f"fixed_version={result.fixed_version}"
        )

# Example: agent about to install a dependency
allow_install("log4j", "2.14.1")  # raises: risk_state=critical

2. Sandbox provider pre-flight (before execute / install)

Admit a dependency into a sandbox only after a structured check. Provenance gaps become warnings. Compromised and critical / high remain hard denies. Batch up to 100 packages per call.

typescript
/** Sandbox provider: pre-flight before admitting a dependency into the sandbox. */
import { Client, AttestdAPIError, AttestdUnsupportedProductError } from '@attestd/sdk';

const client = new Client({
  apiKey: process.env.ATTESTD_API_KEY!,
  cachePolicy: 'runtime',
});

export type PreflightResult = {
  allowed: boolean;
  reason: string;
  warnings: string[];
};

export async function preflightDependency(
  product: string,
  version: string,
): Promise<PreflightResult> {
  const warnings: string[] = [];

  try {
    const result = await client.check(product, version);

    if (result.supplyChain?.compromised) {
      return {
        allowed: false,
        reason: `supply_chain.compromised for ${product}@${version}`,
        warnings,
      };
    }

    if (result.riskState === 'critical' || result.riskState === 'high') {
      return {
        allowed: false,
        reason: `risk_state=${result.riskState} for ${product}@${version}`,
        warnings,
      };
    }

    // npm provenance: false means the package has a baseline but this version
    // lacks attestation. Surface as a warning; do not hard-block by default.
    if (result.supplyChain?.provenance === false) {
      warnings.push(
        `provenance=false for ${product}@${version}: version lacks attestation`,
      );
    }

    return { allowed: true, reason: 'ok', warnings };
  } catch (err) {
    if (err instanceof AttestdUnsupportedProductError) {
      if (err.typosquat?.detected) {
        return {
          allowed: false,
          reason: `name integrity failed; prefer ${err.typosquat.resembles}`,
          warnings,
        };
      }
      return {
        allowed: false,
        reason: `outside coverage for ${product}`,
        warnings,
      };
    }
    if (err instanceof AttestdAPIError) {
      // Propagate so the caller can apply fail-open / fail-closed.
      throw err;
    }
    throw err;
  }
}

/** Admit many packages at once (max 100 per batch call). */
export async function preflightBatch(
  deps: { product: string; version: string }[],
) {
  const results = await client.checkBatch(deps);
  return deps.map((d, i) => ({ dep: d, result: results[i] }));
}

3. Automation platform CI gate (before deploy / expose)

Fail the pipeline when any SBOM item has supply_chain.compromised: true or risk_state in your fail set. Configure strictness with ATTESTD_FAIL_ON.

python
"""Automation platform CI gate: fail the pipeline on critical risk or compromise."""
import os
import sys
import attestd

# Comma-separated risk_state values that fail the build.
# Default: critical,high. Set ATTESTD_FAIL_ON=critical to only block critical.
FAIL_ON = set(
    os.environ.get("ATTESTD_FAIL_ON", "critical,high").lower().split(",")
)

# Parsed from your SBOM / lockfile. Each item is (product, version).
DEPS = [
    ("nginx", "1.20.0"),
    ("log4j", "2.25.5"),
    ("litellm", "1.82.7"),
]

client = attestd.Client(
    api_key=os.environ["ATTESTD_API_KEY"],
    cache_policy="ci",  # infinite TTL within a single CI run
)

failed = False
results = client.batch_check(DEPS)

for (product, version), result in zip(DEPS, results):
    if result is None:
        print(f"  FAIL [OUTSIDE] {product}@{version}", file=sys.stderr)
        failed = True
        continue

    sc = result.supply_chain
    if sc is not None and sc.compromised:
        print(
            f"  FAIL [COMPROMISED] {product}@{version} sources={sc.sources}",
            file=sys.stderr,
        )
        failed = True
        continue

    if result.risk_state in FAIL_ON:
        print(
            f"  FAIL [{result.risk_state.upper()}] {product}@{version} "
            f"fixed_version={result.fixed_version}",
            file=sys.stderr,
        )
        failed = True
        continue

    print(f"  PASS [{result.risk_state}] {product}@{version}")

sys.exit(1 if failed else 0)
related