# Collectors & datasets — QuantumProxies.io API

> Collectors & datasets endpoints of the QuantumProxies.io API with parameters, request and response examples in cURL, Python, Node.js and PHP. Part of https://quantumproxies.io/docs/index.md.

Base URL `https://api.quantumproxies.io/v1` · Auth `Authorization: Bearer qp_live_…` · HTML: https://quantumproxies.io/docs/ · OpenAPI: https://quantumproxies.io/docs/openapi.json · All endpoints: https://quantumproxies.io/docs/llms.txt · This file: https://quantumproxies.io/docs/collectors-datasets.md

_Generated from openapi.json v2026-10-07 on 2026-10-07; prices and limits as of 2026-10-07_

## Collectors

Ready-made, versioned scrapers on a semantic input; billed per delivered row. The catalog is dynamic: read it from GET /scraper/collectors.

### Collector catalog

`GET /scraper/collectors`

**Price:** No charge.  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

Every ready-made collector with its identity and version, semantic `input_schema` (JSON Schema — what to POST to `run_url`), full `output_schema`, examples, hourly health probe and YOUR price per delivered result (list price × tier discount). The catalog is the source of truth: collectors are added and versioned without an API change, so read it rather than hard-coding slugs. Free.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `category` | query | string: `search`, `seo`, `social`, `apps`, `real_estate`, `local`, `jobs`, `news`, `ecommerce`, `travel`, `leads`, `company`, `classifieds`, `finance`, `dev`, `knowledge`, `gaming`, `osint`, `research` | no | Only collectors of this category. |

#### Examples

**curl**

```bash
curl -X GET 'https://api.quantumproxies.io/v1/scraper/collectors' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY'
```

**Python (requests)**

```python
import requests

r = requests.get(
    'https://api.quantumproxies.io/v1/scraper/collectors',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/collectors", {
  method: "GET",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY"
  }
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/collectors');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY'],
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Catalog.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `503` — The Data API group is switched off for non-admin keys (early-access kill switch).

Example `200` response:

```json
{
  "type": "response",
  "message": "Collectors",
  "payload": {
    "collectors": [
      {
        "slug": "google_maps_places",
        "name": "Google Maps places",
        "version": "1.1.0",
        "category": "local",
        "category_label": "Local & Maps",
        "tagline": "Businesses for a keyword in a location — name, rating, address, phone, website, coordinates.",
        "description": "Searches Google's local results for a keyword in a location and delivers de-duplicated place records with contact and geo fields.",
        "unit": "place",
        "engines": [
          "serp"
        ],
        "price": {
          "list_usd": 0.001,
          "your_usd": 0.001,
          "price_key": "collector_google_maps_places",
          "per_1k_usd": 1,
          "min_billable_results": 0,
          "min_run_usd": 0
        },
        "max_results": 300,
        "input_schema": {
          "type": "object",
          "properties": {
            "query": {
              "type": "string",
              "title": "Keyword",
              "minLength": 2,
              "maxLength": 120,
              "examples": [
                "pizza restaurants"
              ]
            },
            "location": {
              "type": "string",
              "title": "Location",
              "minLength": 2,
              "maxLength": 120,
              "examples": [
                "Brooklyn, NY"
              ]
            },
            "country": {
              "type": "string",
              "format": "country"
            },
            "lang": {
              "type": "string",
              "format": "lang"
            },
            "max_results": {
              "type": "integer",
              "default": 20,
              "minimum": 1,
              "maximum": 300
            },
            "enrich_details": {
              "type": "boolean",
              "default": true
            }
          },
          "required": [
            "query",
            "location"
          ],
          "additionalProperties": false
        },
        "output_schema": {
          "fields": [
            {
              "name": "rank",
              "type": "integer",
              "description": "1-based position across the merged pages."
            },
            {
              "name": "name",
              "type": "string",
              "description": "Business name."
            },
            {
              "name": "rating",
              "type": "number",
              "nullable": true,
              "description": "Star rating (1–5)."
            },
            {
              "name": "place_id",
              "type": "string",
              "nullable": true,
              "description": "Google place id."
            }
          ]
        },
        "examples": [
          {
            "title": "Pizza in Brooklyn",
            "input": {
              "query": "pizza restaurants",
              "location": "Brooklyn, NY",
              "country": "us",
              "max_results": 20
            }
          }
        ],
        "health_input": {
          "query": "pizza",
          "location": "Brooklyn, NY",
          "country": "us",
          "max_results": 10
        },
        "health": {
          "status": "healthy",
          "checked_at": "2026-10-07T08:00:12.000Z",
          "latency_ms": 6210,
          "result_count": 10,
          "error": null,
          "success_rate_24h": 1,
          "last_ok_at": "2026-10-07T08:00:12.000Z"
        },
        "run_url": "/api/v1/scraper/collectors/google_maps_places/run"
      }
    ],
    "billing": {
      "enabled": true,
      "discount_multiplier": 1
    }
  },
  "pagination": {}
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `503`:

```json
{
  "type": "error",
  "message": "This API is temporarily unavailable while we finalize pricing. Contact support for early access."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

### One collector

`GET /scraper/collectors/{slug}`

**Price:** No charge.  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

The catalog entry of one collector plus its changelog and the last 24 health probes. Free.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `slug` | path | string | yes | Collector slug from the catalog. |

#### Examples

**curl**

```bash
curl -X GET 'https://api.quantumproxies.io/v1/scraper/collectors/google_maps_places' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY'
```

**Python (requests)**

```python
import requests

r = requests.get(
    'https://api.quantumproxies.io/v1/scraper/collectors/google_maps_places',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/collectors/google_maps_places", {
  method: "GET",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY"
  }
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/collectors/google_maps_places');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY'],
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Collector.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `404` — Unknown slug.
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `503` — The Data API group is switched off for non-admin keys (early-access kill switch).

Example `200` response:

```json
{
  "type": "response",
  "message": "Collector",
  "payload": {
    "collector": {
      "slug": "google_maps_places",
      "name": "Google Maps places",
      "version": "1.1.0",
      "category": "local",
      "category_label": "Local & Maps",
      "tagline": "Businesses for a keyword in a location.",
      "description": "…",
      "unit": "place",
      "engines": [
        "serp"
      ],
      "price": {
        "list_usd": 0.001,
        "your_usd": 0.001,
        "price_key": "collector_google_maps_places",
        "per_1k_usd": 1,
        "min_billable_results": 0,
        "min_run_usd": 0
      },
      "max_results": 300,
      "input_schema": {
        "type": "object",
        "properties": {},
        "required": [
          "query",
          "location"
        ],
        "additionalProperties": false
      },
      "output_schema": {
        "fields": []
      },
      "examples": [],
      "health_input": {},
      "health": {
        "status": "healthy",
        "checked_at": "2026-10-07T08:00:12.000Z",
        "latency_ms": 6210,
        "result_count": 10,
        "error": null,
        "success_rate_24h": 1,
        "last_ok_at": "2026-10-07T08:00:12.000Z"
      },
      "run_url": "/api/v1/scraper/collectors/google_maps_places/run",
      "changelog": [
        {
          "version": "1.1.0",
          "date": "2026-08-21",
          "notes": "Paginates past offset 240."
        }
      ],
      "health_history": [
        {
          "checked_at": "2026-10-07T08:00:12.000Z",
          "ok": true,
          "latency_ms": 6210,
          "result_count": 10,
          "error": null
        }
      ]
    }
  },
  "pagination": {}
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `404`:

```json
{
  "type": "error",
  "message": "Unknown collector \"foo\""
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `503`:

```json
{
  "type": "error",
  "message": "This API is temporarily unavailable while we finalize pricing. Contact support for early access."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

### Run a collector

`POST /scraper/collectors/{slug}/run`

**Price:** `collector_result` per delivered result, price by collector (see the collector price table). Per delivered row: pricing.json key `collector_<slug>` when it exists, else `collector_result`. GET /scraper/collectors returns the resolved key and your discounted price for every collector. _(list of 2026-10-07)_  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

The body is the collector's semantic input exactly as published in its `input_schema` (flat, or wrapped as `{"input": {...}}`), plus runner options: `async: true` forces background processing (also `mode: "async"` or `wait: false`). Short runs answer synchronously with the rows; long ones (the collector decides from the input size) answer 202 with a `statusUrl` to poll. Identical input re-sent inside the dedup window returns the existing run (`deduplicated: true`) — nothing new is created or charged. Per-account brakes (runs per hour, concurrent runs, failure streak) answer 429 with Retry-After. Billed per DELIVERED row at the collector's unit price × your tier discount (some collectors have a small per-run floor, see `price.min_billable_results`); zero rows = zero charge, failed runs are never billed. The worst case (unit × max_results) must be covered by free tier + balance or the run is refused with 402.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `slug` | path | string | yes | Collector slug from the catalog. |

#### Request body (required)

`Content-Type: application/json`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `async` | boolean | no | Force background processing (202 + statusUrl). Default `false`. |
| `mode` | string: `async` | no | Alias of `async: true`. |
| `wait` | boolean | no | `false` = alias of `async: true`. |
| `input` | object | no | Optional wrapper for the collector input. |

Example:

```json
{
  "query": "pizza restaurants",
  "location": "Brooklyn, NY",
  "country": "us",
  "max_results": 20
}
```

#### Examples

**curl**

```bash
curl -X POST 'https://api.quantumproxies.io/v1/scraper/collectors/google_maps_places/run' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"query":"pizza restaurants","location":"Brooklyn, NY","country":"us","max_results":20}'
```

**Python (requests)**

```python
import requests

r = requests.post(
    'https://api.quantumproxies.io/v1/scraper/collectors/google_maps_places/run',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    json={
        "query": "pizza restaurants",
        "location": "Brooklyn, NY",
        "country": "us",
        "max_results": 20
    },
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/collectors/google_maps_places/run", {
  method: "POST",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "query": "pizza restaurants",
    "location": "Brooklyn, NY",
    "country": "us",
    "max_results": 20
  })
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/collectors/google_maps_places/run');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY', 'Content-Type: application/json'],
  CURLOPT_POSTFIELDS => json_encode([
    'query' => 'pizza restaurants',
    'location' => 'Brooklyn, NY',
    'country' => 'us',
    'max_results' => 20
  ]),
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Synchronous run finished with rows.
- `202` — Run queued (or an identical run already in progress): poll `statusUrl`.
- `400` — Input does not match the collector's `input_schema` (`payload.errors`).
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `402` — The free tier plus wallet balance cannot cover the worst-case estimate of this call, or the account's monthly spend cap is reached. Nothing was run or charged.
- `404` — Unknown slug.
- `422` — Input that can never resolve (documentation placeholder, undelegated TLD) — before or after the run; retrying the same input cannot help. Not billed.
- `424` — The run failed at the source (blocked, timed out, layout changed). JSON body with `run_id` and `error`; not billed, safe to retry.
- `429` — Key/plan rate limit, or a per-account collector brake (`payload.code`: RUNS_PER_HOUR, CONCURRENT_RUNS, FAIL_STREAK, USER_PAUSED) with Retry-After.
- `503` — The Data API group is switched off for non-admin keys (early-access kill switch).

Example `200` response:

```json
{
  "type": "response",
  "message": "Collector run complete",
  "payload": {
    "run_id": "cmgfq2x1b0001",
    "slug": "google_maps_places",
    "version": "1.1.0",
    "status": "done",
    "input": {
      "query": "pizza restaurants",
      "location": "Brooklyn, NY",
      "country": "us",
      "max_results": 20
    },
    "count": 20,
    "partial": false,
    "cost": {
      "usd": 0.02,
      "unit_usd": 0.001,
      "unit": "place",
      "billed": true
    },
    "error": null,
    "results": [
      {
        "rank": 1,
        "name": "Joe's Pizza",
        "rating": 4.5,
        "reviews": 3120,
        "category": "Pizza restaurant",
        "address": "7 Carmine St, New York, NY 10014",
        "phone": "+1 212-366-1182",
        "website": "joespizzanyc.com",
        "latitude": 40.7306,
        "longitude": -74.0027,
        "place_id": "ChIJ…",
        "data_id": "0x89c259…:0x…",
        "found_by": "pizza restaurants Brooklyn, NY"
      }
    ],
    "notes": [],
    "created_at": "2026-10-07T09:20:01.000Z",
    "started_at": "2026-10-07T09:20:01.000Z",
    "finished_at": "2026-10-07T09:20:14.000Z",
    "usage": {
      "cost_usd": 0.02,
      "free_usd": 0.02,
      "paid_usd": 0
    }
  },
  "pagination": {}
}
```

Example `400`:

```json
{
  "type": "error",
  "message": "Invalid input: location is required",
  "payload": {
    "errors": [
      "location is required"
    ]
  }
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `402`:

```json
{
  "type": "error",
  "message": "Your free tier for this month is used up and your balance can't cover this call (estimated $0.002). Add pay-as-you-go credit or pick a plan — your API key stays the same: https://app.quantumproxies.io/plans?utm_source=api&utm_medium=402&utm_campaign=free-tier",
  "payload": {
    "code": "INSUFFICIENT_FUNDS",
    "balance": 0,
    "free_remaining": 0,
    "estimated_cost": 0.002,
    "plans_url": "https://app.quantumproxies.io/plans?utm_source=api&utm_medium=402&utm_campaign=free-tier",
    "billing_mode": "free_first"
  }
}
```

Example `422`:

```json
{
  "type": "error",
  "message": "Invalid input: example.com is a documentation placeholder",
  "payload": {
    "errors": [
      "example.com is a documentation placeholder"
    ],
    "error_kind": "input"
  }
}
```

Example `424`:

```json
{
  "type": "error",
  "message": "Collector run failed",
  "payload": {
    "run_id": "cmgfq2x1b0002",
    "slug": "google_maps_places",
    "version": "1.1.0",
    "status": "failed",
    "input": {},
    "count": 0,
    "partial": false,
    "cost": {
      "usd": 0,
      "unit_usd": 0.001,
      "unit": "place",
      "billed": false
    },
    "error": "source timed out after 3 attempts",
    "created_at": "2026-10-07T09:20:01.000Z",
    "started_at": "2026-10-07T09:20:01.000Z",
    "finished_at": "2026-10-07T09:21:01.000Z"
  }
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Too many collector runs this hour.",
  "payload": {
    "code": "RUNS_PER_HOUR",
    "limit": 60,
    "in_last_hour": 60,
    "retry_after": 900,
    "plan": "payg"
  }
}
```

Example `503`:

```json
{
  "type": "error",
  "message": "This API is temporarily unavailable while we finalize pricing. Contact support for early access."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

### Your collector runs

`GET /scraper/collectors/runs`

**Price:** No charge.  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

Newest first, without result rows. Page with `next_cursor`. Free.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `limit` | query | integer | no |  Default `20`. |
| `cursor` | query | string | no | `next_cursor` from the previous page. |
| `slug` | query | string | no | Only runs of this collector. |

#### Examples

**curl**

```bash
curl -X GET 'https://api.quantumproxies.io/v1/scraper/collectors/runs' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY'
```

**Python (requests)**

```python
import requests

r = requests.get(
    'https://api.quantumproxies.io/v1/scraper/collectors/runs',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/collectors/runs", {
  method: "GET",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY"
  }
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/collectors/runs');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY'],
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Runs.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `503` — The Data API group is switched off for non-admin keys (early-access kill switch).

Example `200` response:

```json
{
  "type": "response",
  "message": "Collector runs",
  "payload": {
    "runs": [
      {
        "run_id": "cmgfq2x1b0001",
        "slug": "google_maps_places",
        "version": "1.1.0",
        "status": "done",
        "input": {
          "query": "pizza restaurants",
          "location": "Brooklyn, NY"
        },
        "count": 20,
        "partial": false,
        "cost": {
          "usd": 0.02,
          "unit_usd": 0.001,
          "unit": "place",
          "billed": true
        },
        "error": null,
        "created_at": "2026-10-07T09:20:01.000Z",
        "started_at": "2026-10-07T09:20:01.000Z",
        "finished_at": "2026-10-07T09:20:14.000Z"
      }
    ],
    "next_cursor": null
  },
  "pagination": {}
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `503`:

```json
{
  "type": "error",
  "message": "This API is temporarily unavailable while we finalize pricing. Contact support for early access."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

### One run with its rows

`GET /scraper/collectors/runs/{runId}`

**Price:** No charge.  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

The run you own with its delivered results. `format=csv` streams the rows as CSV (columns follow the collector's `output_schema`). Free.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `runId` | path | string | yes | Collector run id (10–40 alphanumeric characters). |
| `format` | query | string: `csv` | no | `csv` returns a file instead of the JSON envelope. |

#### Examples

**curl**

```bash
curl -X GET 'https://api.quantumproxies.io/v1/scraper/collectors/runs/cmgfq2x1b0001' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY'
```

**Python (requests)**

```python
import requests

r = requests.get(
    'https://api.quantumproxies.io/v1/scraper/collectors/runs/cmgfq2x1b0001',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/collectors/runs/cmgfq2x1b0001", {
  method: "GET",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY"
  }
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/collectors/runs/cmgfq2x1b0001');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY'],
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Run view (JSON) or CSV file.
- `400` — Malformed run id.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `404` — Unknown id — or an id that belongs to another account (ownership failures answer 404, never 403, so ids cannot be probed).
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `503` — The Data API group is switched off for non-admin keys (early-access kill switch).

Example `200` response:

```json
{
  "type": "response",
  "message": "Collector run",
  "payload": {
    "run_id": "cmgfq2x1b0001",
    "slug": "google_maps_places",
    "version": "1.1.0",
    "status": "done",
    "input": {
      "query": "pizza restaurants",
      "location": "Brooklyn, NY",
      "country": "us",
      "max_results": 20
    },
    "count": 20,
    "partial": false,
    "cost": {
      "usd": 0.02,
      "unit_usd": 0.001,
      "unit": "place",
      "billed": true
    },
    "error": null,
    "results": [
      {
        "rank": 1,
        "name": "Joe's Pizza"
      }
    ],
    "created_at": "2026-10-07T09:20:01.000Z",
    "started_at": "2026-10-07T09:20:01.000Z",
    "finished_at": "2026-10-07T09:20:14.000Z",
    "usage": {
      "cost_usd": 0.02,
      "free_usd": 0.02,
      "paid_usd": 0
    }
  },
  "pagination": {}
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `404`:

```json
{
  "type": "error",
  "message": "Job not found"
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `503`:

```json
{
  "type": "error",
  "message": "This API is temporarily unavailable while we finalize pricing. Contact support for early access."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

## Datasets

Prompt-driven dataset builder: one prompt, a validated table.

### Your recent dataset runs

`GET /scraper/datasets`

**Price:** No charge.  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

The last 20 runs, newest first, with status reconciled against the live job for runs still marked running, the settled cost, and whether the rows are still stored. Free.

#### Examples

**curl**

```bash
curl -X GET 'https://api.quantumproxies.io/v1/scraper/datasets' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY'
```

**Python (requests)**

```python
import requests

r = requests.get(
    'https://api.quantumproxies.io/v1/scraper/datasets',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/datasets", {
  method: "GET",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY"
  }
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/datasets');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY'],
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Datasets.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `503` — The Data API group is switched off for non-admin keys (early-access kill switch).

Example `200` response:

```json
{
  "type": "response",
  "message": "Datasets",
  "payload": {
    "datasets": [
      {
        "id": "cmgf0",
        "jobId": "ds_7a1c22",
        "name": null,
        "prompt": "Car rental companies in Bologna with phone and website",
        "columns": "[{\"name\":\"company\",\"type\":\"string\"},{\"name\":\"phone\",\"type\":\"phone\"},{\"name\":\"website\",\"type\":\"url\"}]",
        "country": "it",
        "status": "completed",
        "rowCount": 42,
        "billableRows": 40,
        "refresh": false,
        "createdAt": "2026-10-06T14:02:11.000Z",
        "completedAt": "2026-10-06T14:09:40.000Z",
        "purgedAt": null,
        "costUsd": 1.86,
        "stored": true,
        "storedRows": 42,
        "storedBytes": 18311,
        "purged": false,
        "dropped": null
      }
    ]
  },
  "pagination": {}
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `503`:

```json
{
  "type": "error",
  "message": "This API is temporarily unavailable while we finalize pricing. Contact support for early access."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

### Build a dataset from a prompt

`POST /scraper/datasets`

**Price:** `dataset_row` $0.03 per call · `dataset_row_refresh` $0.01 per call. max_cost_usd charged up front, refunded down to actual spend. Actual spend = delivered validated rows × dataset_row (dataset_row_refresh on refresh) + premium field fees + metered pipeline units (serp/map/extract/AI). _(list of 2026-10-07)_  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

One plain-language prompt → a structured dataset. The service plans queries, searches, maps and scrapes, extracts the requested columns and returns validated rows; `refresh: true` re-reads a known URL set (`refreshUrls`) without discovery at a reduced row fee. Returns a job id immediately; poll `GET /scraper/datasets/{jobId}`, download the file, or pass a `webhook` (public host only, delivered after settlement with the hygiene filters applied). Billing is value-based: the run's budget `limits.max_cost_usd` (default $5, max $500, min $0.05) is charged up front and the unspent share is refunded at settlement, so you pay only for delivered, validated records (`dataset_row`, or `dataset_row_refresh` on a refresh) plus premium columns found (email, phone, deep) plus the pipeline units consumed. Low-confidence rows, off-target pages and blocked pages are never billed.

#### Request body (required)

`Content-Type: application/json`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `prompt` | string | yes | What the dataset is. |
| `columns` | array of object | no | Omit to let the planner infer columns from the prompt. |
| `columns[].name` | string | yes |  |
| `columns[].type` | string: `string`, `number`, `email`, `phone`, `url`, `boolean`, `deep` | no | `email`, `phone` and `deep` are premium (billed only when found). |
| `columns[].description` | string | no |  |
| `country` | string | no | Country code or place name: letters, digits, spaces, dots, hyphens, underscores; max 56 characters. `all` means no targeting. |
| `sources` | object | no | Domain allow/deny lists. |
| `sources.include` | array of string | no |  |
| `sources.exclude` | array of string | no |  |
| `limits` | object | no |  |
| `limits.max_rows` | integer | no |  |
| `limits.max_pages` | integer | no |  |
| `limits.max_cost_usd` | number | no |  Default `5`. |
| `webhook` | string | no | Public http(s) URL that receives the finished, filtered dataset by POST. |
| `refresh` | boolean | no |  Default `false`. |
| `refreshUrls` | array of string | no | Required with `refresh: true`. |

Example:

```json
{
  "prompt": "Car rental companies in Bologna with phone and website",
  "columns": [
    {
      "name": "company",
      "type": "string"
    },
    {
      "name": "phone",
      "type": "phone"
    },
    {
      "name": "website",
      "type": "url"
    }
  ],
  "country": "it",
  "limits": {
    "max_rows": 50,
    "max_cost_usd": 3
  }
}
```

#### Examples

**curl**

```bash
curl -X POST 'https://api.quantumproxies.io/v1/scraper/datasets' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"prompt":"Car rental companies in Bologna with phone and website","columns":[{"name":"company","type":"string"},{"name":"phone","type":"phone"},{"name":"website","type":"url"}],"country":"it","limits":{"max_rows":50,"max_cost_usd":3}}'
```

**Python (requests)**

```python
import requests

r = requests.post(
    'https://api.quantumproxies.io/v1/scraper/datasets',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    json={
        "prompt": "Car rental companies in Bologna with phone and website",
        "columns": [
            {
                "name": "company",
                "type": "string"
            },
            {
                "name": "phone",
                "type": "phone"
            },
            {
                "name": "website",
                "type": "url"
            }
        ],
        "country": "it",
        "limits": {
            "max_rows": 50,
            "max_cost_usd": 3
        }
    },
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/datasets", {
  method: "POST",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "prompt": "Car rental companies in Bologna with phone and website",
    "columns": [
      {
        "name": "company",
        "type": "string"
      },
      {
        "name": "phone",
        "type": "phone"
      },
      {
        "name": "website",
        "type": "url"
      }
    ],
    "country": "it",
    "limits": {
      "max_rows": 50,
      "max_cost_usd": 3
    }
  })
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/datasets');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY', 'Content-Type: application/json'],
  CURLOPT_POSTFIELDS => json_encode([
    'prompt' => 'Car rental companies in Bologna with phone and website',
    'columns' => [[
      'name' => 'company',
      'type' => 'string'
    ], [
      'name' => 'phone',
      'type' => 'phone'
    ], [
      'name' => 'website',
      'type' => 'url'
    ]],
    'country' => 'it',
    'limits' => [
      'max_rows' => 50,
      'max_cost_usd' => 3
    ]
  ]),
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Dataset job started.
- `400` — Malformed input. `message` names the parameter and the rule it broke.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `402` — The free tier plus wallet balance cannot cover the worst-case estimate of this call, or the account's monthly spend cap is reached. Nothing was run or charged.
- `403` — No proxy pool is available to serve the call (no house plan and no residential/datacenter/IPv6 plan on the account).
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `500` — Our side: the scraper service is unavailable or the call timed out. Never billed.
- `503` — The Data API group is off for your key, or the dataset builder is not enabled on this instance (configuration, not a transient error).

Example `200` response:

```json
{
  "type": "response",
  "message": "Dataset started",
  "payload": {
    "id": "ds_7a1c22",
    "status": "running",
    "prompt": "Car rental companies in Bologna with phone and website",
    "columns": [
      {
        "name": "company",
        "type": "string"
      },
      {
        "name": "phone",
        "type": "phone"
      },
      {
        "name": "website",
        "type": "url"
      }
    ],
    "limits": {
      "max_rows": 50,
      "max_pages": 200,
      "max_cost_usd": 3
    },
    "statusUrl": "/api/v1/scraper/datasets/ds_7a1c22",
    "usage": {
      "cost_usd": 3,
      "free_usd": 2,
      "paid_usd": 1,
      "balance": 9
    }
  },
  "pagination": {}
}
```

Example `400`:

```json
{
  "type": "error",
  "message": "Invalid format. Must be one of: markdown, html, text (or data_format markdown/screenshot, format raw)"
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `402`:

```json
{
  "type": "error",
  "message": "Your free tier for this month is used up and your balance can't cover this call (estimated $0.002). Add pay-as-you-go credit or pick a plan — your API key stays the same: https://app.quantumproxies.io/plans?utm_source=api&utm_medium=402&utm_campaign=free-tier",
  "payload": {
    "code": "INSUFFICIENT_FUNDS",
    "balance": 0,
    "free_remaining": 0,
    "estimated_cost": 0.002,
    "plans_url": "https://app.quantumproxies.io/plans?utm_source=api&utm_medium=402&utm_campaign=free-tier",
    "billing_mode": "free_first"
  }
}
```

Example `403`:

```json
{
  "type": "error",
  "message": "Scraper API is not available: no proxy credentials found. Contact support or purchase a residential, datacenter or IPv6 plan."
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `500`:

```json
{
  "type": "error",
  "message": "Scraper service unavailable. Please try again later."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

### Poll a dataset job

`GET /scraper/datasets/{jobId}`

**Price:** No charge.  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

Progress, the collection trace (`steps`) and the rows so far, filtered for you (removal list, your exclusion list, rows already delivered to you). A run the service has already forgotten (about an hour after it finishes) is served from storage (`source: storage`, no progress/steps). Free.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `jobId` | path | string | yes | Job id returned by the POST that started it. |
| `since` | query | integer | no | Row cursor from the previous poll's `nextCursor`. |
| `mode` | query | string: `summary` | no | `summary` omits rows. |

#### Examples

**curl**

```bash
curl -X GET 'https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY'
```

**Python (requests)**

```python
import requests

r = requests.get(
    'https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a", {
  method: "GET",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY"
  }
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY'],
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Job view.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `404` — Unknown id — or an id that belongs to another account (ownership failures answer 404, never 403, so ids cannot be probed).
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `500` — Our side: the scraper service is unavailable or the call timed out. Never billed.
- `503` — The Data API group is switched off for non-admin keys (early-access kill switch).

Example `200` response:

```json
{
  "type": "response",
  "message": "Dataset status",
  "payload": {
    "id": "ds_7a1c22",
    "status": "completed",
    "prompt": "Car rental companies in Bologna with phone and website",
    "columns": [
      {
        "name": "company",
        "type": "string"
      },
      {
        "name": "phone",
        "type": "phone"
      },
      {
        "name": "website",
        "type": "url"
      }
    ],
    "files": null,
    "progress": {
      "queries_run": 6,
      "sites_mapped": 12,
      "pages_scraped": 58,
      "pages_failed": 3,
      "rows": 42,
      "dropped_offtarget": 4,
      "cost_so_far_usd": 1.86
    },
    "limits": {
      "max_rows": 50,
      "max_pages": 200,
      "max_cost_usd": 3
    },
    "entity": "car rental company",
    "billable": {
      "row_fees_usd": 1.62,
      "unit_usd": 0.24
    },
    "steps": [
      {
        "phase": "plan",
        "detail": "entity: car rental company; 6 queries",
        "ts": 1759759331000
      }
    ],
    "rows": [
      {
        "fields": {
          "company": "Bologna Rent",
          "phone": "+39 051 000000",
          "website": "https://example.it"
        },
        "_source_url": "https://example.it/contatti",
        "_fetched_at": "2026-10-06T14:05:10.000Z",
        "confidence": 0.93,
        "billed_fields": [
          "phone"
        ],
        "fee_usd": 0.05
      }
    ],
    "row_count": 42,
    "billable_rows": 40,
    "nextCursor": 42,
    "createdAt": 1759759331000,
    "finishedAt": 1759759780000
  },
  "pagination": {}
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `404`:

```json
{
  "type": "error",
  "message": "Job not found"
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `500`:

```json
{
  "type": "error",
  "message": "Scraper service unavailable. Please try again later."
}
```

Example `503`:

```json
{
  "type": "error",
  "message": "This API is temporarily unavailable while we finalize pricing. Contact support for early access."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

### Cancel a dataset job

`DELETE /scraper/datasets/{jobId}`

**Price:** No charge.  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

Stops a running job you own; the unspent budget is refunded at settlement. To delete the stored record of a finished run use `DELETE /scraper/datasets/{jobId}/record`.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `jobId` | path | string | yes | Job id returned by the POST that started it. |

#### Examples

**curl**

```bash
curl -X DELETE 'https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY'
```

**Python (requests)**

```python
import requests

r = requests.delete(
    'https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a", {
  method: "DELETE",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY"
  }
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'DELETE',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY'],
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Cancelled.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `404` — Unknown id — or an id that belongs to another account (ownership failures answer 404, never 403, so ids cannot be probed).
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `500` — Our side: the scraper service is unavailable or the call timed out. Never billed.
- `503` — The Data API group is switched off for non-admin keys (early-access kill switch).

Example `200` response:

```json
{
  "type": "response",
  "message": "Dataset cancelled",
  "payload": {
    "id": "ds_7a1c22",
    "status": "cancelled"
  },
  "pagination": {}
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `404`:

```json
{
  "type": "error",
  "message": "Job not found"
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `500`:

```json
{
  "type": "error",
  "message": "Scraper service unavailable. Please try again later."
}
```

Example `503`:

```json
{
  "type": "error",
  "message": "This API is temporarily unavailable while we finalize pricing. Contact support for early access."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

### Download a dataset file

`GET /scraper/datasets/{jobId}/download`

**Price:** No charge.  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

The run's rows as CSV or JSON, partial runs included (rows collected before an interruption are delivered too). Always built from rows that passed the list-hygiene filter. 404 while the run is still going or when it produced no rows. Free.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `jobId` | path | string | yes | Job id returned by the POST that started it. |
| `format` | query | string: `csv`, `json` | no |  Default `"csv"`. |

#### Examples

**curl**

```bash
curl -X GET 'https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a/download' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY'
```

**Python (requests)**

```python
import requests

r = requests.get(
    'https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a/download',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    timeout=120,
)
r.raise_for_status()
open("response.out", "wb").write(r.content)
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a/download", {
  method: "GET",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY"
  }
});
const bytes = Buffer.from(await res.arrayBuffer());
require("node:fs").writeFileSync("response.out", bytes);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a/download');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY'],
]);
$raw = curl_exec($ch);
curl_close($ch);
file_put_contents('response.out', $raw);
```

#### Responses

- `200` — File attachment `dataset-{jobId}.csv\|json`.
- `400` — Malformed input. `message` names the parameter and the rule it broke.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `404` — Unknown job, not yours, or file not ready (run not finished or no rows).
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `500` — Our side: the scraper service is unavailable or the call timed out. Never billed.
- `503` — The Data API group is switched off for non-admin keys (early-access kill switch).

Example `200` response:

```json
{
  "columns": [
    {
      "name": "company",
      "type": "string"
    }
  ],
  "rows": [
    {
      "company": "Bologna Rent",
      "_source_url": "https://example.it/contatti"
    }
  ],
  "rowCount": 1
}
```

Example `400`:

```json
{
  "type": "error",
  "message": "Invalid format. Must be one of: markdown, html, text (or data_format markdown/screenshot, format raw)"
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `404`:

```json
{
  "type": "error",
  "message": "File not ready — the run has not finished or produced no rows"
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `500`:

```json
{
  "type": "error",
  "message": "Scraper service unavailable. Please try again later."
}
```

Example `503`:

```json
{
  "type": "error",
  "message": "This API is temporarily unavailable while we finalize pricing. Contact support for early access."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

### Rename a dataset run

`PATCH /scraper/datasets/{jobId}/record`

**Price:** No charge.  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

Sets the run's label (max 120 characters); an empty string or null clears it and the prompt becomes the label again. The prompt itself is never rewritten. Free.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `jobId` | path | string | yes | Job id returned by the POST that started it. |

#### Request body (required)

`Content-Type: application/json`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | no |  |

Example:

```json
{
  "name": "Bologna car rentals — October"
}
```

#### Examples

**curl**

```bash
curl -X PATCH 'https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a/record' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"name":"Bologna car rentals — October"}'
```

**Python (requests)**

```python
import requests

r = requests.patch(
    'https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a/record',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    json={
        "name": "Bologna car rentals — October"
    },
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a/record", {
  method: "PATCH",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "name": "Bologna car rentals — October"
  })
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a/record');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'PATCH',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY', 'Content-Type: application/json'],
  CURLOPT_POSTFIELDS => json_encode([
    'name' => 'Bologna car rentals — October'
  ]),
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Renamed.
- `400` — Malformed input. `message` names the parameter and the rule it broke.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `404` — Unknown id — or an id that belongs to another account (ownership failures answer 404, never 403, so ids cannot be probed).
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `503` — The Data API group is switched off for non-admin keys (early-access kill switch).

Example `200` response:

```json
{
  "type": "response",
  "message": "Dataset renamed",
  "payload": {
    "jobId": "ds_7a1c22",
    "name": "Bologna car rentals — October",
    "prompt": "Car rental companies in Bologna with phone and website"
  },
  "pagination": {}
}
```

Example `400`:

```json
{
  "type": "error",
  "message": "Invalid format. Must be one of: markdown, html, text (or data_format markdown/screenshot, format raw)"
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `404`:

```json
{
  "type": "error",
  "message": "Job not found"
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `503`:

```json
{
  "type": "error",
  "message": "This API is temporarily unavailable while we finalize pricing. Contact support for early access."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

### Delete a dataset run's stored record

`DELETE /scraper/datasets/{jobId}/record`

**Price:** No charge.  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

Permanently removes the record and its stored rows. A run still in flight must be cancelled first (400). Irreversible. Free.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `jobId` | path | string | yes | Job id returned by the POST that started it. |

#### Examples

**curl**

```bash
curl -X DELETE 'https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a/record' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY'
```

**Python (requests)**

```python
import requests

r = requests.delete(
    'https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a/record',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a/record", {
  method: "DELETE",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY"
  }
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/datasets/job_8f2c1a/record');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'DELETE',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY'],
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Deleted.
- `400` — The run is still running — cancel it first.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `404` — Unknown id — or an id that belongs to another account (ownership failures answer 404, never 403, so ids cannot be probed).
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `503` — The Data API group is switched off for non-admin keys (early-access kill switch).

Example `200` response:

```json
{
  "type": "response",
  "message": "Dataset deleted",
  "payload": {
    "jobId": "ds_7a1c22"
  },
  "pagination": {}
}
```

Example `400`:

```json
{
  "type": "error",
  "message": "Cancel the run before deleting it."
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `404`:

```json
{
  "type": "error",
  "message": "Job not found"
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `503`:

```json
{
  "type": "error",
  "message": "This API is temporarily unavailable while we finalize pricing. Contact support for early access."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

## Parser presets

Generate CSS selectors once with an LLM, replay them for free, let them self-heal.

### Generate CSS selectors with an LLM, once

`POST /scraper/parser/generate`

**Price:** `parser_generate` $0.02 per call. parser_generate, only when coverage > 0. _(list of 2026-10-07)_  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

Looks at a page once with a model and returns CSS selectors (`parser`) that extract the fields you asked for — ready to pass as `extract` on every later scrape of that layout, where no model is involved and the plain scrape price applies. Every selector is run against the page before it is returned: `report`, `missed` and `coverage` tell you which fields are reliable. Give `url` (fetched through the pool, `render: true` for SPA pages) or `html` you already have (max 3 MB, no proxy bandwidth). Charged once as a setup step, and only when the parser extracts something (`coverage` > 0).

#### Request body (required)

`Content-Type: application/json`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `url` | string | no | Required unless `html` is given. |
| `html` | string | no |  |
| `fields` | object | no | field name → what it is. Required unless `prompt` is given. |
| `prompt` | string | no | Free-text alternative to `fields` (the model names them). |
| `render` | boolean | no |  Default `false`. |
| `country` | string | no | Country code or place name: letters, digits, spaces, dots, hyphens, underscores; max 56 characters. `all` means no targeting. |

Example:

```json
{
  "url": "https://example.com/products/42",
  "fields": {
    "title": "product name",
    "price": "current price with currency",
    "sku": "SKU code"
  }
}
```

#### Examples

**curl**

```bash
curl -X POST 'https://api.quantumproxies.io/v1/scraper/parser/generate' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://example.com/products/42","fields":{"title":"product name","price":"current price with currency","sku":"SKU code"}}'
```

**Python (requests)**

```python
import requests

r = requests.post(
    'https://api.quantumproxies.io/v1/scraper/parser/generate',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    json={
        "url": "https://example.com/products/42",
        "fields": {
            "title": "product name",
            "price": "current price with currency",
            "sku": "SKU code"
        }
    },
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/parser/generate", {
  method: "POST",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "url": "https://example.com/products/42",
    "fields": {
      "title": "product name",
      "price": "current price with currency",
      "sku": "SKU code"
    }
  })
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/parser/generate');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY', 'Content-Type: application/json'],
  CURLOPT_POSTFIELDS => json_encode([
    'url' => 'https://example.com/products/42',
    'fields' => [
      'title' => 'product name',
      'price' => 'current price with currency',
      'sku' => 'SKU code'
    ]
  ]),
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Parser generated (message says when no usable selector could be produced; then not charged).
- `400` — Malformed input. `message` names the parameter and the rule it broke.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `402` — The free tier plus wallet balance cannot cover the worst-case estimate of this call, or the account's monthly spend cap is reached. Nothing was run or charged.
- `403` — No proxy pool is available to serve the call (no house plan and no residential/datacenter/IPv6 plan on the account).
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `500` — Our side: the scraper service is unavailable or the call timed out. Never billed.
- `503` — Data API off for your key, or the generator's model is not configured.

Example `200` response:

```json
{
  "type": "response",
  "message": "Parser generated",
  "payload": {
    "parser": {
      "title": "h1.product-title",
      "price": {
        "selector": "span.price",
        "attr": null
      },
      "sku": "dd.sku"
    },
    "report": [
      {
        "field": "title",
        "selector": "h1.product-title",
        "sample": "Trail Runner 2",
        "missed": false
      },
      {
        "field": "price",
        "selector": "span.price",
        "sample": "€ 129,00",
        "missed": false
      },
      {
        "field": "sku",
        "selector": "dd.sku",
        "sample": "TR2-42",
        "missed": false
      }
    ],
    "missed": [],
    "coverage": 1,
    "repaired": false,
    "usage": {
      "cost_usd": 0.02,
      "free_usd": 0.02,
      "paid_usd": 0
    }
  },
  "pagination": {}
}
```

Example `400`:

```json
{
  "type": "error",
  "message": "Invalid format. Must be one of: markdown, html, text (or data_format markdown/screenshot, format raw)"
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `402`:

```json
{
  "type": "error",
  "message": "Your free tier for this month is used up and your balance can't cover this call (estimated $0.002). Add pay-as-you-go credit or pick a plan — your API key stays the same: https://app.quantumproxies.io/plans?utm_source=api&utm_medium=402&utm_campaign=free-tier",
  "payload": {
    "code": "INSUFFICIENT_FUNDS",
    "balance": 0,
    "free_remaining": 0,
    "estimated_cost": 0.002,
    "plans_url": "https://app.quantumproxies.io/plans?utm_source=api&utm_medium=402&utm_campaign=free-tier",
    "billing_mode": "free_first"
  }
}
```

Example `403`:

```json
{
  "type": "error",
  "message": "Scraper API is not available: no proxy credentials found. Contact support or purchase a residential, datacenter or IPv6 plan."
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `500`:

```json
{
  "type": "error",
  "message": "Scraper service unavailable. Please try again later."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

### List your presets

`GET /scraper/parser/presets`

**Price:** No charge.  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

Every stored parser of your account with its stats and version history. Free.

#### Examples

**curl**

```bash
curl -X GET 'https://api.quantumproxies.io/v1/scraper/parser/presets' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY'
```

**Python (requests)**

```python
import requests

r = requests.get(
    'https://api.quantumproxies.io/v1/scraper/parser/presets',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/parser/presets", {
  method: "GET",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY"
  }
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/parser/presets');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY'],
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Presets.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `500` — Our side: the scraper service is unavailable or the call timed out. Never billed.
- `503` — The Data API group is switched off for non-admin keys (early-access kill switch).

Example `200` response:

```json
{
  "type": "response",
  "message": "Presets",
  "payload": {
    "presets": [
      {
        "id": "pst_7Qk3",
        "name": "example-product",
        "sourceUrl": "https://example.com/products/42",
        "fields": {
          "title": "product name",
          "price": "current price"
        },
        "render": false,
        "parser": {
          "title": "h1.product-title",
          "price": "span.price"
        },
        "version": 1,
        "autoHeal": true,
        "createdAt": 1759759331000,
        "updatedAt": 1759759331000,
        "lastHealAt": null,
        "stats": {
          "runs": 12,
          "lastRunAt": 1759830000000,
          "fields": {
            "title": {
              "hits": 12,
              "misses": 0
            },
            "price": {
              "hits": 11,
              "misses": 1
            }
          },
          "recent": [
            1,
            1,
            0.5,
            1
          ]
        },
        "history": [
          {
            "version": 1,
            "parser": {
              "title": "h1.product-title",
              "price": "span.price"
            },
            "at": 1759759331000,
            "reason": "created",
            "coverage": 1
          }
        ]
      }
    ]
  },
  "pagination": {}
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `500`:

```json
{
  "type": "error",
  "message": "Scraper service unavailable. Please try again later."
}
```

Example `503`:

```json
{
  "type": "error",
  "message": "This API is temporarily unavailable while we finalize pricing. Contact support for early access."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

### Save a parser as a preset

`POST /scraper/parser/presets`

**Price:** No charge.  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

Stores a parser (usually the one /scraper/parser/generate just returned) under a name. Scrape with `presetId` instead of an inline `extract` schema and every run is scored per field; when the recent success rate decays and `autoHeal` is on, the preset regenerates itself from `sourceUrl` and bumps its version. Ownership is server-side: a client-supplied tenant is ignored. Free to store.

#### Request body (required)

`Content-Type: application/json`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes |  |
| `parser` | object (ExtractSchema) | yes | Structured-extraction schema: field name → CSS selector, or an object with `selector`, optional `attr` (attribute to read instead of text) and `all` (true = every match as an array). |
| `sourceUrl` | string | no | Page the parser was learned from — self-healing refetches it. |
| `fields` | object | no | field → description, so a heal can regenerate the same shape. |
| `render` | boolean | no |  Default `false`. |
| `autoHeal` | boolean | no |  |

Example:

```json
{
  "name": "example-product",
  "parser": {
    "title": "h1.product-title",
    "price": "span.price"
  },
  "sourceUrl": "https://example.com/products/42",
  "fields": {
    "title": "product name",
    "price": "current price"
  },
  "autoHeal": true
}
```

#### Examples

**curl**

```bash
curl -X POST 'https://api.quantumproxies.io/v1/scraper/parser/presets' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"name":"example-product","parser":{"title":"h1.product-title","price":"span.price"},"sourceUrl":"https://example.com/products/42","fields":{"title":"product name","price":"current price"},"autoHeal":true}'
```

**Python (requests)**

```python
import requests

r = requests.post(
    'https://api.quantumproxies.io/v1/scraper/parser/presets',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    json={
        "name": "example-product",
        "parser": {
            "title": "h1.product-title",
            "price": "span.price"
        },
        "sourceUrl": "https://example.com/products/42",
        "fields": {
            "title": "product name",
            "price": "current price"
        },
        "autoHeal": true
    },
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/parser/presets", {
  method: "POST",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "name": "example-product",
    "parser": {
      "title": "h1.product-title",
      "price": "span.price"
    },
    "sourceUrl": "https://example.com/products/42",
    "fields": {
      "title": "product name",
      "price": "current price"
    },
    "autoHeal": true
  })
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/parser/presets');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY', 'Content-Type: application/json'],
  CURLOPT_POSTFIELDS => json_encode([
    'name' => 'example-product',
    'parser' => [
      'title' => 'h1.product-title',
      'price' => 'span.price'
    ],
    'sourceUrl' => 'https://example.com/products/42',
    'fields' => [
      'title' => 'product name',
      'price' => 'current price'
    ],
    'autoHeal' => true
  ]),
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Created.
- `400` — Malformed input. `message` names the parameter and the rule it broke.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `500` — Our side: the scraper service is unavailable or the call timed out. Never billed.
- `503` — The Data API group is switched off for non-admin keys (early-access kill switch).

Example `200` response:

```json
{
  "type": "response",
  "message": "Preset created",
  "payload": {
    "id": "pst_7Qk3",
    "name": "example-product",
    "sourceUrl": "https://example.com/products/42",
    "fields": {
      "title": "product name",
      "price": "current price"
    },
    "render": false,
    "parser": {
      "title": "h1.product-title",
      "price": "span.price"
    },
    "version": 1,
    "autoHeal": true,
    "createdAt": 1759759331000,
    "updatedAt": 1759759331000,
    "lastHealAt": null,
    "stats": {
      "runs": 0,
      "lastRunAt": null,
      "fields": {},
      "recent": []
    },
    "history": [
      {
        "version": 1,
        "parser": {
          "title": "h1.product-title",
          "price": "span.price"
        },
        "at": 1759759331000,
        "reason": "created"
      }
    ]
  },
  "pagination": {}
}
```

Example `400`:

```json
{
  "type": "error",
  "message": "Invalid format. Must be one of: markdown, html, text (or data_format markdown/screenshot, format raw)"
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `500`:

```json
{
  "type": "error",
  "message": "Scraper service unavailable. Please try again later."
}
```

Example `503`:

```json
{
  "type": "error",
  "message": "This API is temporarily unavailable while we finalize pricing. Contact support for early access."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

### Read a preset

`GET /scraper/parser/presets/{id}`

**Price:** No charge.  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

Parser, stats and version history. A preset belonging to someone else answers 404. Free.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Preset id returned when it was created. |

#### Examples

**curl**

```bash
curl -X GET 'https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY'
```

**Python (requests)**

```python
import requests

r = requests.get(
    'https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3", {
  method: "GET",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY"
  }
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY'],
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Preset.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `404` — Unknown id — or an id that belongs to another account (ownership failures answer 404, never 403, so ids cannot be probed).
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `500` — Our side: the scraper service is unavailable or the call timed out. Never billed.
- `503` — The Data API group is switched off for non-admin keys (early-access kill switch).

Example `200` response:

```json
{
  "type": "response",
  "message": "Preset",
  "payload": {
    "id": "pst_7Qk3",
    "name": "example-product",
    "parser": {
      "title": "h1.product-title",
      "price": "span.price"
    },
    "version": 1,
    "autoHeal": true,
    "createdAt": 1759759331000,
    "updatedAt": 1759759331000,
    "lastHealAt": null,
    "stats": {
      "runs": 12,
      "lastRunAt": 1759830000000,
      "fields": {},
      "recent": []
    },
    "history": []
  },
  "pagination": {}
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `404`:

```json
{
  "type": "error",
  "message": "Job not found"
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `500`:

```json
{
  "type": "error",
  "message": "Scraper service unavailable. Please try again later."
}
```

Example `503`:

```json
{
  "type": "error",
  "message": "This API is temporarily unavailable while we finalize pricing. Contact support for early access."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

### Update a preset

`PUT /scraper/parser/presets/{id}`

**Price:** No charge.  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

Rename, replace the parser (bumps the version), toggle `autoHeal`, update `fields`/`sourceUrl`. Only the keys you send change. Free.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Preset id returned when it was created. |

#### Request body (required)

`Content-Type: application/json`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | no |  |
| `parser` | object (ExtractSchema) | no | Structured-extraction schema: field name → CSS selector, or an object with `selector`, optional `attr` (attribute to read instead of text) and `all` (true = every match as an array). |
| `autoHeal` | boolean | no |  |
| `fields` | object | no |  |
| `sourceUrl` | string | no |  |

Example:

```json
{
  "autoHeal": false
}
```

#### Examples

**curl**

```bash
curl -X PUT 'https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"autoHeal":false}'
```

**Python (requests)**

```python
import requests

r = requests.put(
    'https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    json={
        "autoHeal": false
    },
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3", {
  method: "PUT",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "autoHeal": false
  })
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'PUT',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY', 'Content-Type: application/json'],
  CURLOPT_POSTFIELDS => json_encode([
    'autoHeal' => false
  ]),
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Updated.
- `400` — Malformed input. `message` names the parameter and the rule it broke.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `404` — Unknown id — or an id that belongs to another account (ownership failures answer 404, never 403, so ids cannot be probed).
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `500` — Our side: the scraper service is unavailable or the call timed out. Never billed.
- `503` — The Data API group is switched off for non-admin keys (early-access kill switch).

Example `200` response:

```json
{
  "type": "response",
  "message": "Preset updated",
  "payload": {
    "id": "pst_7Qk3",
    "name": "example-product",
    "parser": {
      "title": "h1.product-title",
      "price": "span.price"
    },
    "version": 1,
    "autoHeal": false,
    "createdAt": 1759759331000,
    "updatedAt": 1759840000000,
    "lastHealAt": null,
    "stats": {
      "runs": 12,
      "lastRunAt": 1759830000000,
      "fields": {},
      "recent": []
    },
    "history": []
  },
  "pagination": {}
}
```

Example `400`:

```json
{
  "type": "error",
  "message": "Invalid format. Must be one of: markdown, html, text (or data_format markdown/screenshot, format raw)"
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `404`:

```json
{
  "type": "error",
  "message": "Job not found"
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `500`:

```json
{
  "type": "error",
  "message": "Scraper service unavailable. Please try again later."
}
```

Example `503`:

```json
{
  "type": "error",
  "message": "This API is temporarily unavailable while we finalize pricing. Contact support for early access."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

### Delete a preset

`DELETE /scraper/parser/presets/{id}`

**Price:** No charge.  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

Removes the preset and its version history. Scrapes that still send its `presetId` answer 404 afterwards. Free.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Preset id returned when it was created. |

#### Examples

**curl**

```bash
curl -X DELETE 'https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY'
```

**Python (requests)**

```python
import requests

r = requests.delete(
    'https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3", {
  method: "DELETE",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY"
  }
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'DELETE',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY'],
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Deleted.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `404` — Unknown id — or an id that belongs to another account (ownership failures answer 404, never 403, so ids cannot be probed).
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `500` — Our side: the scraper service is unavailable or the call timed out. Never billed.
- `503` — The Data API group is switched off for non-admin keys (early-access kill switch).

Example `200` response:

```json
{
  "type": "response",
  "message": "Preset deleted",
  "payload": {
    "ok": true
  },
  "pagination": {}
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `404`:

```json
{
  "type": "error",
  "message": "Job not found"
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `500`:

```json
{
  "type": "error",
  "message": "Scraper service unavailable. Please try again later."
}
```

Example `503`:

```json
{
  "type": "error",
  "message": "This API is temporarily unavailable while we finalize pricing. Contact support for early access."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

### Regenerate a preset's parser now

`POST /scraper/parser/presets/{id}/heal`

**Price:** `parser_generate` $0.02 per call. parser_generate only when healed is true. _(list of 2026-10-07)_  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

The manual trigger of the repair that runs automatically when a preset decays: refetches `sourceUrl`, asks the model for fresh selectors and adopts them only if they extract more of the page than the current ones. `force: true` bypasses the cooldown between heals. Billed like a generation, and only when a new version was actually produced (`healed: true`).

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Preset id returned when it was created. |

#### Request body

`Content-Type: application/json`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `force` | boolean | no |  Default `false`. |

Example:

```json
{
  "force": false
}
```

#### Examples

**curl**

```bash
curl -X POST 'https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3/heal' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"force":false}'
```

**Python (requests)**

```python
import requests

r = requests.post(
    'https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3/heal',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    json={
        "force": false
    },
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3/heal", {
  method: "POST",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "force": false
  })
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3/heal');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY', 'Content-Type: application/json'],
  CURLOPT_POSTFIELDS => json_encode([
    'force' => false
  ]),
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Heal attempted (message says whether a new version was adopted).
- `400` — Malformed input. `message` names the parameter and the rule it broke.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `402` — The free tier plus wallet balance cannot cover the worst-case estimate of this call, or the account's monthly spend cap is reached. Nothing was run or charged.
- `404` — Unknown id — or an id that belongs to another account (ownership failures answer 404, never 403, so ids cannot be probed).
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `500` — Our side: the scraper service is unavailable or the call timed out. Never billed.
- `503` — Data API off for your key, or the generator's model is not configured.

Example `200` response:

```json
{
  "type": "response",
  "message": "Preset healed",
  "payload": {
    "healed": true,
    "reason": "coverage improved",
    "version": 2,
    "coverageBefore": 0.5,
    "coverageAfter": 1,
    "parser": {
      "title": "h1[itemprop=name]",
      "price": "span.price-now"
    },
    "usage": {
      "cost_usd": 0.02,
      "free_usd": 0.02,
      "paid_usd": 0
    }
  },
  "pagination": {}
}
```

Example `400`:

```json
{
  "type": "error",
  "message": "Invalid format. Must be one of: markdown, html, text (or data_format markdown/screenshot, format raw)"
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `402`:

```json
{
  "type": "error",
  "message": "Your free tier for this month is used up and your balance can't cover this call (estimated $0.002). Add pay-as-you-go credit or pick a plan — your API key stays the same: https://app.quantumproxies.io/plans?utm_source=api&utm_medium=402&utm_campaign=free-tier",
  "payload": {
    "code": "INSUFFICIENT_FUNDS",
    "balance": 0,
    "free_remaining": 0,
    "estimated_cost": 0.002,
    "plans_url": "https://app.quantumproxies.io/plans?utm_source=api&utm_medium=402&utm_campaign=free-tier",
    "billing_mode": "free_first"
  }
}
```

Example `404`:

```json
{
  "type": "error",
  "message": "Job not found"
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `500`:

```json
{
  "type": "error",
  "message": "Scraper service unavailable. Please try again later."
}
```

Try it: https://app.quantumproxies.io/data-api/playground

### How well a preset still works

`GET /scraper/parser/presets/{id}/stats`

**Price:** No charge.  
**Rate limit:** Per API key, by tier (see Rate limits and tiers).  
[Try it in the Playground](https://app.quantumproxies.io/data-api/playground) · [Markdown for this group](https://quantumproxies.io/docs/collectors-datasets.md)

Lifetime success rate per field, mean coverage over the recent window and whether the preset now counts as decayed (the signal that triggers self-healing). Free — it is the health check of a parser you already paid to build.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Preset id returned when it was created. |

#### Examples

**curl**

```bash
curl -X GET 'https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3/stats' \
  -H 'Authorization: Bearer qp_live_YOUR_API_KEY'
```

**Python (requests)**

```python
import requests

r = requests.get(
    'https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3/stats',
    headers={"Authorization": "Bearer qp_live_YOUR_API_KEY"},
    timeout=120,
)
data = r.json()
if data["type"] != "response":
    raise SystemExit(data["message"])
print(data["payload"])
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3/stats", {
  method: "GET",
  headers: {
    Authorization: "Bearer qp_live_YOUR_API_KEY"
  }
});
const data = await res.json();
if (data.type !== "response") throw new Error(data.message);
console.log(data.payload);
```

**PHP (curl)**

```php
<?php
$ch = curl_init('https://api.quantumproxies.io/v1/scraper/parser/presets/pst_7Qk3/stats');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer qp_live_YOUR_API_KEY'],
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);
if ($data['type'] !== 'response') { throw new RuntimeException($data['message']); }
print_r($data['payload']);
```

#### Responses

- `200` — Stats.
- `401` — Missing, malformed, unknown, disabled or expired API key; or the account is not active.
- `404` — Unknown id — or an id that belongs to another account (ownership failures answer 404, never 403, so ids cannot be probed).
- `429` — Key rate limit (hourly window), plan per-minute budget, browser-render concurrency, or pool capacity. Back off on Retry-After.
- `500` — Our side: the scraper service is unavailable or the call timed out. Never billed.
- `503` — The Data API group is switched off for non-admin keys (early-access kill switch).

Example `200` response:

```json
{
  "type": "response",
  "message": "Preset stats",
  "payload": {
    "id": "pst_7Qk3",
    "name": "example-product",
    "version": 2,
    "runs": 12,
    "lastRunAt": 1759830000000,
    "successRateByField": {
      "title": 1,
      "price": 0.917
    },
    "recentCoverage": 0.96,
    "decayed": false,
    "autoHeal": true,
    "lastHealAt": 1759840000000
  },
  "pagination": {}
}
```

Example `401`:

```json
{
  "type": "error",
  "message": "Missing or invalid Authorization header. Use: Authorization: Bearer qp_live_YOUR_API_KEY"
}
```

Example `404`:

```json
{
  "type": "error",
  "message": "Job not found"
}
```

Example `429`:

```json
{
  "type": "error",
  "message": "Rate limit exceeded. Resets in 23 minutes.",
  "payload": {
    "rateLimit": 1200,
    "requestCount": 1200,
    "resetAt": "2026-10-07T15:00:00.000Z"
  }
}
```

Example `500`:

```json
{
  "type": "error",
  "message": "Scraper service unavailable. Please try again later."
}
```

Example `503`:

```json
{
  "type": "error",
  "message": "This API is temporarily unavailable while we finalize pricing. Contact support for early access."
}
```

Try it: https://app.quantumproxies.io/data-api/playground
