Skip to main content

Skanyr

API endpoint discovery from JS bundles and network activity

3 min read


Skanyr discovers hidden API endpoints by parsing JavaScript bundles and intercepting network activity. After discovery, retrieve the detected APIs and their data via dedicated data endpoints.

discover

result = client.skanyr.discover("https://example.com", artifact_id=page.artifact_id)
for ep in result.endpoints:
    print(ep.method, ep.path, ep.confidence)

discover_all (auto-pagination)

for ep in client.skanyr.discover_all("https://example.com"):
    print(ep.method, ep.path)

discoverStream (SSE)

for await (const event of client.skanyr.discoverStream('https://example.com')) {
  console.log(event.type, event.endpoint?.path);
}

detected_apis

After running discovery, retrieve all detected API endpoints and their status across all 12 detectors.

apis = client.skanyr.detected_apis("https://example.com")
for detector in apis.detectors:
    print(detector.name, detector.status, detector.record_count)
const apis = await client.skanyr.detectedApis('https://example.com');
apis.detectors.forEach(d => console.log(d.name, d.status, d.recordCount));

DetectedAPIsResponse fields

| Field | Type | Description | |-------|------|-------------| | detectors | list | Results from each of the 12 detectors | | total_records | integer | Sum of records across all detectors | | page_url | string | The discovered page URL |

DetectorResult fields

| Field | Type | Description | |-------|------|-------------| | name | string | Detector name (e.g. rest_api, graphql, json_ld) | | status | string | found, empty, or error | | confidence | float | 0.0 to 1.0 | | record_count | integer | Number of data records extracted | | api_type | string | rest, graphql, websocket, etc. |

api_data (paginated)

Retrieve the actual extracted data for a specific API endpoint, with pagination.

data = client.skanyr.api_data(
    "https://example.com/api/v1/products",
    offset=0,
    limit=1000,
)
print(f"Page of {len(data.records)} records (total: {data.total_available})")
for record in data.records:
    print(record)
const data = await client.skanyr.apiData('https://example.com/api/v1/products', {
  offset: 0,
  limit: 1000,
});
console.log(`${data.records.length} of ${data.totalAvailable} records`);

ApiDataResponse fields

| Field | Type | Description | |-------|------|-------------| | records | list | Extracted data records | | total_available | integer | Total records available for this endpoint | | offset | integer | Current offset | | limit | integer | Page size used | | api_type | string | rest, graphql, etc. | | endpoint | string | The API endpoint URL | | method | string | HTTP method used |

Data endpoints require a prior discovery run. If no cached results exist, the API returns 404. Discovery results are cached per-organization — each tenant sees only their own results.

ApiEndpoint fields

| Field | Type | Description | |-------|------|-------------| | method | string | HTTP method | | path | string | Endpoint path | | confidence | float | 0.0 to 1.0 | | source | string | js_bundle, network, or probe | | parameters | list | Detected request parameters |

Was this page helpful?