---
title: "List scans"
method: GET
path: "/v1/scans"
tags: ["Sources"]
---

# List scans

`GET /v1/scans`

⚠️ **Beta endpoint**: behavior and schemas are subject to change.

List historical scans with the same payload the scan detail endpoint
returns, so a whole perimeter can be polled in one request instead of one
request per scan.

Use `active_or_updated_since` to poll: it keeps every scan that is still
running plus every scan whose payload moved since that instant, which is
what a plain "not finished" filter would lose — a scan ending, or its
audit summary landing minutes later, between two polls.

## Query parameters

- `cursor` string
- `per_page` integer
- `active_or_updated_since` string, date-time
- `ordering` 'gg_created_at' | '-gg_created_at'

## Response `200`

Scan list

- object[]
  - `scan_id` string, uuid, required — ID of the scan this progress belongs to.
  - `source` object, nullable, required — ⚠️ **Beta schema**: subject to change. Snapshot of the scanned source, frozen when the scan was launched. It is not refreshed afterwards, so a source renamed or resized mid-scan keeps the values it had at launch — except for scans that carry no snapshot, which report the source's current values.
    - `id` integer, required — ID of the source.
    - `visibility` 'public' | 'private' | 'internal', required — Visibility of the source on the provider.
    - `display_name` string, required — Human-readable name of the source.
    - `type` string, required — Type of the source.
    - `size` integer, nullable, required — Size of the source in bytes. `null` for source types that do not report a size.
  - `report_status` 'pending' | 'in_progress' | 'summarizing' | 'done' | 'unavailable', required — How far the scan's audit report has got. Poll on this, not on `scan_status`: the scan reaching a terminal status does not mean the report's final numbers (`duration_seconds`, `pending_seconds`, `outcome_by_reason`) are ready yet. Stop polling once `report_status` is `done` (the numbers are ready) or `unavailable` (no report will ever come).
  - `scan_status` 'launched' | 'pending' | 'running' | 'finished' | 'failed' | 'canceled' | 'too_large' | 'timeout' | 'skipped' | 'pending_timeout' | 'running_failed' | 'running_cancelled', required — Status of the scan itself.
  - `scan_status_reason` string, nullable, required — Reason for the scan's current status, e.g. why it failed or was skipped. `null` when not applicable.
  - `elements_total` integer, required — Number of elements listed so far. Provisional (still growing) until `listing_finished` is `true`, after which this is the scan's final count.
  - `elements_scanned` integer, required — Number of elements scanned so far. Final once `scan_status` is terminal.
  - `elements_skipped` integer, required — Number of elements skipped so far. Final once `scan_status` is terminal. Includes elements filtered out before listing (e.g. unsupported file types), which are not counted in `elements_total`.
  - `elements_failed` integer, required — Number of elements that failed to scan so far. Final once `scan_status` is terminal.
  - `listing_finished` boolean, required — Whether the scan has finished listing all its elements, i.e. whether `elements_total` reflects the true final count.
  - `data_downloaded_bytes` integer, nullable, required — Amount of data downloaded so far, in bytes. `null` for sources that do not track byte counters, which is distinct from a real `0`.
  - `data_scanned_bytes` integer, nullable, required — Amount of data scanned so far, in bytes. `null` for sources that do not track byte counters, which is distinct from a real `0`.
  - `started_at` string, date-time, nullable, required — Date and time the scan started. `null` while the scan is still queued.
  - `ended_at` string, date-time, nullable, required — Date and time the scan ended. `null` while it is running.
  - `duration_seconds` integer, nullable, required — Duration of the scan, in seconds, from the audit summary. `null` until `report_status` is `done`.
  - `pending_seconds` integer, nullable, required — Time the scan spent pending before it started, in seconds, from the audit summary. `null` until `report_status` is `done`.
  - `outcome_by_reason` object, nullable, required — Element outcome counts broken down by reason, from the audit summary, under the `skipped` and `failed` categories. `null` until `report_status` is `done`.
  - `elements_by_type` object, required — Per-element-type breakdown of the counts above, for sources that track more than one kind of element. Only populated for VCS repository scans, where it reports `commit`, `branch` and `patch` counters; an empty object otherwise. Note `patch` carries skip counters only.

## Other responses

- `400` — Invalid data
- `401` — Invalid API key
- `403` — Forbidden Call
- `503` — API under maintenance

## Changes

- **2026-09-28** `4bc35232f994` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/gitguardian/apis/gitguardian-api/changes/v1/scans/get.md)

---

[API](https://skmtc.dev/gitguardian/apis/gitguardian-api.md) · [All operations](https://skmtc.dev/gitguardian/apis/gitguardian-api/llms.txt) · [OpenAPI document](https://skmtc.dev/gitguardian/apis/gitguardian-api/revisions/488d081f7d86?raw)
