Plans V5 (beta)
Create and edit several automatic collection plans per bot.
Endpoints
-
GET
/v5/api/bots/{bot_id}/plansList plans -
POST
/v5/api/bots/{bot_id}/plansCreate a plan (idempotency key required) -
GET
/v5/api/plans/{plan_id}One plan -
PATCH
/v5/api/plans/{plan_id}Edit only what you send -
DELETE
/v5/api/plans/{plan_id}Delete a plan (its datasets remain) -
POST
/v5/api/plans/{plan_id}/copy_settingsCopy the bot settings values -
POST
/v5/api/plans/{plan_id}/previewPreview without saving -
PUT
/v5/api/plans/{plan_id}/excelPlan-specific Excel (not supported yet)
Plan ids and which accounts have them
A plan id is a string. A plan created in plan mode is a numeric string such as "512", and the computed plan 1 of an existing bot that has no plan row yet is "one-<bot ID>" (for example one-8f3a7c1e9b5d24f6). Renaming it, changing its conditions or turning it off switches the bot to plan mode and creates a plan row, so check the id in the response and use it from then on.
For accounts where multiple plans are not open, every path on this page (and run, runs and the plan_id filter of datasets) is 404 PLAN_NOT_FOUND.
Read
The list is in screen order (plan 1 first), not in the order plans were turned on. Plan 1 has linked: true and follows the bot settings; setting its conditions separately breaks that link.
| Field | Description |
|---|---|
id | The plan id (string). |
name | The plan name. "Plan N" (in Korean) when not given at creation. |
enabled | Whether it is on. |
linked | true means it follows the bot settings. |
when | When it runs: one of the five types below. |
label, label_en | A readable sentence for when (Korean, English). |
inputs | The conditions this plan uses, { param1: value }. The bot settings values when it follows them. |
conditions | The conditions shortened to a list [{ name, value }]. |
input_mode | direct or excel. |
union | { enabled, target_dataset_id }. |
next_runs | The next five run times (while it is on). |
curl 'https://www.hashscraper.com/v5/api/bots/8f3a7c1e9b5d24f6/plans' \
-H 'Authorization: Bearer YOUR_API_KEY'{
"result": "success",
"version": "v5",
"request_id": "req_5a8c1f1c-9b2d-4e7c-9abf-3f7e0a4d1b21",
"elapsed_sec": 0.0123,
"count": 2,
"data": {
"bot_id": "8f3a7c1e9b5d24f6",
"plans": [
{
"id": "one-8f3a7c1e9b5d24f6",
"bot_id": "8f3a7c1e9b5d24f6",
"name": "주기 1",
"enabled": true,
"linked": true,
"when": {
"type": "daily",
"times": [
"09:00"
]
},
"label": "매일 09:00 (KST)",
"label_en": "Every day at 09:00 (KST)",
"inputs": {
"param1": "sneakers"
},
"conditions": [
{
"name": "Keyword",
"value": "sneakers"
}
],
"input_mode": "direct",
"union": {
"enabled": false,
"target_dataset_id": null
},
"next_runs": [
"2026-10-05T09:00:00+09:00",
"2026-10-06T09:00:00+09:00"
]
},
{
"id": "512",
"bot_id": "8f3a7c1e9b5d24f6",
"name": "주기 2",
"enabled": true,
"linked": false,
"when": {
"type": "weekly",
"every_weeks": 1,
"anchor": null,
"days": [
"mon"
],
"times": [
"09:00"
]
},
"label": "매주 월요일 09:00 (KST)",
"label_en": "Every Monday at 09:00 (KST)",
"inputs": {
"param1": "sneakers"
},
"conditions": [
{
"name": "Keyword",
"value": "sneakers"
}
],
"input_mode": "direct",
"union": {
"enabled": false,
"target_dataset_id": null
},
"next_runs": [
"2026-10-05T09:00:00+09:00",
"2026-10-12T09:00:00+09:00",
"2026-10-19T09:00:00+09:00"
]
}
]
}
}curl 'https://www.hashscraper.com/v5/api/plans/512' \
-H 'Authorization: Bearer YOUR_API_KEY'{
"result": "success",
"version": "v5",
"request_id": "req_5a8c1f1c-9b2d-4e7c-9abf-3f7e0a4d1b21",
"elapsed_sec": 0.0123,
"data": {
"id": "512",
"bot_id": "8f3a7c1e9b5d24f6",
"name": "주기 2",
"enabled": true,
"linked": false,
"when": {
"type": "weekly",
"every_weeks": 1,
"anchor": null,
"days": [
"mon"
],
"times": [
"09:00"
]
},
"label": "매주 월요일 09:00 (KST)",
"label_en": "Every Monday at 09:00 (KST)",
"inputs": {
"param1": "sneakers"
},
"conditions": [
{
"name": "Keyword",
"value": "sneakers"
}
],
"input_mode": "direct",
"union": {
"enabled": false,
"target_dataset_id": null
},
"next_runs": [
"2026-10-05T09:00:00+09:00",
"2026-10-12T09:00:00+09:00",
"2026-10-19T09:00:00+09:00"
]
}
}When it runs: five types of when
Send when as the screen values, not as an expression. Times are "HH:MM" (24-hour, KST) and you can give several.
manual and custom cannot be used for a plan. To stop a plan, turn it off with enabled: false. A bad value gives 400 INVALID_PARAM with the reason in details.errors. An old expression that the screen cannot represent reads as { "type": "custom", "editable": false } and cannot be changed through this path.
| type | Fields | Meaning |
|---|---|---|
interval | minutes | Every N minutes. |
daily | times | Every day at the given times. |
days | every_days (2 or more), anchor (start date), times | Every N days, counted from the start date. |
weekly | every_weeks (default 1), anchor, days (mon to sun), times | Every N weeks on the given weekdays. When every_weeks is 2 or more, anchor sets the reference week (this week if omitted). |
monthly | dates (1 to 31 and "last"), times | Every month on the given dates. |
{
"type": "interval",
"minutes": 10
}{
"type": "daily",
"times": [
"09:00",
"18:30"
]
}{
"type": "days",
"every_days": 3,
"anchor": "2026-10-05",
"times": [
"09:00"
]
}{
"type": "weekly",
"every_weeks": 2,
"anchor": "2026-10-05",
"days": [
"mon",
"thu"
],
"times": [
"09:00"
]
}{
"type": "monthly",
"dates": [
1,
15,
"last"
],
"times": [
"06:00"
]
}Create
Body: when (required), name ("Plan N" if omitted), inputs (filled with the current bot settings values if omitted), union (true, false or { enabled }), enabled (default true). Like plans from plan 2 on, a new plan has its own conditions from the start. On success you get 201 and the plan.
An idempotency key is required (without it you get 400 IDEMPOTENCY_KEY_REQUIRED). Resending with the same key returns the first response and does not create a second plan.
curl -X POST 'https://www.hashscraper.com/v5/api/bots/8f3a7c1e9b5d24f6/plans' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H "Idempotency-Key: $(uuidgen)" \
-H 'Content-Type: application/json' \
-d '{
"name": "Monday morning",
"when": {
"type": "weekly",
"days": [
"mon"
],
"times": [
"09:00"
]
},
"inputs": {
"param1": "sneakers"
}
}'{
"result": "success",
"version": "v5",
"request_id": "req_5a8c1f1c-9b2d-4e7c-9abf-3f7e0a4d1b21",
"elapsed_sec": 0.0123,
"data": {
"id": "512",
"bot_id": "8f3a7c1e9b5d24f6",
"name": "Monday morning",
"enabled": true,
"linked": false,
"when": {
"type": "weekly",
"every_weeks": 1,
"anchor": null,
"days": [
"mon"
],
"times": [
"09:00"
]
},
"label": "매주 월요일 09:00 (KST)",
"label_en": "Every Monday at 09:00 (KST)",
"inputs": {
"param1": "sneakers"
},
"conditions": [
{
"name": "Keyword",
"value": "sneakers"
}
],
"input_mode": "direct",
"union": {
"enabled": false,
"target_dataset_id": null
},
"next_runs": [
"2026-10-05T09:00:00+09:00",
"2026-10-12T09:00:00+09:00",
"2026-10-19T09:00:00+09:00"
]
}
}Edit
Of name, enabled, when, inputs, union and input_mode, only what you send changes (sending none gives MISSING_PARAM). input_mode accepts only direct. union.target_dataset_id must be a dataset made by this plan. Sending inputs or union for a plan that follows the bot settings breaks the link and gives it its own conditions.
curl -X PATCH 'https://www.hashscraper.com/v5/api/plans/512' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H "Idempotency-Key: $(uuidgen)" \
-H 'Content-Type: application/json' \
-d '{
"enabled": false
}'curl -X PATCH 'https://www.hashscraper.com/v5/api/plans/512' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H "Idempotency-Key: $(uuidgen)" \
-H 'Content-Type: application/json' \
-d '{
"when": {
"type": "daily",
"times": [
"07:30"
]
},
"inputs": {
"param1": "boots"
}
}'Delete
Deleting a plan keeps the datasets it made. Plan 1 (the plan that follows the bot settings, or the computed plan 1) cannot be deleted and gives 409 PLAN_UNDELETABLE. To stop it, PATCH enabled: false.
curl -X DELETE 'https://www.hashscraper.com/v5/api/plans/512' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H "Idempotency-Key: $(uuidgen)"{
"result": "success",
"version": "v5",
"request_id": "req_5a8c1f1c-9b2d-4e7c-9abf-3f7e0a4d1b21",
"elapsed_sec": 0.0123,
"data": {
"id": "512",
"deleted": true
}
}Copy bot settings values
This is "Apply to plans too" on screen. It copies the current bot settings values into a plan whose conditions are set separately. Give fields an array of field names (name, name_en) or paramN to copy only those, or omit it for every field the bot uses. copied_fields in the response lists what was actually copied. A plan that follows the bot settings already reads the same values, so nothing changes ([]).
curl -X POST 'https://www.hashscraper.com/v5/api/plans/512/copy_settings' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H "Idempotency-Key: $(uuidgen)" \
-H 'Content-Type: application/json' \
-d '{
"fields": [
"Keyword"
]
}'{
"result": "success",
"version": "v5",
"request_id": "req_5a8c1f1c-9b2d-4e7c-9abf-3f7e0a4d1b21",
"elapsed_sec": 0.0123,
"data": {
"id": "512",
"bot_id": "8f3a7c1e9b5d24f6",
"name": "주기 2",
"enabled": true,
"linked": false,
"when": {
"type": "weekly",
"every_weeks": 1,
"anchor": null,
"days": [
"mon"
],
"times": [
"09:00"
]
},
"label": "매주 월요일 09:00 (KST)",
"label_en": "Every Monday at 09:00 (KST)",
"inputs": {
"param1": "sneakers"
},
"conditions": [
{
"name": "Keyword",
"value": "sneakers"
}
],
"input_mode": "direct",
"union": {
"enabled": false,
"target_dataset_id": null
},
"next_runs": [
"2026-10-05T09:00:00+09:00",
"2026-10-12T09:00:00+09:00",
"2026-10-19T09:00:00+09:00"
],
"copied_fields": [
"param1"
]
}
}Preview
See how a when would run without saving it. Without when in the body, the plan's current value is used. You get the next count run times (1 to 20, default 5), sentences in Korean and English, and the monthly average runs_per_month. No estimated credits are returned.
curl -X POST 'https://www.hashscraper.com/v5/api/plans/512/preview' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H "Idempotency-Key: $(uuidgen)" \
-H 'Content-Type: application/json' \
-d '{
"when": {
"type": "monthly",
"dates": [
1,
15
],
"times": [
"06:00"
]
},
"count": 3
}'{
"result": "success",
"version": "v5",
"request_id": "req_5a8c1f1c-9b2d-4e7c-9abf-3f7e0a4d1b21",
"elapsed_sec": 0.0123,
"data": {
"id": "512",
"when": {
"type": "monthly",
"dates": [
1,
15
],
"times": [
"06:00"
]
},
"label": "매월 1일, 15일 06:00 (KST)",
"label_en": "Monthly on the 1st and 15th at 06:00 (KST)",
"sentence": {
"ko": "매월 1일, 15일 06:00 (KST)에 수집합니다.",
"en": "Collects monthly on the 1st and 15th at 06:00 (KST)."
},
"next_runs": [
"2026-10-15T06:00:00+09:00",
"2026-11-01T06:00:00+09:00",
"2026-11-15T06:00:00+09:00"
],
"runs_per_month": 2
}
}Plan-specific Excel
Plans that run from Excel are outside the first scope of v5. This path exists only as an address and always returns 422 EXCEL_NOT_SUPPORTED_YET.
curl -X PUT 'https://www.hashscraper.com/v5/api/plans/512/excel' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H "Idempotency-Key: $(uuidgen)" \
-F 'file=@products.xlsx'{
"result": "error",
"version": "v5",
"request_id": "req_5a8c1f1c-9b2d-4e7c-9abf-3f7e0a4d1b21",
"code": "EXCEL_NOT_SUPPORTED_YET",
"message": "Collecting with Excel input is not supported in v5 yet.",
"elapsed_sec": 0.0011
}Errors you meet when writing
| Code | HTTP | Meaning |
|---|---|---|
PLAN_CONDITION_BLOCKED | 422 | This bot cannot have its own conditions per plan. |
PLAN_NAME_TAKEN | 422 | A plan with the same name already exists. |
PLAN_UNDELETABLE | 409 | Plan 1 cannot be deleted. |
PLAN_MODE_REFUSED | 422 | This bot cannot be switched to plan mode (the reason is in details.reason; legacy_running when the old mechanism is running it). |
EXCEL_NOT_SUPPORTED_YET | 422 | Excel input is not supported yet. |
FORBIDDEN | 403 | Bots of a demo account cannot be changed. |
INVALID_PARAM | 400 | A value is wrong. See details.errors. |