Jobs
Asynchronous multi-target batches
/job List your jobs and crawls
Your jobs newest first, crawls included (type: crawl), with the same counters as
GET /job/{job_id}. Pass next_cursor back as cursor for the next page; it is absent on the
last page. Unknown status or type values match nothing.
statusstringtypestringstart_datestring400 INVALID_DATE_FORMAT.end_datestringstart_date answers 400 INVALID_DATE_RANGE.limitinteger400 INVALID_QUERY_PARAM. Default: 50.cursorstringnext_cursor of the previous page. A cursor that does not decode answers 400 INVALID_CURSOR.curl https://scraping-api.datafuel.ai/api/v1/job \ --header 'X-API-Key: df_key_your_key_here'
{ "jobs": [ { "id": "1d2c3b4a-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "type": "crawl", "status": "completed", "tasks_count": 120, "tasks_done": 120, "tasks_remaining": 0, "total_cost": 120, "created_at": "2026-09-29T10:00:00Z", "updated_at": "2026-09-29T10:04:31Z" } ] }
{ "code": "INVALID_QUERY_PARAM", "message": "limit, page and job_id must be valid values" }
{ "code": "UNAUTHORIZED", "message": "You are not authorized to perform this action" }
/job type: unlocker · asynchronous batchUnlocker
Queues a batch of targets and returns immediately with {"id": ...}.
Attribute shape matches the task variant, except the target field is plural:
urls (unlocker), prompts (llm_scraping) or queries (serp). At least two
targets are required (400 JOB_REQUIRES_MULTIPLE_TARGETS); an empty one answers
400 MISSING_TARGET. map is not a job type (400 UNSUPPORTED_TASK_TYPE) and
crawls go through POST /crawl. Every task is charged when the job is queued.
Idempotency-KeystringtypeREQUIREDstringPOST /task accepts unlocker, llm_scraping, serp and map (crawl answers 400 UNSUPPORTED_TASK_TYPE, use POST /crawl); POST /job accepts unlocker, llm_scraping and serp.proxy_typestringllm_scraping and serp.proxy_countrystringproxy_citystringproxy_statestringproxy_asnstringmultithreadedbooleanfalse.urlsREQUIREDarray<string>methodstring400 INVALID_ATTRIBUTES. Default: "GET".bodystringmethod POST, PUT or PATCH, on both
engines (js_rendering on or off).content_typestringbody. A Content-Type in headers takes precedence.headersobjectheader_orderarray<string>cookie_stringstringuser_agent_typestringuser_agentstringuser_agent_typejs_renderingbooleanredirected / final_url in the
response either way.
Default: false.js_instructionsarray<object> | objectjs_rendering only). Recommended form: an array of
single-action objects, run in order, where an action may repeat, e.g.
[{"fill": ["input[name=q]", "laptops"]}, {"click": "button[type=submit]"}, {"wait_ms": 1000}].
The older object form keyed by action ({"fill": [...], "click": "..."}) is still accepted,
but its order is not guaranteed and an action cannot repeat. The supported actions and their
argument shapes are listed by GET /config/js-instructions; actions marked iframe also
accept the iframe_ prefix. Anything else (a string, a number, an array element that is not
a single-action object, an unknown action) answers 400 INVALID_ATTRIBUTES.block_resourcestring | array<string>400 INVALID_ATTRIBUTES.wait_for_selectorstringjs_rendering only: CSS selector to wait for before capturingwait_for_selector_timeout_msintegerjs_rendering only: timeout of wait_for_selector Default: 3000.extract_selectorstringselector) or a JSON-encoded object of
name → selector for several fields. A JSON object (not a string) answers
400 INVALID_ATTRIBUTES. Append @attr to read an attribute instead of the text.
The result is {"data": {name: [values...]}} and result_format is forced to json.extract_regexstringregex) or a JSON-encoded object of name → pattern. The first capture group is returned when
present, otherwise the whole match; all matches are collected as a list.result_formatstringhtml: raw page. markdown: cleaned text with a title/meta header,
best for LLMs. json: schema.org / JSON-LD and embedded JSON objects.
png / jpeg: full-page screenshot, base64; needs js_rendering: true
(the request engine returns html instead).
Default: "html".result_templatestringinclude_imagesbooleanfalse drops  images (and the links that
only wrapped them); signed image URLs often dominate the token
count of a listing page. The MCP server defaults this to false.
Default: true.main_content_onlyboolean<main> / <article> container when the page has one. Default: false.result_use_aibooleanresult_ai_formatobjectresult_ai_promptstringai_providerstringai_modelstringai_api_keystringproxy_session_idstringproxy_ttlintegerproxy_typestringproxy_type. Set the plan at the top level; that is the one that is billed.proxy_countrystringproxy_countryproxy_citystringproxy_cityproxy_statestringproxy_stateproxy_asnstringproxy_asncurl https://scraping-api.datafuel.ai/api/v1/job \ --request POST \ --header 'Content-Type: application/json' \ --header 'X-API-Key: df_key_your_key_here' \ --data '{ "type": "unlocker", "multithreaded": true, "proxy_type": "Basic", "attributes": { "urls": [ "https://example.com/product/1", "https://example.com/product/2" ], "method": "GET", "js_rendering": false } }'
{ "id": "9f1d3c2a-4b6e-4f8a-9c7d-2e5b8a1f0d43" }
{ "code": "INVALID_ATTRIBUTES", "message": "Invalid attributes for selected task type" }
{ "code": "UNAUTHORIZED", "message": "You are not authorized to perform this action" }
{ "code": "INSUFFICIENT_CREDITS", "message": "You do not have enough credits to perform this action" }
{ "code": "TASK_ALREADY_EXISTS", "message": "A task with this id already exists; retry the request" }
{ "code": "IDEMPOTENCY_KEY_REUSED", "message": "Idempotency-Key was already used for a different request" }
{ "code": "ENGINE_UNAVAILABLE", "message": "This engine is switched off at the moment: temporarily unavailable" }
/job type: llm_scraping · asynchronous batchLLM scraping
Queues a batch of targets and returns immediately with {"id": ...}.
Attribute shape matches the task variant, except the target field is plural:
urls (unlocker), prompts (llm_scraping) or queries (serp). At least two
targets are required (400 JOB_REQUIRES_MULTIPLE_TARGETS); an empty one answers
400 MISSING_TARGET. map is not a job type (400 UNSUPPORTED_TASK_TYPE) and
crawls go through POST /crawl. Every task is charged when the job is queued.
Idempotency-KeystringtypeREQUIREDstringPOST /task accepts unlocker, llm_scraping, serp and map (crawl answers 400 UNSUPPORTED_TASK_TYPE, use POST /crawl); POST /job accepts unlocker, llm_scraping and serp.proxy_typestringllm_scraping and serp.proxy_countrystringproxy_citystringproxy_statestringproxy_asnstringmultithreadedbooleanfalse.promptsREQUIREDarray<string>engineREQUIREDstringGET /config/capabilities.websearchbooleanfollow_up_promptstringproxy_countrystringproxy_countrylocationstringresult_formatstringjson.curl https://scraping-api.datafuel.ai/api/v1/job \ --request POST \ --header 'Content-Type: application/json' \ --header 'X-API-Key: df_key_your_key_here' \ --data '{ "type": "llm_scraping", "multithreaded": true, "attributes": { "prompts": [ "best CRM tools for startups 2026", "top project management software 2026" ], "engine": "perplexity", "websearch": true } }'
{ "id": "9f1d3c2a-4b6e-4f8a-9c7d-2e5b8a1f0d43" }
{ "code": "INVALID_ATTRIBUTES", "message": "Invalid attributes for selected task type" }
{ "code": "UNAUTHORIZED", "message": "You are not authorized to perform this action" }
{ "code": "INSUFFICIENT_CREDITS", "message": "You do not have enough credits to perform this action" }
{ "code": "TASK_ALREADY_EXISTS", "message": "A task with this id already exists; retry the request" }
{ "code": "IDEMPOTENCY_KEY_REUSED", "message": "Idempotency-Key was already used for a different request" }
{ "code": "ENGINE_UNAVAILABLE", "message": "This engine is switched off at the moment: temporarily unavailable" }
/job type: serp · asynchronous batchSERP
Queues a batch of targets and returns immediately with {"id": ...}.
Attribute shape matches the task variant, except the target field is plural:
urls (unlocker), prompts (llm_scraping) or queries (serp). At least two
targets are required (400 JOB_REQUIRES_MULTIPLE_TARGETS); an empty one answers
400 MISSING_TARGET. map is not a job type (400 UNSUPPORTED_TASK_TYPE) and
crawls go through POST /crawl. Every task is charged when the job is queued.
Idempotency-KeystringtypeREQUIREDstringPOST /task accepts unlocker, llm_scraping, serp and map (crawl answers 400 UNSUPPORTED_TASK_TYPE, use POST /crawl); POST /job accepts unlocker, llm_scraping and serp.proxy_typestringllm_scraping and serp.proxy_countrystringproxy_citystringproxy_statestringproxy_asnstringmultithreadedbooleanfalse.queriesREQUIREDarray<string>countrystringgl), e.g. us, gb, fr.languagestringhl), e.g. en, en-gb, es-419.pageinteger(page-1) * 10 (start). Default: 1.google_domainstringgoogle.co.uk (a leading www. is dropped). Default google.com; pooled per domain.locationstringuule. Exclusive with
uule and lat/lon. Google may still place the local pack by the exit IP.uulestringlocation, lat/lon.latnumberlon.lonnumberlat.radiusintegerlocation, uule or lat/lon.crstring|-delimited upper-case codes, e.g. countryFR|countryDE.lrstring|-delimited, e.g. lang_fr|lang_de.tbsstringsafestringactive filters explicit content, off disables.nfprbooleantrue excludes auto-corrected-query results (served via Google's own link).filterbooleantrue on (default); sends 0 only when explicitly false.udsstringkgmidstringsistringludocidstringlsigstringibpstringgwp;0,7.proxy_countrystringcountry and language to target results.result_formatstringjson structured results, markdown LLM-optimized, html raw served page. Default: "json".curl https://scraping-api.datafuel.ai/api/v1/job \ --request POST \ --header 'Content-Type: application/json' \ --header 'X-API-Key: df_key_your_key_here' \ --data '{ "type": "serp", "multithreaded": true, "proxy_country": "US", "attributes": { "queries": [ "best CRM tools for startups 2026", "top project management software 2026" ], "country": "us", "language": "en" } }'
{ "id": "9f1d3c2a-4b6e-4f8a-9c7d-2e5b8a1f0d43" }
{ "code": "INVALID_ATTRIBUTES", "message": "Invalid attributes for selected task type" }
{ "code": "UNAUTHORIZED", "message": "You are not authorized to perform this action" }
{ "code": "INSUFFICIENT_CREDITS", "message": "You do not have enough credits to perform this action" }
{ "code": "TASK_ALREADY_EXISTS", "message": "A task with this id already exists; retry the request" }
{ "code": "IDEMPOTENCY_KEY_REUSED", "message": "Idempotency-Key was already used for a different request" }
{ "code": "ENGINE_UNAVAILABLE", "message": "This engine is switched off at the moment: temporarily unavailable" }
/job/{job_id} Get job progress
job_idREQUIREDstringcurl https://scraping-api.datafuel.ai/api/v1/job/{job_id} \ --header 'X-API-Key: df_key_your_key_here'
{ "status": "processing", "tasks_count": 50, "tasks_done": 32, "tasks_remaining": 18, "total_cost": 64 }
{ "code": "UNAUTHORIZED", "message": "You are not authorized to perform this action" }
{ "code": "JOB_NOT_FOUND", "message": "Job not found" }
/job/{job_id}/results Get job results
job_idREQUIREDstringcurl https://scraping-api.datafuel.ai/api/v1/job/{job_id}/results \ --header 'X-API-Key: df_key_your_key_here'
{ "tasks_count": 50, "tasks_failed": 1, "tasks_complete": 49, "tasks_result": [ { "id": "0c6f1f9e-2b3a-4c5d-8e9f-1a2b3c4d5e6f", "status": "completed", "status_code": 200, "credits_used": 1, "result": { "data": "# Example Domain\n\nThis domain is for use in documentation examples." } }, { "id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a", "status": "failed", "blocked": true, "status_code": 403, "credits_used": 0, "result": { "status": "failed", "error_detail": "target answered 403 (anti-bot)", "status_code": 403 } } ] }
{ "code": "UNAUTHORIZED", "message": "You are not authorized to perform this action" }
{ "code": "JOB_NOT_FOUND", "message": "Job not found" }
/job/{job_id}/cancel Cancel a job
Stops the job. Tasks that have not started yet fail and their credits are
refunded right away; tasks already running finish and are billed as usual.
The job ends with status cancelled. Cancelling a cancelled job is a no-op
and returns 200; a job that already finished returns 409.
job_idREQUIREDstringcurl https://scraping-api.datafuel.ai/api/v1/job/{job_id}/cancel \ --request POST \ --header 'X-API-Key: df_key_your_key_here'
{ "status": "cancelled", "tasks_count": 50, "tasks_done": 32, "tasks_remaining": 0, "total_cost": 64, "refunded_tasks": 18, "refunded_credits": 18 }
{ "code": "UNAUTHORIZED", "message": "You are not authorized to perform this action" }
{ "code": "JOB_NOT_FOUND", "message": "Job not found" }
{ "code": "JOB_NOT_CANCELLABLE", "message": "The job already finished and cannot be cancelled" }