Getting Started
Is Batch available to everyone?
Is Batch available to everyone?
Do I need a separate API key?
Do I need a separate API key?
What's the base URL?
What's the base URL?
https://async.api.zenrows.com/v1. Send your key in the X-API-Key header on every request.How do I integrate?
How do I integrate?
How It Works
What's the difference between a job, a run, and a task?
What's the difference between a job, a run, and a task?
What's the difference between a rerun and retrying failures?
What's the difference between a rerun and retrying failures?
How do I know when a job is done?
How do I know when a job is done?
run.completed event when the run completes (or run.failed if it fails on its own; stopping a run sends no event), delivered best effort with retries for up to 3 days, or poll the job until latest_run.status is terminal (completed, failed, or stopped) and read the stats counters (completed === successful + failed). Webhooks are a convenience; the run state remains the source of truth.Can I pause or stop a running job?
Can I pause or stop a running job?
POST /jobs/{id}/pause reversibly suspends the current run and POST /jobs/{id}/resume continues it, while POST /jobs/{id}/stop (alias POST /jobs/{id}/cancel) ends it for good. These act on the job’s current run, which is different from pausing a scheduled job’s recurring schedule. See Control the current run.My submit returned 202 instead of 201. Is that an error?
My submit returned 202 instead of 201. Is that an error?
POST /jobs returns 201 Created for fewer than 10,000 tasks and 202 Accepted for 10,000 or more, inline or from a CSV upload. Every rerun returns 202 too. The response body is identical and you track completion the same way, so treat both the same. For a large 202, GET /jobs/{id}/results may return partial pages for a few seconds while the task list finishes writing, but stats.total is correct from the start.Can I submit URLs as I go, instead of all at once?
Can I submit URLs as I go, instead of all at once?
last_batch: true. See open jobs.How many jobs can I run at the same time?
How many jobs can I run at the same time?
429 quota_exceeded. A job counts as active until you delete it, or until it’s closed and its latest run has ended, so an open job always counts. An open job that receives no tasks for 48 hours closes automatically. To run more than 3 at once, use the chat in your dashboard. Email success@zenrows.com if you can’t use the chat.Scraping Options
What scraping options can I use?
What scraping options can I use?
zenrows_params as Fetch, including js_render, premium_proxy, proxy_country, mode (auto), wait_for, wait, css_extractor, extract, extract_fields, json_response, custom_headers, and more. Set them once on the job, and override any of them per URL. Screenshot parameters aren’t supported, and an unknown key rejects the submit with 400. A task can also fetch its target with POST and a body of up to 16 KiB; see POST target fetches.Can I use different options for different URLs in the same job?
Can I use different options for different URLs in the same job?
proxy_country for a handful of URLs).Can one job include URLs from different websites?
Can one job include URLs from different websites?
What output formats are available?
What output formats are available?
response_type: markdown) and records it on each result.Results and Limits
How long are result download links valid?
How long are result download links valid?
result_url is a presigned link valid for 2 hours. If it expires, re-list the results to get a fresh one rather than storing it. You can also stream a task’s content directly, or export an entire run as a ZIP.How long are results stored, and do I need to manage storage?
How long are results stored, and do I need to manage storage?
result_url lasts 2 hours; re-list the results to get a fresh one. The result itself stays available for 14 days by default, counted from the task’s updated_at: when it finished, or when a partial rerun carried it over. After that, the task’s result row reads status: "expired" with no result_url, and its content endpoint returns 410 result_expired. The stored body is deleted automatically within 30 days of being scraped. You don’t need to delete anything to stay within storage limits. If you want to remove results sooner, you can delete a single run’s results or an entire job yourself. See Delete a job or a run.Can I delete a job or its results?
Can I delete a job or its results?
DELETE /jobs/{id}/runs/{run_id} to delete one run’s stored results while keeping the job, or DELETE /jobs/{id} to delete the whole job (all runs and results). Stopping a run only ends it and keeps the results, so use delete when you want the data removed. See Delete a job or a run.How many URLs can a job handle?
How many URLs can a job handle?
How do I match results back to my own records?
How do I match results back to my own records?
external_id to each URL. The API returns it unchanged on every result, so you can correlate results to your records without tracking the API’s task IDs. It doesn’t need to be unique, but it must use only letters, digits, ., _ and -, up to 128 characters; put free text in metadata.Can I download all results at once?
Can I download all results at once?
Scheduling
Can I run a job on a recurring schedule?
Can I run a job on a recurring schedule?
Why was my scheduled time rejected?
Why was my scheduled time rejected?
"09:00", not "09:30". Also provide exactly one schedule type (at, rate, or calendar) and a valid IANA timezone for at and calendar.Pricing
How is Batch priced?
How is Batch priced?
404 or 410. The credit cost depends on the scraping tier each URL uses.Am I charged for failed requests?
Am I charged for failed requests?
404 Not Found or 410 Gone is billed, as on Fetch, even though Batch records it as failed because it has no usable content. Other failed tasks aren’t billed. A task’s attempt history shows what each attempt was charged, and stats.spend on the run shows the total.Can I estimate the cost before running a job?
Can I estimate the cost before running a job?
How can I keep costs as low as possible?
How can I keep costs as low as possible?
mode=auto). It starts each request with the cheapest viable setup and escalates to JavaScript rendering or premium proxies only when a site actually needs them, so you pay for the lightest configuration that succeeds.Reliability and Security
What does the idempotency key do, and is it safe to retry a submit?
What does the idempotency key do, and is it safe to retry a submit?
Idempotency-Key header) makes a retry safe. It works on submits, reruns, and add-tasks calls, and lasts 24 hours. If you never saw the answer, such as after a timeout, resend the same request with the same key: the API replays the original response if the request went through, so you never get a second job, run or set of tasks. A submit or rerun the API refused, for example with 429 quota_exceeded, doesn’t use up its key, so you can fix the cause and retry with it. An add-tasks call keeps its key, so send a corrected body with a new key. The same key with a different request, or while the first attempt is still running, returns 409 idempotency_key_conflict. See Idempotency.How do I verify that a webhook really came from Zenrows?
How do I verify that a webhook really came from Zenrows?
signature: true when you attach the webhook. The API then HMAC-signs each delivery, and your receiver verifies the X-Signature header against the raw request body with your organization’s key, base64-decoded. The SDKs include a helper for it. See Verify signed webhooks.Didn’t Find Your Answer?
Check the Troubleshooting page for error-specific guidance, or reach out to support with yourjob_id, the request body (API key redacted), and the exact error code and detail.