# Datasets, feedback & status

> Inspect active and historical dataset snapshots (/v1/metadata/datasets), submit network corrections (/v1/feedback), and probe service health (/v1/status).

## 1. Dataset snapshots metadata (`GET /v1/metadata/datasets`)

```http
GET https://api.ipscope.io/v1/metadata/datasets
```

Authentication: API key (`X-API-Key` header or `Authorization: Bearer`). Plan: scope: lookup

Returns the currently active dataset snapshot version, the previous rollback snapshot version, and the list of compiled snapshot manifests (`DatasetsMetadataResponse`).

```bash curl
curl -sS "https://api.ipscope.io/v1/metadata/datasets" \
  -H "Authorization: Bearer $IPSCOPE_KEY"
```

```js Node.js
const res = await fetch('https://api.ipscope.io/v1/metadata/datasets', {
  headers: { 'Authorization': `Bearer ${process.env.IPSCOPE_KEY}` },
});
const data = await res.json();
```

```python Python
import os, httpx

async with httpx.AsyncClient(timeout=5.0) as client:
    res = await client.get(
        "https://api.ipscope.io/v1/metadata/datasets",
        headers={"Authorization": f"Bearer {os.environ['IPSCOPE_KEY']}"},
    )
    data = res.json()
```

```go Go
req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.ipscope.io/v1/metadata/datasets", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("IPSCOPE_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
```

### 200 `DatasetsMetadataResponse`: Active and historical dataset snapshot manifests and prefix counts.

- `active_version` (string, required, nullable): Snapshot version currently serving real-time lookups.
- `previous_version` (string, optional, nullable): Prior snapshot version retained in memory for instant zero-downtime rollback.
- `snapshots` (DatasetSnapshotMetadataItem[], required): Catalog of active and recent dataset snapshots.
  - `snapshot_version` (string, required): Unique version identifier of the snapshot.
  - `digest` (string, required): Cryptographic SHA-256 content digest (`"sha256:..."`).
  - `ruleset_version` (string, required): Version of the classification ruleset used to compile the snapshot.
  - `published_at` (string, required): ISO 8601 UTC publication timestamp.
  - `ipv4_prefix_count` (integer, required): Total routed IPv4 prefixes indexed in the snapshot.
  - `ipv6_prefix_count` (integer, required): Total routed IPv6 prefixes indexed in the snapshot.

```json 200 DatasetsMetadataResponse
{
  "active_version": "2026-10-27T00:00:00Z.crawl-1793088000000",
  "previous_version": "2026-10-26T00:00:00Z.crawl-1793001600000",
  "snapshots": [
    {
      "snapshot_version": "2026-10-27T00:00:00Z.crawl-1793088000000",
      "digest": "sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
      "ruleset_version": "2026.10.2",
      "published_at": "2026-10-27T00:00:00Z",
      "ipv4_prefix_count": 28410200,
      "ipv6_prefix_count": 6912400
    }
  ]
}
```

### 401 `ApiError`: Missing or invalid API key.

- `statusCode` (integer, required): HTTP status code returned by the API gateway.
- `message` (string, required): Human-readable diagnostic message describing the error condition.
- `error` (string, required): Canonical HTTP error classification.

```json 401 ApiError
{
  "statusCode": 401,
  "message": "Missing or invalid API key",
  "error": "Unauthorized"
}
```

## 2. Submit a correction report (`POST /v1/feedback`)

```http
POST https://api.ipscope.io/v1/feedback
```

Authentication: API key (`X-API-Key` header or `Authorization: Bearer`). Plan: scope: lookup · 201 Created

Programmatically submit a geolocation, virtual-location, or VPN/anonymizer false-positive correction report. Submissions are persisted via `PlatformStateService` with status `pending_review` and feed directly into our RFC 8805 geofeed and active-probe verification pipeline.

**Request body** (FeedbackSubmissionRequestDto)

- `prefix_or_ip` (string, required): The IPv4/IPv6 address (`"198.51.100.7"`) or CIDR prefix (`"198.51.100.0/24"`) being reported.
- `role` (string, required): Relationship of the submitter to the reported network.
- `issue_type` (string, required): Category of the classification discrepancy.
- `requested_correction` (Record<string, unknown>, required): Non-empty JSON object describing the expected attribute values.
- `evidence_url` (string, optional): Optional URL pointing to an RFC 8805 geofeed CSV, PeeringDB entry, or RIR RDAP object.
- `contact_consent` (boolean, optional): Whether our network engineering team may contact you regarding verification.
- `contact_email` (string, optional): Optional NOC or researcher email address.

```json Example
{
  "prefix_or_ip": "198.51.100.0/24",
  "role": "network_owner",
  "issue_type": "wrong_city",
  "requested_correction": {
    "country_code": "US",
    "city": "Ashburn"
  },
  "evidence_url": "https://example.net/geofeed.csv",
  "contact_consent": true,
  "contact_email": "noc@example.net"
}
```

```bash curl
curl -sS -X POST "https://api.ipscope.io/v1/feedback" \
  -H "Authorization: Bearer $IPSCOPE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prefix_or_ip":"198.51.100.0/24","role":"network_owner","issue_type":"wrong_city","requested_correction":{"country_code":"US","city":"Ashburn"},"evidence_url":"https://example.net/geofeed.csv"}'
```

```js Node.js
const res = await fetch('https://api.ipscope.io/v1/feedback', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${process.env.IPSCOPE_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    "prefix_or_ip": "198.51.100.0/24",
    "role": "network_owner",
    "issue_type": "wrong_city",
    "requested_correction": {
      "country_code": "US",
      "city": "Ashburn"
    },
    "evidence_url": "https://example.net/geofeed.csv"
  }),
});
const data = await res.json();
```

```python Python
import os, httpx

async with httpx.AsyncClient(timeout=5.0) as client:
    res = await client.post(
        "https://api.ipscope.io/v1/feedback",
        headers={"Authorization": f"Bearer {os.environ['IPSCOPE_KEY']}"},
        json={
          "prefix_or_ip": "198.51.100.0/24",
          "role": "network_owner",
          "issue_type": "wrong_city",
          "requested_correction": {
            "country_code": "US",
            "city": "Ashburn"
          },
          "evidence_url": "https://example.net/geofeed.csv"
        },
    )
    data = res.json()
```

```go Go
req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.ipscope.io/v1/feedback", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("IPSCOPE_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
```

### 201 `FeedbackSubmissionResponse`: Correction report queued for automated geofeed & active-probe review.

- `id` (string, required): Unique identifier assigned to the feedback ticket.
- `prefix_or_ip` (string, required): Reported IP address or CIDR prefix.
- `role` (string, required): Submitter role.
- `issue_type` (string, required): Reported issue classification.
- `requested_correction` (Record<string, unknown>, required): Submitted correction attributes.
- `evidence_url` (string, optional, nullable): Supporting RFC 8805 geofeed or WHOIS URL.
- `contact_consent` (boolean, optional): Whether follow-up contact was authorized.
- `contact_email` (string, optional, nullable): Contact email address.
- `createdAt` (string, required): ISO 8601 UTC creation timestamp.
- `status` (string, required): Verification workflow status.

```json 201 FeedbackSubmissionResponse
{
  "id": "fb_01J8Z5A9M4",
  "prefix_or_ip": "198.51.100.0/24",
  "role": "network_owner",
  "issue_type": "wrong_city",
  "requested_correction": {
    "country_code": "US",
    "city": "Ashburn"
  },
  "evidence_url": "https://example.net/geofeed.csv",
  "contact_consent": true,
  "contact_email": "noc@example.net",
  "createdAt": "2026-10-27T01:15:00.000Z",
  "status": "pending_review"
}
```

### 400 `ApiError`: Invalid prefix_or_ip, unknown role/issue_type, or empty requested_correction.

- `statusCode` (integer, required): HTTP status code returned by the API gateway.
- `message` (string, required): Human-readable diagnostic message describing the error condition.
- `error` (string, required): Canonical HTTP error classification.

```json 400 ApiError
{
  "statusCode": 400,
  "message": "requested_correction must be a non-empty object",
  "error": "Bad Request"
}
```

## 3. Service liveness & snapshot status (`GET /v1/status`)

```http
GET https://api.ipscope.io/v1/status
```

Authentication: none. Plan: Public · Unmetered

Unauthenticated health check endpoint (`GET /v1/status`). Returns `status: "ok"` alongside the node’s `currentVersion` and `previousVersion` snapshot identifiers. Does not require an API key and never counts against rate limits or lookup credits.

```bash curl
curl -sS "https://api.ipscope.io/v1/status"
```

```js Node.js
const res = await fetch('https://api.ipscope.io/v1/status');
const data = await res.json();
```

```python Python
import os, httpx

async with httpx.AsyncClient(timeout=5.0) as client:
    res = await client.get(
        "https://api.ipscope.io/v1/status",
    )
    data = res.json()
```

```go Go
req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.ipscope.io/v1/status", nil)
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
```

### 200 `ServiceStatusResponse`: Node liveness and loaded snapshot versions.

- `status` (string, required): Service health indicator (`"ok"`).
- `snapshot` (SnapshotVersionState, required): Currently active and previous rollback snapshot versions in memory.
  - `currentVersion` (string, optional, nullable): Active dataset snapshot version.
  - `previousVersion` (string, optional, nullable): Previous dataset snapshot version.

```json 200 ServiceStatusResponse
{
  "status": "ok",
  "snapshot": {
    "currentVersion": "2026-10-27T00:00:00Z.crawl-1793088000000",
    "previousVersion": "2026-10-26T00:00:00Z.crawl-1793001600000"
  }
}
```
