Skip to content

Windows Patch Level (API v2)

API version 2.0 (2026-09-26). Implements the Windows Build and KB Data Contract v0.1.

1. Purpose

API v2 takes the Windows build and update facts you collect from each host and returns, per CVE, whether the host is confirmed open, cleared (patched) or needs review, using Microsoft's own fixed builds and update (KB) data. Without a build, BreachSpider can only say a CVE applies to the Windows release; with a build, it can say whether this host is still exposed.

  • Cumulative Windows (Windows 10, Windows 11, Server 2016 and later): the host's os_build is compared with Microsoft's fixed build for that CVE on that product. At or above means cleared; below means confirmed open.
  • Legacy Windows (Windows 7, Server 2008 R2, Server 2012 R2): the host's installed_kbs are checked against the fix KB. A later monthly rollup, or a KB that Microsoft lists as replacing the fix, also counts. For CVEs published after end of support, esu_enrolled decides the outcome.
  • Build and KB list disagree: the result is needs review. It is never guessed.
  • No os_build, or a bare "Windows": the host is not patch-resolved. It stays product-level, as in API v1.

API v1, including POST /api/v1/assets/correlate-cves, is unchanged.

2. Authentication

Send an API key in the Authorization header:

Authorization: Bearer bs_live_...

Each key belongs to one BreachSpider organization and only sees that organization's environments.

Action Key scope needed
Submit hosts (POST /api/v2/assets/correlate, POST /api/v2/assets/correlate-csv) write
Read stored results (GET /api/v2/assets/results) read (a read-only key is enough)

Rate limits, per key: 60 requests per minute and 5,000 hosts per minute. Each call accepts at most 200 hosts. For your initial bulk load, we can raise the limits on your key for a set period. The raised limits lapse automatically at the agreed end time.

Logging: we log each request's time, key, path, HTTP status, host count and duration. We never log request or response bodies.

3. Endpoints

Method and path Purpose
POST /api/v2/assets/correlate Submit up to 200 Windows hosts (JSON), plus optional installed software, and get results
POST /api/v2/assets/correlate-csv The same as a CSV upload (multipart form)
GET /api/v2/assets/results Read stored results for an environment, or for one asset_id

Base URL: https://breachspider.com

4. Host fields

These are the contract fields, with the same names in JSON and CSV. An empty value means unknown.

Field Required Format and meaning
asset_id yes Your scrubbed asset identifier, up to 64 characters. It must not be a hostname, IP, MAC or serial. Example: A-0417
os_product yes Windows ProductName, exactly as the host reports it. Example: Windows Server 2019 Datacenter. Windows 11 reports "Windows 10", so we identify it by build 22000 or higher.
edition_id yes EditionID. Examples: ServerDatacenter, ServerStandard, Enterprise, EnterpriseS (LTSC), Professional
display_version no DisplayVersion, or ReleaseId on older builds. Example: 21H2
os_build yes Full build 10.0.<CurrentBuild>.<UBR>, digits and dots only. Example: 10.0.17763.6189
architecture yes x64, x86 or arm64
installation_type for servers Server, Server Core or Client
installed_kbs see note KB numbers. JSON: a list (["KB5034439","KB5033371"]). CSV: semicolon-separated (KB5034439;KB5033371). Duplicates are ignored.
kb_source when installed_kbs is sent How the KB list was collected (free text). Examples: DISM packages, WMI QuickFixEngineering
esu_enrolled no (legacy Windows) yes or no
collected_at yes Collection time, ISO 8601 UTC. Example: 2026-09-25T14:02:00Z

KB list states: - installed_kbs has values: the KB list was collected. - installed_kbs is empty and kb_source is filled: collected, none found. - Both are empty, or both are omitted: not collected.

Legacy Windows hosts need a collected KB list to be patch-resolved.

Installed software (optional, stored only for now). Send it in the installed_software array (JSON) or a second CSV. Fields: asset_id, name, publisher, version. List each host in windows_hosts before sending its software.

Never send: hostnames, domain names, IP or MAC addresses, user names, serial numbers, license keys, install paths, or anything naming a site or customer. A field with one of these names is refused with an error, and nothing in that host record is stored.

5. Validation rules

We validate each host on its own. A refused host does not stop the other hosts in the call.

Rule Error code
A field that identifies a host, person or site (hostname, ip_address, mac_address, domain, serial_number, user_name, license_key, install_path, site, customer, ...) forbidden_field
asset_id that looks like an IP, MAC or domain name, or is longer than 64 characters (the value is not echoed back) forbidden_value
A field that is not in the contract unknown_field
A placeholder value (N/A, -, unknown, none, null, TBD, ...). Send an empty value instead. placeholder_value
A required field is missing missing_field
os_product is only "Windows" and there is no os_build bare_windows
os_build is not digits and dots invalid_build
architecture is not x64, x86 or arm64 invalid_architecture
installation_type is not Server, Server Core or Client invalid_installation_type
A server edition without installation_type missing_installation_type
A KB that is not "KB" followed by digits invalid_kb
installed_kbs without kb_source missing_kb_source
esu_enrolled is not yes or no invalid_esu
collected_at is not ISO 8601 with a time zone invalid_collected_at

Warning (the host is accepted):

Condition Warning code
os_build has three parts (no revision). The host stays product-level and is labelled "needs revision" until the full build is sent. needs_revision

6. Results

For each accepted host:

Field Meaning
asset_id Your identifier
microsoft_product The Microsoft product the host was matched to, e.g. Windows Server 2019
candidate_products Set only when the edition was not supplied and several Microsoft products fit the build
patch_resolved true when results are based on the build or KB list
end_of_life true when the Windows version is past Microsoft's end of support (and ESU, if enrolled)
map_note Why a host could not be matched, or which products fit a build-only host
labels Any of: product-level (no build), needs revision, product-level (not mapped), resolved by build; edition not supplied, end of life
counts Number of CVEs per status: confirmed_open, cleared, needs_review
cves[] One entry per CVE: cve_id, status (confirmed open, cleared (patched), needs review), fixed_build, kb, source (the Microsoft Security Update Guide document), severity (Microsoft's rating), known_exploited (confirmed open only), note (why, for needs review or build-only results), priority_rank (1 = first), priority_reason (plain-language reason), fix (available, action, source, derived), references (nvd_url, cve_org_url, vendor_advisories (Microsoft's own advisory pages), cisa_ics_advisories, other_references capped at 25, other_references_total; same rules as the v1 correlate references fields)
fix_groups[] One entry per fix action, ranked: fix (e.g. install KB5122876 (latest cumulative, build 10.0.17763.9245)), fix_type (kb, esu, none), kb, kbs_covered (the per-CVE KBs this action supersedes), cve_ids, counts (total, confirmed, known_exploited, exploit_available), highest_score, group_rank
cves_page Only when paging is requested: page, page_size, total (after filters), total_unfiltered, has_more
warnings For example needs_revision

Set options.include_cleared (JSON) or include_cleared (CSV form) to false to leave cleared CVEs out of cves[]. They still appear in counts.

Ordering, filters and paging (JSON options, CSV form fields, or /results query parameters, all optional):

Option Meaning
sort priority (default): confirmed open → needs review → cleared; then known-exploited; then exploit or proof-of-concept available; then installable fix, then ESU-required, then no fix; then BCS, CVSS, EPSS. score: the previous order (confirmed open first, then CVE id). exploit: known-exploited, exploit/PoC, EPSS, CVSS. newest: published date. Any other value returns 422.
confirmed_only, known_exploited_only, fix_available_only Filters, off by default. ESU-required fixes count as available.
cve_page, cve_page_size Paging, off by default (every CVE is returned, as before). cve_page_size 1–1000.

Sorting and filters are applied before paging; counts always reports every CVE.

Fix actions for Windows. - Cumulative-servicing Windows (Server 2016 and later, Windows 10/11): every open CVE with a fixed build is grouped under the product's latest cumulative update, whose build is at or above every fixed build, so one install clears them all. The per-CVE KBs it supersedes are listed in kbs_covered. - Legacy servicing (for example Server 2012 R2): Monthly Rollup and Security Only fixes are grouped under the newest monthly rollup the host can install; servicing-stack and standalone security updates keep their own KB. A KB already in the host's installed_kbs is never recommended. - End-of-life hosts not enrolled in ESU: fixes released after end of support are Extended Security Updates, grouped as ESU required (or upgrade the OS), with the ESU KB named in each CVE's priority_reason. They rank below directly installable fixes of the same exploit tier.

data.fix_summary[] lists the top 10 fix actions across every host in the call (rank, fix, product, asset_ids, counts, highest_score). meta.sort and meta.filters echo what was applied.

meta.microsoft_data_as_of is the revision date of the newest Microsoft document behind the results. Microsoft data is refreshed daily, and in full after each monthly release.

End of life. A host is labelled end of life when its Windows version or edition is past Microsoft's end of support. With esu_enrolled: yes, the label applies only after the Extended Security Updates period has ended too.

7. Errors

Errors use BreachSpider's standard error envelope. error.code is the general code (for example RATE_LIMITED). For the v2 errors below, error.detail holds the specific error code, a message and any extra fields such as retry_after. See the example in section 8.

HTTP error When
401 API key missing or invalid
403 insufficient_scope Submitting with a key that lacks the write scope
404 environment_not_found environment_id is not in your organization
413 batch_too_large More than 200 hosts in one call
422 Malformed JSON body, a top-level field outside environment_id, windows_hosts, installed_software, options, or an invalid option (e.g. sort not one of priority, score, exploit, newest)
422 (per host) Every host in the call was refused. The response lists them in data.rejected with their error codes.
429 rate_limited Per-key limit reached; retry_after gives the seconds to wait

If some hosts are accepted and others refused, the call returns 200 with the refused hosts in data.rejected.

8. Example

Request: two hosts, plus a third that carries a hostname and is refused. Cleared CVEs are left out, and the list is cut to two CVEs per host here.

POST /api/v2/assets/correlate
Authorization: Bearer bs_live_...
Content-Type: application/json

{
  "environment_id": 12,
  "windows_hosts": [
    {
      "asset_id": "A-0417",
      "os_product": "Windows Server 2019 Standard",
      "edition_id": "ServerStandard",
      "display_version": "1809",
      "os_build": "10.0.17763.7792",
      "architecture": "x64",
      "installation_type": "Server",
      "collected_at": "2026-09-25T14:02:00Z"
    },
    {
      "asset_id": "A-0533",
      "os_product": "Windows Server 2012 R2 Standard",
      "edition_id": "ServerStandard",
      "os_build": "6.3.9600.21620",
      "architecture": "x64",
      "installation_type": "Server",
      "installed_kbs": [
        "KB5031419"
      ],
      "kb_source": "WMI QuickFixEngineering",
      "esu_enrolled": "no",
      "collected_at": "2026-09-25T14:02:00Z"
    },
    {
      "asset_id": "A-0600",
      "hostname": "plc-eng-ws",
      "os_product": "Windows 10 Enterprise LTSC 2021",
      "edition_id": "EnterpriseS",
      "os_build": "10.0.19044.6332",
      "architecture": "x64",
      "installation_type": "Client",
      "collected_at": "2026-09-25T14:02:00Z"
    }
  ],
  "options": {
    "include_cleared": false
  }
}

Response (200):

{
  "data": {
    "assets": [
      {
        "asset_id": "A-0417",
        "microsoft_product": "Windows Server 2019",
        "candidate_products": null,
        "patch_resolved": true,
        "end_of_life": false,
        "labels": [],
        "map_note": null,
        "counts": {
          "confirmed_open": 1653,
          "cleared": 3949,
          "needs_review": 3
        },
        "cves": [
          {
            "cve_id": "CVE-2016-9535",
            "status": "confirmed open",
            "fixed_build": "10.0.17763.7919",
            "kb": "KB5066586",
            "source": "https://api.msrc.microsoft.com/cvrf/v3.0/cvrf/2025-Oct",
            "severity": "Critical",
            "known_exploited": false,
            "note": null
          },
          {
            "cve_id": "CVE-2020-17103",
            "status": "confirmed open",
            "fixed_build": "10.0.17763.8880",
            "kb": "KB5094123",
            "source": "https://api.msrc.microsoft.com/cvrf/v3.0/cvrf/2020-Dec",
            "severity": "Important",
            "known_exploited": false,
            "note": null
          }
        ],
        "warnings": []
      },
      {
        "asset_id": "A-0533",
        "microsoft_product": "Windows Server 2012 R2",
        "candidate_products": null,
        "patch_resolved": true,
        "end_of_life": true,
        "labels": [
          "end of life"
        ],
        "map_note": null,
        "counts": {
          "confirmed_open": 1937,
          "cleared": 2074,
          "needs_review": 9
        },
        "cves": [
          {
            "cve_id": "CVE-2016-9535",
            "status": "confirmed open",
            "fixed_build": "6.3.9600.22824",
            "kb": "KB5066873",
            "source": "https://api.msrc.microsoft.com/cvrf/v3.0/cvrf/2025-Oct",
            "severity": "Critical",
            "known_exploited": false,
            "note": null
          },
          {
            "cve_id": "CVE-2022-0001",
            "status": "confirmed open",
            "fixed_build": "6.3.9600.21924",
            "kb": "KB5036960",
            "source": "https://api.msrc.microsoft.com/cvrf/v3.0/cvrf/2024-Apr",
            "severity": "Important",
            "known_exploited": false,
            "note": null
          }
        ],
        "warnings": []
      }
    ],
    "rejected": [
      {
        "asset_id": "A-0600",
        "errors": [
          {
            "code": "forbidden_field",
            "field": "hostname",
            "message": "Field 'hostname' is not accepted: identifying data must not be sent. The field was not stored."
          }
        ]
      }
    ],
    "software_stored": 0,
    "software_rejected": []
  },
  "meta": {
    "api_version": "2",
    "microsoft_data_as_of": "2026-09-25T07:00:00+00:00",
    "took_ms": 1793
  }
}

A-0417 is a Server 2019 host about a year behind: 1,653 CVEs are confirmed open and 3,949 are cleared by its build. A-0533 is Server 2012 R2 without ESU, past end of support: CVEs Microsoft published after 10 October 2023 are open because no ESU fix can be installed, and older CVEs are checked against its October 2023 monthly rollup. A-0600 was refused and nothing from it was stored. The other hosts in the call were still processed.

Error example (429):

{
  "api": {"version": "1.0.0", "request_id": "bs-req-...", "timestamp": "2026-09-26T02:45:49Z"},
  "error": {
    "code": "RATE_LIMITED",
    "message": "Per-key limit is 60 requests and 5000 hosts per minute.",
    "detail": {"error": "rate_limited", "message": "Per-key limit is 60 requests and 5000 hosts per minute.", "retry_after": 10}
  }
}

9. CSV equivalent

POST /api/v2/assets/correlate-csv takes a multipart form with these parts:

Part Content
environment_id The environment to write to
hosts A UTF-8 CSV file with a header row, using the field names in section 4 as column names
software Optional. A CSV file with columns asset_id,name,publisher,version
include_cleared Optional. true (default) or false
sort, confirmed_only, known_exploited_only, fix_available_only, cve_page, cve_page_size Optional; the same meaning as in section 6
asset_id,os_product,edition_id,display_version,os_build,architecture,installation_type,installed_kbs,kb_source,esu_enrolled,collected_at
A-0417,Windows Server 2019 Standard,ServerStandard,1809,10.0.17763.7792,x64,Server,,,,2026-09-25T14:02:00Z
A-0533,Windows Server 2012 R2 Standard,ServerStandard,,6.3.9600.21620,x64,Server,KB5031419,WMI QuickFixEngineering,no,2026-09-25T14:02:00Z
curl -X POST https://breachspider.com/api/v2/assets/correlate-csv \
  -H "Authorization: Bearer bs_live_..." \
  -F environment_id=12 -F [email protected] -F [email protected]

The CSV upload runs the same validation and the same processing as the JSON call, and returns the same response. The same hosts give identical results either way; and our tests check this on every release.