List Your Scans
Every EdgeProtect attack-surface scan run for your organisation, newest first. Each row embeds the target it ran against and rollup counts for everything the scan found — hosts, ports, services, domains, IP addresses, DNS records, SSL certificates, network ranges, vulnerabilities (and instances), and exposed credentials.
This is the entry point to the whole attack-surface dataset, and it is designed
to be cheap: one call answers "what scans do I have, how big is each one, and
did anything new appear?" There is deliberately no /my/targets endpoint —
the target is on every scan row.
/v1/my/scansCost: 1 credit per successful call · Scope: api:org
Query parameters
targetstring (uuid)optionalOnly scans of this target. The target id comes from the target.id field of
any scan row.
statusstringoptionalOnly scans with this status (e.g. completed).
limitintegeroptionalPage size, 1–200. Default 50. Out-of-range is a 400, not a silent clamp.
cursorstringoptionalOpaque pagination cursor from a previous page's next_cursor. Replay the
same filters with it.
Request
curl https://api.precursorintelligence.com/functions/v1/my/scans \
-H "Authorization: Bearer $PRECURSOR_API_KEY"Response
{
"data": {
"count": 2,
"items": [
{
"id": "f63285e2-9c78-4020-b2bb-5c8bd2ca51ed",
"name": "Scan 06/08/2026 - acmecorp.com",
"status": "completed",
"created_at": "2026-08-06T06:12:44+00:00",
"target": {
"id": "73d787fb-7cd7-6421-4d79-bc5bbe00bf86",
"name": "Acme Corporation",
"value": "acmecorp.com",
"type": "domain"
},
"counts": {
"hosts": 16,
"ports": 36,
"services": 36,
"domains": 1,
"ip_addresses": 17,
"dns_records": 34,
"ssl_certificates": 13,
"network_ranges": 6,
"vulnerabilities": 15,
"vulnerability_instances": 42,
"exposed_credentials": 40
}
}
],
"next_cursor": "eyJpIjogImVjM2Q4...",
"has_more": true,
"generated_at": "2026-08-18T09:30:00+00:00"
},
"meta": {
"request_id": "8b16efb8-9a6c-4ace-b817-11cbee626d08",
"api_version": "1.3.0",
"credits": { "charged": 1, "remaining": 9998 }
}
}Response fields
data.items[].idstring (uuid)optionalThe scan id. Use it in /my/scans/{scan_id}, …/delta and
…/credentials.
data.items[].targetobjectoptionalThe target the scan ran against: id, name, value (e.g. the domain)
and type.
data.items[].countsobjectoptionalRollup counts for every collection the scan produced. Authoritative — use them to decide whether a scan is worth fetching before spending a credit on the full document.
data.next_cursorstring | nulloptionalFollow until null, replaying the same filters. Opaque — do not parse it.
The intended polling loop
Scans are immutable once complete, so the cheapest way to stay current is:
GET /my/scans?limit=1— has a new scan appeared? (1 credit)- If yes:
GET /my/scans/{id}/deltafor what changed, orGET /my/scans/{id}for the full snapshot. (1 credit)
That is 1–2 credits per scan cycle. There is no need to re-fetch a scan you have already downloaded — it will never change.
Errors
| Status | error | When |
|---|---|---|
| 400 | invalid_target, invalid_status, invalid_limit, invalid_cursor | A parameter failed validation. Free — rejected before billing. |
| 401 | invalid_authorization | Missing or malformed Authorization header. |
| 401 | unauthorized | Invalid/revoked key, IP not allowlisted, or the key lacks the api:org scope. |
| 402 | insufficient_credits | Organisation credit balance is below 1. |
| 405 | method_not_allowed | Only GET and OPTIONS are accepted. |
| 500 | internal | Unexpected server error (credit auto-refunded). |
See Errors for the full error reference.