---
title: "Up to 20 URLs (HTML or PDF) as Markdown, text or HTML, with query-ranked highlights, links and images (1 credit per URL read)"
method: POST
path: "/v1/extract"
---

# Up to 20 URLs (HTML or PDF) as Markdown, text or HTML, with query-ranked highlights, links and images (1 credit per URL read)

`POST /v1/extract`

## Request

- Base URL: `https://api.serpkite.com`
- URL: `https://api.serpkite.com/v1/extract`
- Auth: HTTP bearer

Every URL is billed only when it comes back: 1 credit, 0.5 from cache. URLs that
fail are listed in `failed` and cost nothing. The response is `200` even when every
URL failed. Highlights are ranked with BM25 (lexical, no model).

## Request body

- ExtractRequest
  - `urls` string[], required: HTML pages or PDFs (duplicates are dropped)
  - `format` 'markdown' | 'text' | 'html'
  - `query` string: What highlights are ranked against
  - `highlights` integer: Query-ranked passages per page (BM25; needs query)
  - `max_tokens` integer: Trim each page's markdown or text to about this many tokens
  - `include_links` boolean
  - `include_images` boolean
  - `max_age` integer: Accept a cached page up to this many seconds old (0.5 credit)
  - `country` string: Fetch through an exit in this country (ISO 3166-1 alpha-2)
  - `timeout` integer: Seconds to wait for the pages; a page still loading is listed in `failed` (`upstream_timeout`, not charged)

## Response `200`

OK

- ExtractResponse
  - `request` object, required
    - `endpoint` 'extract'
    - `urls` string[]
    - `format` string
    - `query` string
  - `results` ExtractResult[], required
    - `url` string, required: Final URL after redirects
    - `status_code` integer
    - `title` string
    - `published_at` string: The page's published time as ISO 8601, when it has one
    - `metadata` PageMetadata
      - `title` string
      - `description` string
      - `language` string
      - `canonical` string
      - `site_name` string
      - `image` string
      - `published_time` string
      - `author` string
      - `content_type` string: The page's media type
      - `pages` integer: Page count of a PDF
    - `cached` boolean, required
    - `markdown` string: format=markdown
    - `text` string: format=text
    - `html` string, nullable: format=html (null for a PDF); at most 2 MiB per page
    - `links` PageLink[]: include_links=true only
      - `url` string, required: Absolute URL
      - `text` string: Anchor text
    - `images` string[]: include_images=true only
    - `highlights` Highlight[]: highlights > 0 only
      - `text` string, required
      - `score` number, required: Relevance to the query (BM25; higher is better
      - `heading` string: The section heading path the passage sits under
  - `failed` ExtractFailure[], required
    - `url` string, required
    - `error` object, required
      - `code` string, required
      - `message` string, required
  - `meta` object, required
    - `request_id` string, required
    - `credits_used` number, required
    - `latency_ms` integer
    - `succeeded` integer, required
    - `failed` integer, required

## Other responses

- `400`: Error
- `401`: Error
- `402`: Error
- `403`: Error
- `429`: Error
- `503`: Temporarily unavailable, not billed, safe to retry after `Retry-After`. Codes: `upstream_error` (the upstream page couldn't be fetched or parsed), `upstream_blocked` (the upstream is rate limiting us), `upstream_timeout` (the search took too long), `unavailable` (endpoint or dependency down). The API never sends 502 or 504.

---

[API](https://skmtc.dev/serpkite/apis/serpkite-serp-api.md) · [All operations](https://skmtc.dev/serpkite/apis/serpkite-serp-api/llms.txt) · [OpenAPI document](https://skmtc.dev/serpkite/apis/serpkite-serp-api/revisions/f2c6dd05cfc5?raw)
