> ## Documentation Index
> Fetch the complete documentation index at: https://docs.scanoss.com/llms.txt
> Use this file to discover all available pages before exploring further.

# v3 API overview

> Base URL, authentication, request and response conventions, PURL-keyed batch requests, and the fingerprint scan flow of the public SCANOSS v3 API.

The SCANOSS v3 API is the public HTTP API behind scanoss-cli. Use it directly when you build your
own client, or when you need SCANOSS component data inside another service. If you only need
results in a pipeline, [scanoss-cli](/en/latest/cli/scanoss-go/installation) already implements
everything on this page.

The **API Reference** group in the sidebar lists every endpoint with its request and response
schema.

## Base URL

```
https://api.scanoss.com
```

All endpoints are under the `/v3/` prefix. An on-premise deployment exposes the same paths under
its own base URL.

## Authentication

Send your API key in the `x-api-key` header on every request:

```bash theme={null}
curl -sS "https://api.scanoss.com/v3/components/status" \
  --get --data-urlencode "purl=pkg:github/scanoss/engine" \
  -H "x-api-key: $SCANOSS_API_KEY"
```

HTTP header names are not case-sensitive, so `X-Api-Key` works too. The API rejects a missing or
invalid key with HTTP `401`. To get a key, see
[API keys and authentication](/en/latest/developer-tools/authentication).

## What the API covers

| Area | Example endpoints | Returns |
| - | - | - |
| Vulnerabilities | `/v3/vulnerabilities/vulnerabilities`, `/v3/vulnerabilities/cpes` | Known CVEs (with CVSS and EPSS data) and CPEs per component |
| Licences | `/v3/licenses`, `/v3/license/attribution`, `/v3/license/evidence` | Declared licences, attribution files, per-file licence evidence |
| Cryptography | `/v3/cryptography/algorithms`, `/v3/cryptography/hints` | Algorithms and crypto libraries per component version or version range |
| Components | `/v3/components/search`, `/v3/components/versions`, `/v3/components/status`, `/v3/components/releases` | Search, known versions, lifecycle status, release notes |
| Dependencies | `/v3/dependencies/dependencies`, `/v3/dependencies/transitive` | Declared and transitive dependencies |
| Geoprovenance | `/v3/geoprovenance/countries`, `/v3/geoprovenance/origin` | Contributor locations and origin distribution |
| Copyright | `/v3/copyright/evidence`, `/v3/copyright/holders` | Copyright statements and holders |
| Scanning | `/v3/wfp/scan`, `/v3/wfp/scan/{id}` | Open source matches for fingerprinted source code |

## Identify components by PURL

Component data is keyed by [Package URL (PURL)](https://github.com/package-url/purl-spec), for
example `pkg:github/scanoss/engine` or `pkg:npm/lodash`. An optional `requirement` narrows the
request to a version or, on range endpoints, a version range:

| Field | Required | Example |
| - | - | - |
| `purl` | Yes | `pkg:github/scanoss/engine` |
| `requirement` | No | `v5.4.5` |

Most lookup endpoints accept both forms:

* **`GET` for one component.** Pass `purl` and `requirement` as query parameters.
* **`POST` for many components.** Send a JSON body with a `components` array. This is the batch
  form.

```bash theme={null}
curl -sS https://api.scanoss.com/v3/vulnerabilities/vulnerabilities \
  -H "x-api-key: $SCANOSS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "components": [
      { "purl": "pkg:github/madler/zlib", "requirement": "1.2.11" },
      { "purl": "pkg:npm/lodash" }
    ]
  }'
```

A batch request must contain at least one component. To send a list larger than you want in one
request, split it into chunks and send the chunks in parallel. scanoss-cli does this with a
default chunk size of 10 PURLs.

### Search options

A batch body can also carry a `search` object, and the same options are available as query
parameters on `GET` requests:

| Option | Default | Meaning |
| - | - | - |
| `max_results_per_purl` | `0` (no limit) | Caps the results returned for each PURL |
| `show_related_results` | `false` | Also look up the component's source PURL |
| `on_version_not_found` | `strict` | Version fallback: `strict`, `show_latest`, `show_closest_lt`, `show_closest_gt`, `show_any`. Not applied to range endpoints. |
| `encoded` | `none` | Encoding for content strings in the response: `none`, `url_encoded`, `base64_encoded` |

Endpoints that support these options say so in the API Reference. Today, `/v3/license/evidence` is
the main endpoint that uses them.

## Response conventions

### Batch status and per-item info codes

A batch request returns HTTP `200` even when some components could not be resolved. Each response
has two levels of outcome:

* **`status.status`** for the request as a whole: `SUCCESS`, `PARTIAL_SUCCESS`, or `ERROR`, with
  a human-readable `status.message`.
* **`info_code`** and **`info_message`** on each item in `components`, when that item did not
  resolve cleanly.

This is an illustrative response for the request above, where the second PURL is not known:

```json theme={null}
{
  "components": [
    {
      "purl": "pkg:github/madler/zlib",
      "requirement": "1.2.11",
      "version": "1.2.11",
      "vulnerabilities": [
        {
          "id": "CVE-2022-37434",
          "cve": "CVE-2022-37434",
          "severity": "Critical",
          "source": "NVD"
        }
      ]
    },
    {
      "purl": "pkg:npm/does-not-exist",
      "info_code": "COMPONENT_NOT_FOUND",
      "info_message": "component not found"
    }
  ],
  "status": { "status": "PARTIAL_SUCCESS", "message": "..." }
}
```

| `info_code` | Meaning |
| - | - |
| `REQUIREMENT_NOT_MET` | Informational. The requested version had no data, so the API used the nearest version instead. The item still has results. |
| `INVALID_PURL` | The API could not parse the PURL. |
| `COMPONENT_NOT_FOUND` | The component is not in the SCANOSS Knowledge Base. |
| `VERSION_NOT_FOUND` | The component is known, but the requested version is not. |
| `RESOLVE_FAILED` | The lookup failed for this item. |
| `RELEASE_NOTES_UNAVAILABLE` | No release notes exist for the resolved version. |
| `WARNING` | The item resolved with a warning. Read `info_message`. |

A single-component `GET` reports the same `status.status`, derived from that one item's
`info_code`.

<Tip>
  In a client, treat `SUCCESS` and `PARTIAL_SUCCESS` as usable responses, and read `info_code` on
  each item to decide what to retry or report. Do not retry a whole batch because one item
  returned `COMPONENT_NOT_FOUND`.
</Tip>

### Errors

Requests that fail as a whole, such as a malformed body or a server error, return an HTTP error
status with this body:

```json theme={null}
{
  "status": "error",
  "error": { "code": "INVALID_QUERY", "message": "purl query parameter is required" },
  "timestamp": "2026-05-19T11:39:56Z"
}
```

`error.code` is a stable identifier, so parse it instead of `message`. Common codes include
`INVALID_BODY`, `INVALID_QUERY`, `EMPTY_BATCH`, `INVALID_PURL`, `COMPONENT_NOT_FOUND`,
`VERSION_NOT_FOUND`, `TIMEOUT`, and `INTERNAL_ERROR`.

| HTTP status | Typical cause |
| - | - |
| `400` | Invalid parameters or body |
| `401` | Missing or invalid API key |
| `404` | Component, version, or scan not found |
| `410` | Scan session expired |
| `413` | Upload larger than the allowed size |
| `500` | Unexpected server error |
| `504` | The request exceeded the server's deadline |

## Scanning source code: the fingerprint flow

The API never receives your source code. You send **WFP fingerprints**, which are compact hashes
of each file and of its snippets. Generate them with `scanoss-cli wfp`, the
[Go SDK](https://github.com/scanoss/scanoss.go), or another SCANOSS client, rather than writing
your own fingerprinter:

```bash theme={null}
scanoss-cli wfp ./my-project --output project.wfp
```

`POST /v3/wfp/scan` accepts a WFP in one of two modes. The `X-Scan-Id` request header selects the
mode. Both return the same `ScanEnvelope`, and the final `result` is identical in both.

### Small inputs: one synchronous request

Without an `X-Scan-Id` header, send the whole WFP as the body. The request blocks until the scan
finishes and returns `200` with `status: completed` and the `result`:

```bash theme={null}
curl -sS -X POST https://api.scanoss.com/v3/wfp/scan \
  -H "x-api-key: $SCANOSS_API_KEY" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @project.wfp
```

The request timeout and the maximum upload size limit this mode. Use it only for small inputs.

### Large inputs: upload in blocks, then poll

For anything larger, upload the WFP in blocks and poll for the result. This is what
`scanoss-cli scan` does.

<Steps>
  <Step title="Create a scan ID">
    Generate a new UUID version 7 in canonical lowercase form, for example
    `018f7b2c-9a3e-7d41-8b6a-2c1d4e5f6a7b`. Your client creates this ID, not the server. The
    server rejects any other ID format with `400 INVALID_SCAN_ID`.
  </Step>

  <Step title="Upload each block">
    Split the WFP into byte ranges (scanoss-cli uses 1 MiB blocks by default). Send each one as
    `POST /v3/wfp/scan` with:

    * `X-Scan-Id`: the same scan ID on every block
    * `Content-Range: bytes <start>-<end>/<total>`: the block's position, zero-based, end inclusive
    * `Content-Type: application/octet-stream`

    ```bash theme={null}
    curl -sS -X POST https://api.scanoss.com/v3/wfp/scan \
      -H "x-api-key: $SCANOSS_API_KEY" \
      -H "X-Scan-Id: $SCAN_ID" \
      -H "Content-Range: bytes 0-1048575/3145728" \
      -H "Content-Type: application/octet-stream" \
      --data-binary @block-0.bin
    ```

    Each accepted block returns `202` with `status: uploading` and `received_bytes`. Blocks can
    arrive in any order and in parallel. If you resend a block the server already has, with the
    same bytes, it returns `202` again, so you can retry a block safely. When the blocks cover the
    whole range with no gaps, the server starts the scan.
  </Step>

  <Step title="Poll for the result">
    ```bash theme={null}
    curl -sS "https://api.scanoss.com/v3/wfp/scan/$SCAN_ID" -H "x-api-key: $SCANOSS_API_KEY"
    ```

    `status` moves through `uploading`, `queued`, `scanning`, and finally `completed`, `failed`,
    or `expired`. While scanning, `phase`, `phase_done`, and `phase_total` report progress. Once
    `completed`, the envelope carries `result`. The API reports a `failed` scan in the body with an
    `error` string, not as an HTTP error. scanoss-cli polls every 2 seconds by default.
  </Step>
</Steps>

A block upload can return these errors:

| Response | Cause |
| - | - |
| `400 INVALID_SCAN_ID` | The scan ID is not a canonical lowercase UUID version 7 |
| `400 MISSING_RANGE` | `Content-Range` is missing |
| `400 INVALID_RANGE` | `Content-Range` is malformed, or the body length does not match it |
| `409 RANGE_CONFLICT` | A block overlaps received bytes with different content, or the scan ID belongs to a finished upload |
| `413 PAYLOAD_TOO_LARGE` | A block or the declared total is larger than allowed |

The server keeps a scan session for a limited time. Polling an unknown ID returns `404 SCAN_NOT_FOUND`,
and polling an expired one returns `410 SCAN_EXPIRED`.

### The scan result

`result` contains:

* `files`: one entry per scanned file, with its `path`, its `match_type` (`file`, `snippet`, or
  `none`), and a `matches` list. Each match names a component release by `url_hash` and carries a
  `confidence` grade (`LOW`, `MEDIUM`, or `HIGH`). Snippet matches also carry
  `match_percentage` and the matched line ranges in your file and in the open source file.
* `components`: the matched component releases, keyed by `url_hash`, with `component`, `vendor`,
  `version`, `url`, `release_date`, and `purls`.

scanoss-cli turns this result into its raw inventory, SPDX, or CycloneDX output and can add
licence, vulnerability, cryptography, and geoprovenance data with `--include`. If you call the
API yourself, you add that data by sending the matched PURLs to the lookup endpoints above.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.