ScavioScavio
Pricing
Tools
Sign InsGet Startedg
Quick StartAPI & SDKsEcosystem

Extract

Batch Extract URLs

Extract a list of URLs in one job instead of one request per page: each URL comes back as Markdown, plain text or HTML, exactly like Extract, with results in input order. Duplicates are removed and invalid URLs are reported in the 202 and never billed. Returns 202 with a job id at once; poll the status URL or take a signed webhook when it finishes. Billed per successful page at Extract's price (normal 1, advanced 1, ultra 2); failed pages are free.

POST/api/v1/extract/batch

Authorizations

Authorizationstringheaderrequired

Bearer authentication header of the form Bearer <token>, where <token> is your Scavio API key (e.g. Bearer sk_live_your_key).

Body

application/json
urlsstring[]required

The pages to extract, 1-1,000 URLs of up to 2048 characters each. Duplicates are removed after normalising (a trailing slash or a bare host upgraded to https counts as the same URL). Must be within your plan's limit: Free 10, PAYG 50, Project 100, Bootstrap 500, Startup 1,000, Growth 1,000.

Example: ["https://example.com/a", "https://example.com/b"]

formatenum<string>default:markdown

Return format for every page, as on Extract.

  • markdown — Clean Markdown with links kept, ready for an LLM or RAG. The default.
  • text — The same content flattened to plain text.
  • html — The raw page as served.
modeenum<string>default:normal

Fetch tier for every URL, and the price per page.

  • normal — The standard fetch. 1 credit per successful page.
  • advanced — Renders JavaScript. 1 credit per successful page.
  • ultra — For the hardest pages. 2 credits per successful page.
webhook_urlstring

Optional public https URL that receives one signed POST when the batch completes, fails or is cancelled. The signing secret comes back once, in the 202, as webhook_secret.

Idempotency-Keystringheader

Optional, max 255 characters. Repeating the POST with the same key within 24 hours returns the original job instead of starting a second one.

Notes

Batch or crawl? Use batch when you already know the URLs: from Map, a sitemap, a search result or your own list. It can span any number of sites. Use Crawl when you want one site's pages discovered for you.

Pricing: successful pages only. Each URL that comes back is charged once at the tier price (credits_per_page in the 202). URLs refused up front (in invalid_urls), pages that fail or 404, and starting, polling and cancelling cost nothing. Credits are taken page by page; if your balance runs out, the batch stops with stopped_reason: "insufficient_credits" and keeps the pages it already fetched. If every URL is invalid the POST returns 400 with invalid_urls and no job is created.

Robots.txt. Batch behaves like Extract: you named each URL, so it is fetched as you asked. Crawl and Map, which discover pages for you, always obey robots.txt.

Plan limits. URLs per batch, and crawl and batch jobs running at once:

PlanPages per crawlActive jobsURLs per batchMap links
Free10110500
PAYG1001501,000
Project50021005,000
Bootstrap2,00035005,000
Startup5,00051,0005,000
Growth10,000101,0005,000

Retention. Results are kept 3 days after the batch finishes, up to 2 MB of content per page and 250 MB per job; a job runs for at most 6 hours. Read them from Batch Status and stop a batch early with Cancel Batch.

Webhooks. Set webhook_url to a public https URL and Scavio POSTs one signed JSON event when the batch ends: event is completed, failed or cancelled, job is the same summary the status endpoint returns, and sent_at is the send time. Results are not in the body; fetch them from the status URL. Headers: Scavio-Signature, Scavio-Event and Scavio-Job-Id. A delivery that does not get a 2xx within 10 seconds is retried twice, 30 seconds and 5 minutes after the first attempt. Redirects are not followed, and the URL must use a public host name (no IP addresses or private hosts).

Verify every delivery. The 202 response returns webhook_secret (whsec_...) once; store it. Scavio-Signature is t=<unix seconds>,v1=<hex>, where v1 is the HMAC-SHA256 of <t>.<raw request body> keyed with that secret. Recompute it over the raw bytes, compare in constant time, and reject timestamps more than 5 minutes old:

import hashlib, hmac, time

def verify_scavio_signature(secret: str, header: str, raw_body: bytes, tolerance: int = 300) -> bool:
    """header is the Scavio-Signature value: t=<unix>,v1=<hex>."""
    parts = dict(p.strip().split("=", 1) for p in header.split(",") if "=" in p)
    t, v1 = parts.get("t", ""), parts.get("v1", "")
    if not t.isdigit() or not v1 or abs(time.time() - int(t)) > tolerance:
        return False
    signed = t.encode() + b"." + raw_body
    expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, v1)

# Flask example
from flask import Flask, request, abort
app = Flask(__name__)
WEBHOOK_SECRET = "whsec_from_the_202_response"

@app.post("/scavio/webhook")
def scavio_webhook():
    if not verify_scavio_signature(WEBHOOK_SECRET, request.headers.get("Scavio-Signature", ""), request.get_data()):
        abort(400)
    event = request.get_json()
    print(event["event"], event["job"]["id"], event["job"]["pages"]["succeeded"])
    return "", 204

A delivery body looks like this:

{
  "event": "completed",
  "job": {
    "id": "crawl_01a12d2e-f813-73c2-8c07-4c1f0ae402df",
    "type": "crawl",
    "status": "completed",
    "stopped_reason": null,
    "error": null,
    "url": "https://example.com/",
    "format": "markdown",
    "mode": "normal",
    "pages": { "discovered": 1, "queued": 0, "succeeded": 1, "failed": 0, "skipped": 0 },
    "credits_used": 1,
    "created_at": "2026-10-11T22:56:55.312Z",
    "started_at": "2026-10-11T22:57:00.424Z",
    "completed_at": "2026-10-11T22:57:02.665Z",
    "expires_at": "2026-10-14T22:57:02.665Z",
    "webhook": { "status": "pending", "attempts": 1 },
    "status_url": "https://api.scavio.dev/api/v1/extract/crawl/crawl_01a12d2e-f813-73c2-8c07-4c1f0ae402df"
  },
  "sent_at": "2026-10-11T22:57:02.701Z"
}

Request

from scavio import ScavioClient

client = ScavioClient(api_key="sk_live_your_key")

urls = [
    "https://hono.dev/docs/api/routing",
    "https://hono.dev/docs/api/context",
    "https://hono.dev/docs/api/request",
]

# wait=True polls the job and returns every result, in input order
done = client.extract.batch(urls, format="markdown", wait=True)
for r in done["data"]["results"]:
    print(r["status"], r["url"], r["credits"])

Response

"id": "batch_01a12d2e-f9c1-737f-bfdc-97e7f94d643f",
"type": "batch",
"status": "queued",
"url": null,
"max_pages": 2,
"max_depth": 0,
"format": "markdown",
"mode": "normal",
"credits_per_page": 1,
"status_url": "https://api.scavio.dev/api/v1/extract/batch/batch_01a12d2e-f9c1-737f-bfdc-97e7f94d643f",
"urls_count": 2,
},
"credits_used": 0
}
PreviousCancel a CrawlNextBatch Status and Results
ScavioScavio

One scraper API for every social, search, e-commerce and real estate platform. Built for AI agents.

Product

  • Features
  • Pricing
  • Dashboard
  • Affiliates

Developers

  • Documentation
  • API Reference
  • Quickstart
  • MCP Integration
  • Python SDK

Alternatives

  • Tavily Alternative
  • SerpAPI Alternative
  • Firecrawl Alternative
  • Exa Alternative
  • Serper Alternative
  • Tavily vs Scavio
  • SerpAPI vs Scavio
  • All alternatives
  • Compare Scavio vs alternatives

Search APIs

  • Google Search API
  • Amazon Product API
  • YouTube API
  • Reddit API
  • Walmart Product API
  • TikTok API
  • Instagram API

Tools

  • All Tools

© 2026 Scavio. All rights reserved.

Featured on TAAFT
Terms of ServicePrivacy Policy