Quickstart V5 (beta)

From finding a bot to downloading data. Finish your first collection in five minutes.

v5 splits resources using the same words as the product screens: bots, settings, plans and datasets. A bot can have several plans, and a dataset tells you whether it was collected manually or by which plan, and with which inputs. Replace only YOUR_API_KEY and the commands below work as they are.

Using v4 today? Start with Moving from v4 to v5. v4 keeps working as it is.

A machine-readable spec is available as OpenAPI (JSON).

Want to try the paths before signing up? Import this OpenAPI address into an API tool such as Postman or Insomnia. Every path is filled in, so after you sign up you only add your key to start calling.

  1. Copy your API key

    Copy the key from My info → API key. It is the same key as v4. Send it in the Authorization header of every request as Bearer YOUR_API_KEY.

    Treat the key like a password. Never expose it in a code repository or a shared screen.

    Sign up free and get an API key

    After signing up, your key is under My info → API key. Already have an account? Log in.

  2. Check the connection

    GET

    GET /v5/api/health is a status check that needs no key. GET /v5/api/me returns the account the key belongs to.

    Example request
    curl 'https://www.hashscraper.com/v5/api/health'
    Example response 200
    {
      "result": "success",
      "version": "v5",
      "request_id": "req_5a8c1f1c-9b2d-4e7c-9abf-3f7e0a4d1b21",
      "elapsed_sec": 0.0123,
      "data": {
        "status": "ok",
        "time": "2026-10-04T09:00:00+09:00"
      }
    }
    Example request
    curl 'https://www.hashscraper.com/v5/api/me' \
      -H 'Authorization: Bearer YOUR_API_KEY'
    Example response 200
    {
      "result": "success",
      "version": "v5",
      "request_id": "req_5a8c1f1c-9b2d-4e7c-9abf-3f7e0a4d1b21",
      "elapsed_sec": 0.0123,
      "data": {
        "email": "dev@example.com",
        "name": "Sample User"
      }
    }

    If you see "result": "success" and your email, you are ready. On 401, copy the key again.

  3. Pick a bot

    GET

    List your bots and pick the id of the one to collect with. You can also copy it from the bot detail screen with More → Copy bot ID.

    Example request
    curl 'https://www.hashscraper.com/v5/api/bots' \
      -H 'Authorization: Bearer YOUR_API_KEY'
    Example response 200
    {
      "result": "success",
      "version": "v5",
      "request_id": "req_5a8c1f1c-9b2d-4e7c-9abf-3f7e0a4d1b21",
      "elapsed_sec": 0.0123,
      "count": 1,
      "next_cursor": null,
      "data": [
        {
          "id": "8f3a7c1e9b5d24f6",
          "name": "Sample shopping bot",
          "description": "Collects product lists by keyword.",
          "schedule_group": null,
          "union": false,
          "created_at": "2026-08-12T10:21:05+09:00",
          "updated_at": "2026-10-01T18:02:40+09:00",
          "worker_source": {
            "name": "Shopping list",
            "version": 12,
            "updated_at": "2026-09-20T11:00:00+09:00",
            "price": 5
          },
          "credit_per_item": 5,
          "plans_count": 2,
          "active_plans": [
            {
              "id": "512",
              "name": "주기 2",
              "label": "매주 월요일 09:00 (KST)"
            }
          ],
          "period_summary": "주기 2 · 매주 월요일 09:00 (KST)",
          "next_run_at": "2026-10-05T09:00:00+09:00",
          "latest_dataset": {
            "id": 239758028,
            "status": "done",
            "data_count": 1280,
            "trigger": "period",
            "created_at": "2026-09-28T09:00:03+09:00"
          }
        }
      ]
    }

    data[].id is the bot ID. Use it in the path of the next steps.

  4. Check the inputs

    GET

    See which inputs the bot takes (keyword, sort and so on). The key (or alias) of each entry in inputs is the name to use in inputs when you collect, and for fields with options pick one of the listed values.

    Example request
    curl 'https://www.hashscraper.com/v5/api/bots/8f3a7c1e9b5d24f6/inputs' \
      -H 'Authorization: Bearer YOUR_API_KEY'
    Example response 200
    {
      "result": "success",
      "version": "v5",
      "request_id": "req_5a8c1f1c-9b2d-4e7c-9abf-3f7e0a4d1b21",
      "elapsed_sec": 0.0123,
      "data": {
        "bot_id": "8f3a7c1e9b5d24f6",
        "excel_supported": true,
        "inputs": [
          {
            "key": "param1",
            "name": "Keyword",
            "name_en": "Keyword",
            "alias": "keyword",
            "type": "text",
            "required": true,
            "options": [],
            "excel_supported": true
          }
        ]
      }
    }

    Each field the bot uses shows its key, name and options.

  5. Start a collection

    POST

    Start a collection on the bot you picked. Starting a collection requires an idempotency key (the Idempotency-Key header). Create a new key for every request (the $(uuidgen) in the example above) and reuse the same key only when you resend after a dropped connection. See Idempotency key for the rules.

    save_to_settings defaults to true: the inputs you send are saved to the bot settings and used for this collection. Send false to use them for this one collection only.

    Example request
    curl -X POST 'https://www.hashscraper.com/v5/api/bots/8f3a7c1e9b5d24f6/collections' \
      -H 'Authorization: Bearer YOUR_API_KEY' \
      -H "Idempotency-Key: $(uuidgen)" \
      -H 'Content-Type: application/json' \
      -d '{
      "inputs": {
        "param1": "sneakers"
      }
    }'
    Example response 200
    {
      "result": "success",
      "version": "v5",
      "request_id": "req_5a8c1f1c-9b2d-4e7c-9abf-3f7e0a4d1b21",
      "elapsed_sec": 0.0123,
      "data": {
        "id": 239758028,
        "bot": {
          "id": "8f3a7c1e9b5d24f6",
          "name": "Sample shopping bot"
        },
        "status": "running",
        "data_count": 0,
        "union": false,
        "trigger": "api",
        "credits_used": 0,
        "created_at": "2026-10-04T09:00:02+09:00",
        "updated_at": "2026-10-04T09:00:02+09:00",
        "plan": null,
        "inputs": {
          "param1": {
            "name": "Keyword",
            "value": "sneakers"
          }
        },
        "started_at": "2026-10-04T09:00:02+09:00",
        "elapsed_sec": 3,
        "saved_to_settings": true,
        "plans_affected": []
      }
    }

    data.id is the number of this collection (dataset). Credits are used for each row the collection saves (Credits & rate limits).

  6. Wait until it finishes

    GET

    Collections run in the background. Check the status every 10 to 30 seconds. Depending on the site and volume it takes from tens of seconds to tens of minutes.

    Example request
    curl 'https://www.hashscraper.com/v5/api/datasets/239758028' \
      -H 'Authorization: Bearer YOUR_API_KEY'
    Example response 200
    {
      "result": "success",
      "version": "v5",
      "request_id": "req_5a8c1f1c-9b2d-4e7c-9abf-3f7e0a4d1b21",
      "elapsed_sec": 0.0123,
      "data": {
        "id": 239758028,
        "bot": {
          "id": "8f3a7c1e9b5d24f6",
          "name": "Sample shopping bot"
        },
        "status": "done",
        "data_count": 1280,
        "union": false,
        "trigger": "api",
        "credits_used": 6400,
        "created_at": "2026-10-04T09:00:02+09:00",
        "updated_at": "2026-10-04T09:00:02+09:00",
        "plan": null,
        "inputs": {
          "param1": {
            "name": "Keyword",
            "value": "sneakers"
          }
        },
        "started_at": "2026-10-04T09:00:02+09:00",
        "elapsed_sec": 94
      }
    }

    When status is done it has finished. waiting, running and retrying are in progress. failed and canceled have ended without collecting everything. attention needs a look (finished with a notice, or stalled).

  7. Download the data

    GET

    Download the data of the finished dataset. It arrives limit rows at a time. Pass the response next_cursor as the cursor of the next request to continue.

    Example request
    curl 'https://www.hashscraper.com/v5/api/datasets/239758028/results?limit=1000' \
      -H 'Authorization: Bearer YOUR_API_KEY'
    Example response 200
    {
      "result": "success",
      "version": "v5",
      "request_id": "req_5a8c1f1c-9b2d-4e7c-9abf-3f7e0a4d1b21",
      "elapsed_sec": 0.0123,
      "count": 1,
      "next_cursor": null,
      "data": [
        {
          "id": 91000001,
          "created_at": "2026-10-04T09:00:40+09:00",
          "updated_at": "2026-10-04T09:00:40+09:00",
          "title": "Sneakers A",
          "price": "59000"
        }
      ]
    }

    When next_cursor is null you have the last page.

Common rules

  • Address — every path lives under https://www.hashscraper.com/v5/api.
  • Authentication — Authorization: Bearer <API key>. Only health works without a key.
  • Time — ISO 8601 in the Korea time zone (+09:00).
  • Credits — integers.
  • Plan id — always a string ("512"). Do not compare it as a number.
  • Request ID — send X-Request-ID: req_... and it is echoed back, otherwise the server makes one. Include it when you contact us.
Response fieldDescription
resultsuccess or error. Bulk collection, which handles several items at once, can also return partial_success and failure.
versionAlways v5.
request_idThe request ID.
elapsed_secSeconds taken to build the response.
dataThe result: an array for lists, an object for a single item. Fields always have the same shape; missing values arrive as null or an empty array instead of being left out.
count, next_cursorList responses only: how many items arrived and the marker for the next page (null when there is none).

Paging through lists

Lists arrive limit items at a time (default 100, maximum 1000). Pass the response next_cursor unchanged as the cursor of the next request. null means you are done. Do not change conditions such as sorting while paging.

The whole flow at once (Python · Node.js)

Steps 5–7 above (start a collection → wait until it ends → download the data) joined into one script. Replace YOUR_API_KEY and the bot ID, and change inputs to the input fields of that bot from step 4 (GET /bots/{bot_id}/inputs) — the example param1: "sneakers" fits a bot with one keyword field. This example sends save_to_settings: false, so the bot settings stay as they are. A bot that cannot run with one-off inputs answers 422 PLAN_CONDITION_BLOCKED; in that case send without that field.

For when and how many credits are used, and how many calls you can make per minute, see Credits & rate limits.

Python example
import time
import uuid
import requests

BASE = "https://www.hashscraper.com/v5/api"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}
BOT_ID = "8f3a7c1e9b5d24f6"

# 1. start a collection (a new Idempotency-Key for every new request)
res = requests.post(
    f"{BASE}/bots/{BOT_ID}/collections",
    headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())},
    json={"inputs": {"param1": "sneakers"}, "save_to_settings": False},  # this run only
    timeout=30,
)
res.raise_for_status()
dataset_id = res.json()["data"]["id"]

# 2. wait until it ends (check every 20 seconds)
while True:
    dataset = requests.get(f"{BASE}/datasets/{dataset_id}", headers=HEADERS, timeout=30).json()["data"]
    if dataset["status"] in ("done", "attention", "failed", "canceled"):  # attention = ended with a notice, or stalled
        break
    time.sleep(20)
print(dataset["status"], dataset["data_count"], "rows", dataset["credits_used"], "credits")

# 3. download every row (until next_cursor is null)
rows, cursor = [], None
while True:
    params = {"limit": 1000, **({"cursor": cursor} if cursor else {})}
    page = requests.get(f"{BASE}/datasets/{dataset_id}/results", headers=HEADERS, params=params, timeout=60).json()
    rows.extend(page["data"])
    cursor = page["next_cursor"]
    if cursor is None:
        break
print(len(rows), "rows downloaded")
Node.js example
// Node.js 18+ (built-in fetch)
const { randomUUID } = require("node:crypto");
const BASE = "https://www.hashscraper.com/v5/api";
const HEADERS = { Authorization: "Bearer YOUR_API_KEY" };
const BOT_ID = "8f3a7c1e9b5d24f6";
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function call(method, path, { body, query } = {}) {
  const url = new URL(BASE + path);
  for (const [k, v] of Object.entries(query ?? {})) if (v != null) url.searchParams.set(k, v);
  const headers = { ...HEADERS };
  if (method !== "GET") headers["Idempotency-Key"] = randomUUID(); // a new key for every new request
  if (body) headers["Content-Type"] = "application/json";
  const res = await fetch(url, { method, headers, body: body ? JSON.stringify(body) : undefined });
  if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
  return res.json();
}

async function main() {
  // 1. start a collection
  const started = await call("POST", `/bots/${BOT_ID}/collections`, {
    body: { inputs: { param1: "sneakers" }, save_to_settings: false }, // this run only
  });
  const datasetId = started.data.id;

  // 2. wait until it ends (check every 20 seconds)
  let dataset;
  for (;;) {
    dataset = (await call("GET", `/datasets/${datasetId}`)).data;
    if (["done", "attention", "failed", "canceled"].includes(dataset.status)) break; // attention = ended with a notice, or stalled
    await sleep(20000);
  }
  console.log(dataset.status, dataset.data_count, "rows", dataset.credits_used, "credits");

  // 3. download every row (until next_cursor is null)
  const rows = [];
  let cursor = null;
  do {
    const page = await call("GET", `/datasets/${datasetId}/results`, { query: { limit: 1000, cursor } });
    rows.push(...page.data);
    cursor = page.next_cursor;
  } while (cursor !== null);
  console.log(rows.length, "rows downloaded");
}

main().catch((err) => {
  console.error(err.message);
  process.exitCode = 1;
});

Related guides