isotope13 / beamline
Browse sample data →
Supply-chain malware detection API

Find 0-day malware in the software supply chain.

Beamline is an API for finding 0-day malware in the software supply chain. Calls wait for an assessment and may be retried.

Your false-positive policy

Set false_positive_budget to match your risk tolerance, then use the measured fires_at level for any additional policy.

Built for what is not known yet

Analyze packages, exact downloads, and uploaded artifacts—not just files that already appear on a threat list.

Endpoint https://api.isotope13.aiAuth Anonymous / Bearer TokenFormats JSON + NDJSON
MethodRouteUse it for
GET/v1/lookupAsk whether an artifact is already known.
POST/v1/analyzeAnalyze a PURL, exact URL, or uploaded bytes.
POST/v1/flushForget every cached answer for an artifact.

Lookup

GET /v1/lookup returns what we already know. It never starts an analysis. Ask with a PURL, an exact URL, or a SHA-256.

PURL

GET /v1/lookup?purl=…
curl -sS \
  "https://api.isotope13.ai/v1/lookup?purl=pkg%3Anpm%2Faxios%401.19.0"
ResponseReady

URL-encode PURLs. Repeat purl for up to 50 packages. One PURL returns an object; several return a list.

Exact URL New

GET /v1/lookup?url=…
curl -sS \
  "https://api.isotope13.ai/v1/lookup?url=https%3A%2F%2Fregistry.npmjs.org%2Faxios%2F-%2Faxios-1.19.0.tgz"
ResponseReady

URL-encode the url query parameter value.

SHA-256

GET /v1/lookup?sha256=…
curl -sS \
  "https://api.isotope13.ai/v1/lookup?sha256=dd46efaa38534ef67370ac3ebc6151e4cf475fdb4bb68f8e2003b432d11d92c2"
ResponseReady

Analyze

POST /v1/analyze streams newline-delimited JSON until an assessment arrives. Complex samples may take minutes. Retrying the same PURL or URL reuses an analysis already in progress.

PURL

POST /v1/analyze?purl=…
curl -sN -X POST \
  "https://api.isotope13.ai/v1/analyze?purl=pkg%3Acargo%2Ftokio%401.40.0"
ResponseReady

Exact URL New

POST /v1/analyze?url=…
curl -sN -X POST \
  "https://api.isotope13.ai/v1/analyze?url=https%3A%2F%2Fregistry.npmjs.org%2Faxios%2F-%2Faxios-1.19.0.tgz"
ResponseReady

Beamline fetches the exact URL and returns its SHA-256. The response includes a PURL when one is known.

Refresh a stored sample

POST /v1/analyze?sha256=…&refresh=1

For a sample already held by Hopper, refresh=1 skips Beamline's edge and KV cache reads. A current Scan-local verdict may answer immediately; otherwise Scan accepts Hopper's verdict only when it matches Scan's current traits version. If it does not, Scan fetches the sample and runs the normal analysis path. The result refills the ordinary caches, and refresh is not part of their key.

Upload bytes

POST /v1/analyze
curl -sN -X POST \
  --data-binary @sample.tgz \
  -H "Content-Type: application/octet-stream" \
  "https://api.isotope13.ai/v1/analyze"
ResponseReady

Archives, binaries, and source are accepted. The default upload limit is 16 MiB.

Add ?full=1 to return {status: "analyzed", ml, raw, llm?} as the terminal line. The complete Scan envelope remains at the top level, with the same terminal status marker as the compact response. Full envelopes and compact decisions use separate cache entries.

Flush New

POST /v1/flush drops every cached answer for one artifact. Name it with ?purl=, ?url=, or ?sha256= — whichever you have. Nothing is re-analyzed; the next lookup or analyze starts from scratch.

POST /v1/flush?purl=…
curl -X POST \\
  "https://api.isotope13.ai/v1/flush?purl=pkg%3Anpm%2Faxios%401.19.0"

An artifact is filed under more than one key: one per follow policy, one per response shape, and one per name that reaches it. A flush clears all of them, then follows the answers it found to the artifact's other names — its digest, its download URL, the PURL Scan normalized it to — and clears those too. The response reports what it reached.

Flushing something that was never cached is not an error. It returns 200 with keys_dropped: 0.

False-positive budget

false_positive_budget sets the false-positive rate you accept, measured per 100 million benign files. It defaults to 25 and controls the returned severity. We recommend choosing 1–250; values through 3000 are accepted because 3000 is the suspicious ceiling.

GET /v1/lookup?purl=…&false_positive_budget=25
POST /v1/analyze?url=…&false_positive_budget=250
ValueBehavior
0Block only when fires_at is 0.
25Block when fires_at is 0–25. Default.
250Recommended upper end; block when fires_at is 0–250.

Use a whole number from 0 to 3000. We recommend 1 to 250. The response field fires_at is the tightest budget at which the artifact is hostile. Severity is hostile at or below the requested budget, suspicious above it through 3000, and benign above 3000 or at -1.

Following references New

?follow= controls what Beamline retrieves from inside the requested artifact. The artifact itself is always analyzed.

ValueRetrievesDefault for
noneNothing else.URL
dependenciesDependencies in manifests and lockfiles.
referencesPackages and URLs in install or download commands.PURL, SHA-256
ci-actionsThird-party CI actions and their dependencies.
allEverything above.Upload
curl -sN -X POST \
  "https://api.isotope13.ai/v1/analyze?purl=pkg%3Anpm%2Faxios%401.19.0&follow=all"

Omit ?follow= to use the default above.

Response

{
  "status": "analyzed",
  "purl": "pkg:npm/axios@1.19.0",
  "sha256": "a511049fdaec40a320368b3ee965079b3e14481f82d052584f746bbdc3f01ede",
  "severity": "benign",
  "fires_at": -1,
  "findings": [],
  "engine_version": "2.8.0",
  "analyzed_at": "2026-08-23T11:48:00Z"
}

status describes whether Beamline has an assessment; severity describes that assessment. A response is factual and does not choose whether your system should proceed. Fields with no value are omitted to save bandwidth:

  • status: "analyzed" means severity was derived from fires_at and the requested budget.
  • status: "unanalyzed" means nobody has analyzed the artifact; severity is unknown.
  • status: "unavailable" means Beamline could not answer; severity is unknown. cause says which outage it was: saturated and mixed are worth retrying with backoff, unreachable and no_workers are not.

For streaming analysis, the terminal line contains status, or ml and raw when full=1. Other lines report progress. Retry if the stream ends without a terminal line.

A {"state":"resumed"} line means the scan worker was lost mid-run and Beamline moved the run to another one. It is progress, not an answer: keep reading. Phases restart after it; elapsed times do not go backwards.

Use cases

CI systems

Use POST /v1/analyze when a job needs a fresh assessment. Name registry dependencies with purl. Upload local build outputs.

Wait for the terminal line containing status, then apply your policy to severity and fires_at:

StatusCI action
analyzedCompare fires_at with your budget.
unanalyzedApply your unknown-artifact policy.
unavailableRetry with backoff when cause is saturated or mixed; otherwise apply your outage policy.

A stream that ends before a status is not an answer. Retry it. Keep the returned sha256 with the build record.

Transparent proxy integration

Keep proxy integrations narrow:

  1. Use ?url=. Send the exact URL already resolved by the proxy.
  2. Choose ?follow=. Use ?follow=none when the proxy sees every download. If it sees only a subset of commands, such as curl or npm, consider ?follow=references. Beamline will also analyze packages and URLs named by install or download commands, which can catch a package that downloads malware later.
  3. Whitelist domains. For privacy reasons, never forward arbitrary user-supplied URLs or URLs containing credentials or private query data.
curl -sN -X POST --get \
  --data-urlencode "url=${EXACT_URL}" \
  --data "follow=none" \
  "https://api.isotope13.ai/v1/analyze"

Keep the returned sha256 and cache the result too.

Errors

Errors are JSON with a stable error.code and a human-readable message.

{
  "error": {
    "code": "invalid_url",
    "message": "url must be an absolute http or https URL."
  }
}

400 means the request is invalid. 401 means a bearer token is required or invalid. 413 means too many packages or an oversized upload. 429 means capacity is temporarily full; retry with backoff. If Beamline cannot answer about an artifact, it returns 200 with status: "unavailable".