/v0 request fails with HTTP 410 Gone.
Migrate with your coding agent
Paste this prompt into Claude Code, Cursor, Codex, or any coding agent, in the root of your project:Prompt
Migrate this codebase from the Firecrawl v0 API to v2. v0 shuts down on Thursday, December 10, 2026, 15:00 UTC, and every /v0 request returns HTTP 410 after that.
1. Find every v0 call:
- Raw HTTP requests to https://api.firecrawl.dev/v0/ (or <self-hosted base URL>/v0/).
- SDK calls that pass pageOptions, extractorOptions, crawlerOptions or searchOptions: scrape_url, crawl_url, check_crawl_status, search (Python, Rust); scrapeUrl, crawlUrl, checkCrawlStatus, search (Node); ScrapeURL, CrawlURL, CheckCrawlStatus, CancelCrawlJob, Search (Go).
2. Upgrade the Firecrawl SDK to its latest release:
- Python: pip install --upgrade firecrawl-py (or firecrawl, if that is the package installed). Use the Firecrawl class: scrape, crawl, start_crawl, get_crawl_status, cancel_crawl, search.
- Node: npm install firecrawl@latest (or @mendable/firecrawl-js@latest). Use scrape, crawl, startCrawl, getCrawlStatus, cancelCrawl, search. scrape returns the document itself, not { success, data }.
- Go: replace the module github.com/mendableai/firecrawl-go with github.com/firecrawl/firecrawl/apps/go-sdk, then run go mod tidy. Use firecrawl.NewClient and Scrape, Crawl, StartCrawl, GetCrawlStatus, CancelCrawl, Search.
- Rust: cargo add firecrawl@2 (and cargo remove firecrawl_rs if present). Use firecrawl::Client with scrape, crawl, start_crawl, get_crawl_status, cancel_crawl, search and the typed ScrapeOptions, CrawlOptions, SearchOptions.
3. Rewrite each call to v2 with this mapping, keeping its behavior the same:
- POST /v0/scrape -> POST /v2/scrape. pageOptions fields move to the top level.
- POST /v0/crawl -> POST /v2/crawl. crawlerOptions fields move to the top level, pageOptions becomes scrapeOptions, and the response returns id instead of jobId.
- GET /v0/crawl/status/{jobId} -> GET /v2/crawl/{id}. DELETE /v0/crawl/cancel/{jobId} -> DELETE /v2/crawl/{id}.
- POST /v0/search -> POST /v2/search. searchOptions fields move to the top level.
- GET /v0/keyAuth -> GET /v2/team/credit-usage, which returns 200 for a valid key.
- includeMarkdown, includeHtml, includeRawHtml, includeLinks, screenshot -> "markdown", "html", "rawHtml", "links", "screenshot" in formats. fullPageScreenshot -> {"type": "screenshot", "fullPage": true} in formats. v0 always returned links, so add "links" wherever the code reads them.
- onlyMainContent defaults to true in v2 and false in v0: send false where the code relied on the v0 default.
- onlyIncludeTags -> includeTags, removeTags -> excludeTags (both arrays), geolocation.country -> location.country, useFastMode -> fastMode, parsePDF: false -> parsers: [].
- extractorOptions with an llm-extraction mode -> {"type": "json", "schema": <extractionSchema>, "prompt": <extractionPrompt and userPrompt combined>} in formats. v0 extraction also forced onlyMainContent: true and, unless timeout was set, timeout: 90000, so send those.
- includes -> includePaths, excludes -> excludePaths, maxCrawledLinks -> limit, allowBackwardCrawling -> crawlEntireDomain, allowExternalContentLinks -> allowExternalLinks, ignoreSitemap: true -> sitemap: "skip", sitemapOnly: true -> sitemap: "only", returnOnlyUrls -> call POST /v2/map instead.
- maxDepth has no direct equivalent: use maxDiscoveryDepth (link hops from the start URL), or includePaths and excludePaths to bound URL depth.
- v0 search scraped every result: send scrapeOptions: {"formats": ["markdown"]} unless the code set fetchPageContent: false.
- Remove includeExtract, replaceAllPathsWithAbsolutePaths, disableJsDom, atsv, fallback, crawlerOptions.mode and generateImgAltText. All other option names stay the same.
- Responses: data.content -> data.markdown, data.linksOnPage -> data.links, data.llm_extraction -> data.json, metadata.screenshot -> data.screenshot, metadata.pageStatusCode -> metadata.statusCode, metadata.pageError -> metadata.error. Crawl status "active" -> "scraping", current -> completed, partial_data -> data, and follow next until it is absent to read every page (the SDK crawl methods do this). Search results move from data to data.web.
4. Run the project's tests and fix any failures.
Reference: https://docs.firecrawl.dev/migrating-from-v0.md
Migrate by hand
| v0 | v2 | Note |
|---|---|---|
POST /v0/scrape | POST /v2/scrape | pageOptions fields move to the top level. |
POST /v0/crawl | POST /v2/crawl | Returns id instead of jobId. |
GET /v0/crawl/status/{jobId} | GET /v2/crawl/{id} | Follow next to read every page. |
DELETE /v0/crawl/cancel/{jobId} | DELETE /v2/crawl/{id} | |
POST /v0/search | POST /v2/search | Send scrapeOptions to scrape each result. |
GET /v0/keyAuth | GET /v2/team/credit-usage | Returns 200 for a valid key. |
includeHtml, includeRawHtml, includeLinks, screenshot | "html", "rawHtml", "links", "screenshot" in formats | v0 always returned links. |
onlyMainContent | onlyMainContent | Defaults to true in v2. |
onlyIncludeTags, removeTags | includeTags, excludeTags | |
extractorOptions | { "type": "json", "schema": ..., "prompt": ... } in formats | Result moves to data.json. |
crawlerOptions.includes, excludes | includePaths, excludePaths | |
allowBackwardCrawling | crawlEntireDomain | |
ignoreSitemap: true | sitemap: "skip" | |
returnOnlyUrls | POST /v2/map | |
searchOptions.limit | limit | |
data.content, data.linksOnPage | data.markdown, data.links | |
status: "active", current, partial_data | status: "scraping", completed, data |

