All integrations

ZenRows

DEVELOPER · DEVELOPER

Pages fetched through the proxy, batch scraping jobs, and the plan behind their key.

Connect ZenRows with Fabriq Developer

Your user pastes their ZenRows credential on a page Agentic Fabriq hosts, so it never reaches your backend and never becomes one shared key across all of your users. Same call as OAuth, one more argument.

from af_sdk import AgenticFabriq

af = AgenticFabriq()                      # reads AF_APP_ID / AF_APP_SECRET

url = await af.initiate_connection(request, provider="zen_rows", method="api_key")
return redirect(url)                      # an AF-hosted page, not yours

async with await af.for_user(request) as session:
    tools = await session.get_tools()     # only what this user granted

Provider names are surfaces, not vendors, and the authoritative list is the capabilities endpoint rather than any page including this one — an unknown name returns 400 with the valid list. Fabriq Developer is free to start and needs no provider paperwork. Start free or read the quickstart.

Connecting ZenRows in practice

ZenRows prices one request between 1 and 25 credits depending on what you turn on — 1 standard, 5 for JavaScript rendering, 10 for premium proxies, 25 for both — so a single flag change makes a crawl 25 times more expensive. Concurrency is a hard ceiling rather than a rate: on the Free tier the sixth simultaneous request 429s immediately, however slowly you are pacing.

Rate limits

  • Concurrency by tier: Free 5, Build 20, Launch 50, Growth 100, Scale 200, Enterprise custom from 400 to 1,000+.
  • Credit weights per successful request: standard 1, JavaScript Rendering 5, Premium Proxies 10, JS Rendering plus Premium Proxies 25. These weights are fixed on every plan.
  • Residential Proxies and Browser Sessions bandwidth meters at 25,000 credits per GB; Browser Sessions add 5 credits per minute of session time.
  • Maximum response size per tier: Free 10 MB, Build 5 MB, Launch 10 MB, Growth 10 MB, Scale 20 MB.

Worth knowing

  • A 429 here means you are out of concurrent slots, not out of requests per minute, so backoff has to be driven by in-flight count rather than by a timer.
  • You are charged only for successful requests, and HTTP 404 and 410 count as successful because the request completed and returned valid data.
  • The Build tier caps a single response at 5 MB — lower than the Free tier’s 10 MB — so upgrading from Free can shrink the largest page you can fetch.
  • One shared credit balance covers Fetch, Extract, Batch and Browser Sessions, so a runaway browser session drains the budget for scraping.

Checked against ZenRows pricing (credit multipliers, concurrency, response size) (2026-09-29), Concurrency (2026-09-29)

Acts as the person, not as itself

Each user connects their own account. Every call carries both identities — the agent and the person it is acting for — so the agent can never reach past what that individual can already do.

Credentials never touch the agent

Tokens live in the vault and attach server-side at call time. The agent holds a session, not a secret, and revoking access does not mean rotating a key.

Every call on the record

Who asked, which agent acted, which action ran, and the verdict that let it through — one audit trail across every integration, not one per vendor.

What an agent can do

Each action is granted on its own. An agent allowed to read is not thereby allowed to write, and the scope beside each row is what the acting user must have connected for it to run at all.

zen_rows_delete_hmac_keys_rotateWRITE

Discard the PENDING webhook signing key and keep signing with the current one. The pending key is destroyed with no undo -- starting over means another Start a key rotation -- but no delivery breaks, because the key in use does not change. Answers 204 with no body via DELETE /hmac/keys/rotate

api
zen_rows_delete_jobs_by_job_id_runs_by_run_idWRITE

Delete one run of a Batch job AND the results it holds. There is no undo and no trash: re-collecting the data means rerunning the job, which spends credits again. Answers 204 with no body via DELETE /jobs/{job_id}/runs/{run_id}

api
zen_rows_delete_jobs_by_job_id_webhookWRITE

Stop delivering this Batch job's results to a webhook. Deliveries already made are not recalled, and results stay readable through Read a job's results. REVERSIBLE: set it again with Set a job's webhook. Answers 204 with no body via DELETE /jobs/{job_id}/webhook

api
zen_rows_getREAD

Retrieve one URL through ZenRows and return its content. One request covers the whole Universal Scraper surface, because these are configurations rather than separate endpoints: `js_render` runs a headless browser, `premium_proxy` plus `proxy_country` picks a residential exit IP, `response_type=markdown|plaintext|pdf` converts the page, `screenshot`/`screenshot_fullpage` return an image, and `extract=auto`, `css_extractor`, `autoparse` and `outputs` return structured JSON instead of markup. EVERY CALL SPENDS CREDITS and the cost depends on the configuration that succeeds, so `mode=auto` (escalate only when the target needs it) is the cheapest way to fetch a protected page. A non-JSON reply comes back as `{content_type, text}`, and a PDF or screenshot as `{content_type, content_base64}`; anything over 4 MB is refused rather than truncated -- use a Batch job with a webhook for bulk. For many URLs use Create a batch job instead of calling this in a loop via GET /

api
zen_rows_get_api_agent_accountREAD

Report the claim state of the connected account: its id, whether a person has taken ownership (`claimed`), whether it was created by ZenRows' anonymous agent signup (`isAgent`) and when a trial allowance ends. Claiming does not rotate the key, so this is how a long-running connection learns a human took over. It never returns an email or any secret. This is the only tool served from app.zenrows.com and it is the endpoint a pasted key would be probed against via GET /api/agent/account

api
zen_rows_get_hmac_keysREAD

The HMAC keys ZenRows signs this account's webhook deliveries with, so a receiver can verify them. These are the account's own webhook-verification secrets; they are not the API key and cannot be used to call this API via GET /hmac/keys

api
zen_rows_get_jobsREAD

Page through the Batch jobs on the account, newest first. Filter by whether a job still accepts tasks (`status=open|closed`) or by `type=regular|scheduled`, and pass the previous page's `next_cursor` back as `cursor` via GET /jobs

api
zen_rows_get_jobs_by_job_idREAD

Read one Batch job and the state of its most recent run, including `latest_run.status` (`running`, `completed`, `stopped` and `deleted` are terminal) and `latest_run.stats` (total, completed, successful, failed). Poll this, or set a webhook, to learn when a run has finished via GET /jobs/{job_id}

api
zen_rows_get_jobs_by_job_id_resultsREAD

Page through the per-URL results of a run: each task's status, its content or the location to collect it from, and the `external_id` you set when the task was submitted so a result can be joined back to your own record. Filter with `status=successful|failed` and page with `cursor` via GET /jobs/{job_id}/results

api
zen_rows_get_jobs_by_job_id_runsREAD

Every run of one Batch job, newest first, with each run's stats. This is where a `run_id` comes from for Delete a run and Export a run as a ZIP via GET /jobs/{job_id}/runs

api
zen_rows_get_subscriptions_self_detailsREAD

Read the plan behind the connected key: its credit allowance, the credits already used and the concurrency it is allowed. The cheapest read on this integration and the one to call before a large run, because ZenRows answers 402 once an account is out of credits and 429 AUTH008 once every concurrency slot is busy -- neither is a broken tool via GET /subscriptions/self/details

api
zen_rows_post_hmac_keys_rotateWRITE

Issue a new webhook signing key alongside the current one, so a receiver can accept both while the new one is deployed. Finish a key rotation promotes it; Cancel a key rotation discards it via POST /hmac/keys/rotate

api
zen_rows_post_hmac_keys_rotate_finalizeWRITE

Promote the pending webhook signing key and retire the previous one. Any receiver still verifying against only the old key starts rejecting deliveries at this point, so deploy the new key first via POST /hmac/keys/rotate/finalize

api
zen_rows_post_job_inputsWRITE

Upload a CSV of URLs to run as a Batch job, for an input too large to send inline. The body is the CSV ITSELF, sent as `text/csv` -- rows carry the URLs and any per-URL columns -- and the identifier it returns goes into Create a batch job as `input_id` via POST /job_inputs

api
zen_rows_post_jobsWRITE

Submit a Batch job -- the supported way to fetch many URLs, because results are collected asynchronously and can be delivered to a webhook instead of returned inline. A `closed` job carries every URL up front in `tasks` (up to 10,000 per call); an `open` job is created empty and receives URLs through Add URLs to an open job until one call sets `last_batch`. `zenrows_params` applies the Fetch parameters to every task and a per-task `zenrows_params` overrides it. `type=scheduled` needs a cron from Set a job's schedule. Answers 201 under 10,000 inline tasks and 202 at or above that (or for a CSV input); the body is identical, so treat both the same via POST /jobs

api
zen_rows_post_jobs_by_job_id_cancelWRITE

Cancel the Batch job and the work still pending on it. Results already produced stay readable through Read a job's results; the job stops accepting and dispatching anything further via POST /jobs/{job_id}/cancel

api
zen_rows_post_jobs_by_job_id_closeWRITE

Lock an open Batch job so it accepts no further tasks. Equivalent to sending `last_batch: true` on the last add, and there is no reopen: a closed job can only be rerun or copied via POST /jobs/{job_id}/close

api
zen_rows_post_jobs_by_job_id_pauseWRITE

Stop dispatching new tasks without abandoning the run, so Resume a paused run can continue it. The reversible alternative to Stop the current run via POST /jobs/{job_id}/pause

api
zen_rows_post_jobs_by_job_id_rerunWRITE

Start a new run of the same Batch job -- how a dataset is refreshed on demand. `only_failed: true` retries just the tasks that failed last time, which is the cheaper call: a rerun spends credits again for every task it dispatches via POST /jobs/{job_id}/rerun

api
zen_rows_post_jobs_by_job_id_resumeWRITE

Continue dispatching the remaining tasks of a paused run via POST /jobs/{job_id}/resume

api
zen_rows_post_jobs_by_job_id_runs_by_run_id_exportsWRITE

Ask ZenRows to package a run's content as a ZIP. The export is prepared asynchronously and downloaded from the URL in the response, which is why this is the supported route for bulk content rather than reading pages through tool results via POST /jobs/{job_id}/runs/{run_id}/exports

api
zen_rows_post_jobs_by_job_id_schedule_stateWRITE

Turn a scheduled Batch job on or off with `enabled`, without deleting the cron it holds. This is the reversible way to stop a recurring job from spending credits via POST /jobs/{job_id}/schedule/state

api
zen_rows_post_jobs_by_job_id_stopWRITE

Abandon the run in flight. Tasks that already completed keep their results, and the remaining ones are not dispatched. Use Pause the current run instead if the run should continue later via POST /jobs/{job_id}/stop

api
zen_rows_post_jobs_by_job_id_tasksWRITE

Append up to 10,000 URLs to an OPEN Batch job. Send `last_batch: true` on the final call to close it; a later addition then answers 409, which means the job is closed rather than that the request was wrong via POST /jobs/{job_id}/tasks

api
zen_rows_post_webhook_testWRITE

Deliver a sample payload to a `url` you name, so a receiver and its signature check can be verified before a real run spends credits via POST /webhook/test

api
zen_rows_put_jobs_by_job_id_scheduleWRITE

Give a `scheduled` Batch job its cron expression and the IANA timezone the cron is read in. REPLACES the whole schedule rather than merging into it, and every run it triggers spends credits via PUT /jobs/{job_id}/schedule

api
zen_rows_put_jobs_by_job_id_webhookWRITE

Have ZenRows deliver this job's results to an endpoint you control as tasks complete, instead of polling. REPLACES any webhook already on the job. Deliveries are signed with the account's HMAC keys, which List webhook signing keys returns so a receiver can verify them via PUT /jobs/{job_id}/webhook

api

Put ZenRows behind one governed endpoint.

Same permissions, same audit trail, whatever else you connect next.