SerpKite Extract API

The Extract API from SerpKite — 1 operation(s) for extract.

Operations 1

POST /v1/extract Up to 20 URLs (HTML or PDF) as Markdown, text or HTML, with query-ranked… #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/serpkite-com:serpkite-com-extract-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

serpkite-com-extract-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: SerpKite SERP Extract API
  version: 1.12.4
  description: 'Public search API (api.serpkite.com). Google results as clean JSON or Markdown

    for AI agents, plus a Google Custom Search–compatible endpoint. Official SDKs:

    `serpkite` on npm and PyPI, `github.com/serpkite/serpkite-go`. **Auth:** `Authorization: Bearer skt_live_…`. A bare `Authorization: skt_live_…`

    (no scheme) is also accepted, for MCP hosts that can''t add one. GET requests

    may pass `?api_key=` instead. `/customsearch/v1` also accepts Google''s `?key=`. **Bodies:** every vertical accepts `POST` with a JSON object or `GET` with the

    same parameters in the query string (only `GET /v1/search` is spelled out

    here). Unknown parameters are rejected with 400, and so is a parameter the

    endpoint would ignore (e.g. `time` on `/v1/scholar`, `ll` on `/v1/search`). To run many queries at once,

    use `POST /v1/batches`. **Formats:** `format=json` (default) returns the schemas below. `format=markdown` returns `text/markdown` for every vertical. `format=compact` and `fields=` return a reduced JSON object (same top-level

    keys, fewer item fields, `meta` always kept), so required item fields may be

    absent there. **Responses** share one envelope: `request` (the normalised request),

    `results` (the vertical''s primary list), vertical-specific extras and `meta`. All keys are snake_case. **Credits** are decimal numbers (e.g. `0.5`). Failed, empty and blocked

    responses are refunded. Every billed response carries `X-Credits-Used`,

    `X-Credits-Remaining`, `X-Cost-USD`, `X-Cache` (`HIT`|`MISS`), `X-Latency-Ms`,

    `X-Tokens-Estimate` and `X-Request-Id`. **Errors** share one body: `{"error":{"code","message","request_id"}}`. Upstream failures (`upstream_error`, `upstream_blocked`, `upstream_timeout`)

    are `503` with `Retry-After`, never billed and safe to retry. The API never

    returns `502` or `504`. `429` also carries `Retry-After`: `rate_limited` is

    the per-second limit; `daily_limit_reached` is the free daily limit of an

    account that never bought a pack, which resets at 00:00 UTC (the message

    names the limit and the billing page; buying any pack removes it). `403 account_restricted` means the account''s free use is paused because it

    appears to be one of several accounts run by the same person (same device

    or network, or requests in step with other accounts) or uses a disposable

    email address; buying any pack lifts it. **CORS:** `Access-Control-Allow-Origin: *` without credentials; the `X-*`

    headers above are exposed, so a browser playground can call the API with a key. The keyless `/playground/search` is the exception: it only answers serpkite.com

    and app.serpkite.com (other `Origin`s get 403). Credit table: search/news/images/videos/maps/places/shopping/scholar/patents/

    webpage/customsearch = 1 per page; place details = 1; `num=100` depth bundle = 7; reviews = 1 per 10;

    autocomplete = 0.5; `include_content` = +1 per fetched page;

    batches ×0.5 (from 2026-11-23 a batch depth request is 0.5 per page with

    results, without the bundle cap: `num=100` = 5); cache hit via `max_age` ×0.5. `engine=consensus` (search only) =

    the sum of one page per provider that returned results. **AI** (Claude writes, OpenAI''s Decisions API runs typed checks; a failed

    model step is never billed): an answer (`include_answer` on `/v1/search` and

    `/v1/news`, the model part of `/v1/answer`) = +2 over the result page, +4

    when it read pages (`include_content`, `/v1/answer` depth=standard);

    `/v1/extract` `summary` = +4 and `output_schema` = +4 per page;

    `/v1/research` = lite 30, standard 75, deep 200. Responses that used a

    model carry `meta.llm`. **AI assistants** (`/v1/chatgpt`, `/v1/gemini`, `/v1/copilot`,

    `/v1/ai_mode`, `/v1/brave_ai`): a `prompt` sent to the public assistant

    as a logged-out user; the response is its answer

    (`text`, `markdown`) with the `sources` it cited or listed,

    `search_queries`, `products` and `places` where the assistant shows them,

    and `mentions` for the brands and domains in `track`.'
servers:
- url: https://api.serpkite.com
- url: http://localhost:8080
security:
- bearer: []
tags:
- name: Extract
paths:
  /v1/extract:
    post:
      summary: Up to 20 URLs (HTML or PDF) as Markdown, text or HTML, with query-ranked…
      operationId: extract
      description: '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).


        **AI:** `summary: true` adds a 3–6 sentence summary of each page (+4 credits per

        page); `output_schema` (a JSON Schema, at most 16 KB, optionally guided by

        `prompt`) returns each page''s data as JSON in `output` (+4 credits per page).

        Claude Haiku writes both; a schema whose fields are all booleans or enums is

        answered by a decision model instead (always valid against the schema). A

        summary or extraction that fails is reported in `summary_error` /

        `output_error` and not charged. With either, `timeout` defaults to 75 seconds

        and the last 25 are kept for the model.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExtractRequest'
            example:
              urls:
              - https://example.com/pricing
              - https://example.com/docs/limits.pdf
              query: enterprise price
              highlights: 2
      responses:
        '200':
          $ref: '#/components/responses/ExtractOK'
        '400':
          $ref: '#/components/responses/Error'
        '401':
          $ref: '#/components/responses/Error'
        '402':
          $ref: '#/components/responses/Error'
        '403':
          $ref: '#/components/responses/Error'
        '429':
          $ref: '#/components/responses/Error'
        '503':
          $ref: '#/components/responses/Unavailable'
      tags:
      - Extract
components:
  headers:
    RetryAfter:
      description: Seconds to wait before retrying
      schema:
        type: integer
    CreditsRemaining:
      schema:
        type: number
    TokensEstimate:
      schema:
        type: integer
    LatencyMs:
      schema:
        type: integer
    CreditsUsed:
      schema:
        type: number
    CostUSD:
      schema:
        type: number
    Cache:
      schema:
        type: string
        enum:
        - HIT
        - MISS
  schemas:
    Highlight:
      type: object
      description: A query-relevant passage of a page, verbatim
      required:
      - text
      - score
      properties:
        text:
          type: string
        score:
          type: number
          description: Relevance to the query (BM25; higher is better
          comparable within one response): null
        heading:
          type: string
          description: The section heading path the passage sits under
    PageLink:
      type: object
      required:
      - url
      properties:
        url:
          type: string
          description: Absolute URL
        text:
          type: string
          description: Anchor text
    ExtractResult:
      type: object
      required:
      - url
      - cached
      properties:
        url:
          type: string
          description: Final URL after redirects
        status_code:
          type: integer
        title:
          type: string
        published_at:
          type: string
          description: The page's published time as ISO 8601, when it has one
        metadata:
          $ref: '#/components/schemas/PageMetadata'
        cached:
          type: boolean
        markdown:
          type: string
          description: format=markdown
        text:
          type: string
          description: format=text
        html:
          type:
          - string
          - 'null'
          description: format=html (null for a PDF); at most 2 MiB per page
        links:
          type: array
          items:
            $ref: '#/components/schemas/PageLink'
          description: include_links=true only
        images:
          type: array
          items:
            type: string
          description: include_images=true only
        highlights:
          type: array
          items:
            $ref: '#/components/schemas/Highlight'
          description: highlights > 0 only
        summary:
          type:
          - string
          - 'null'
          description: summary=true only (null when it failed)
        summary_error:
          type: string
        output:
          description: 'output_schema only: the JSON value matching the schema (null when it failed)'
        output_error:
          type: string
    PageMetadata:
      type: object
      properties:
        title:
          type: string
        description:
          type: string
        language:
          type: string
        canonical:
          type: string
        site_name:
          type: string
        image:
          type: string
        published_time:
          type: string
        author:
          type: string
        content_type:
          type: string
          description: The page's media type
          examples:
          - text/html
          - application/pdf
        pages:
          type: integer
          description: Page count of a PDF
    ExtractResponse:
      type: object
      required:
      - request
      - results
      - failed
      - meta
      properties:
        request:
          type: object
          additionalProperties: true
          properties:
            endpoint:
              type: string
              const: extract
            urls:
              type: array
              items:
                type: string
            format:
              type: string
            query:
              type: string
        results:
          type: array
          items:
            $ref: '#/components/schemas/ExtractResult'
        failed:
          type: array
          items:
            $ref: '#/components/schemas/ExtractFailure'
        meta:
          type: object
          required:
          - request_id
          - credits_used
          - succeeded
          - failed
          properties:
            request_id:
              type: string
            credits_used:
              type: number
            latency_ms:
              type: integer
            succeeded:
              type: integer
            failed:
              type: integer
            llm:
              $ref: '#/components/schemas/LLMUsage'
    ExtractRequest:
      type: object
      required:
      - urls
      properties:
        urls:
          type: array
          items:
            type: string
            format: uri
          minItems: 1
          maxItems: 20
          description: HTML pages or PDFs (duplicates are dropped)
        format:
          type: string
          enum:
          - markdown
          - text
          - html
          default: markdown
        query:
          type: string
          maxLength: 4096
          description: What highlights are ranked against
        highlights:
          type: integer
          minimum: 0
          maximum: 10
          default: 0
          description: Query-ranked passages per page (BM25; needs query)
        max_tokens:
          type: integer
          minimum: 100
          maximum: 100000
          description: Trim each page's markdown or text to about this many tokens
        include_links:
          type: boolean
          default: false
        include_images:
          type: boolean
          default: false
        max_age:
          type: integer
          minimum: 0
          maximum: 2592000
          description: Accept a cached page up to this many seconds old (0.5 credit)
        country:
          type: string
          description: Fetch the pages as seen from this country (ISO 3166-1 alpha-2)
        timeout:
          type: integer
          minimum: 1
          maximum: 90
          default: 50
          description: Seconds to wait for the pages; a page still loading is listed in `failed` (`upstream_timeout`, not charged). Default 75 with summary or output_schema
        summary:
          type: boolean
          default: false
          description: Add a 3-6 sentence AI summary of each page (+4 credits per page; focused on `query` when set)
        output_schema:
          type: object
          additionalProperties: true
          description: 'A JSON Schema (at most 16 KB): each page''s data is returned as JSON matching it in `output` (+4 credits per page)'
        prompt:
          type: string
          maxLength: 4096
          description: Guides output_schema extraction (what to pick, how to normalise); needs output_schema
    ExtractFailure:
      type: object
      required:
      - url
      - error
      properties:
        url:
          type: string
        error:
          type: object
          required:
          - code
          - message
          properties:
            code:
              type: string
              examples:
              - invalid_request
              - upstream_error
              - upstream_timeout
              - empty_page
            message:
              type: string
    LLMUsage:
      type: object
      description: The model that wrote this response's AI part and the tokens it used
      properties:
        provider:
          type: string
          examples:
          - anthropic
          - openai
        model:
          type: string
          examples:
          - claude-haiku-5-5
          - gpt-6-luna
        input_tokens:
          type: integer
        output_tokens:
          type: integer
    Error:
      type: object
      required:
      - error
      properties:
        error:
          type: object
          required:
          - code
          - message
          properties:
            code:
              type: string
              description: '403: spend_cap_reached, key_limit_reached, account_restricted, forbidden. 409/422: idempotency_key_reused. 422: target_unavailable (the URL you asked for failed: its site answered 404, its domain doesn''t resolve; resending won''t help), no_pages. 429: rate_limited, daily_limit_reached. 503: upstream_error, upstream_blocked, upstream_timeout, unavailable (the API never sends 502 or 504)'
              examples:
              - unauthorized
              - invalid_request
              - insufficient_credits
              - rate_limited
              - daily_limit_reached
              - spend_cap_reached
              - key_limit_reached
              - account_restricted
              - idempotency_key_reused
              - forbidden
              - not_found
              - upstream_error
              - upstream_blocked
              - upstream_timeout
              - unavailable
              - internal
            message:
              type: string
            request_id:
              type: string
  responses:
    Unavailable:
      description: '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 or refused the query), `upstream_timeout`

        (the search took too long), `unavailable` (endpoint or dependency down).

        The API never sends 502 or 504.

        '
      headers:
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ExtractOK:
      description: OK
      headers:
        X-Credits-Used:
          $ref: '#/components/headers/CreditsUsed'
        X-Credits-Remaining:
          $ref: '#/components/headers/CreditsRemaining'
        X-Cost-USD:
          $ref: '#/components/headers/CostUSD'
        X-Cache:
          $ref: '#/components/headers/Cache'
        X-Latency-Ms:
          $ref: '#/components/headers/LatencyMs'
        X-Tokens-Estimate:
          $ref: '#/components/headers/TokensEstimate'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExtractResponse'
          example:
            request:
              endpoint: extract
              urls:
              - https://example.com/pricing
              - https://example.com/missing
              format: markdown
              query: enterprise price
            results:
            - url: https://example.com/pricing
              status_code: 200
              title: Pricing
              metadata:
                title: Pricing
                content_type: text/html
              cached: false
              markdown: '# Pricing


                …'
              highlights:
              - text: 'Enterprise: $499 per month …'
                score: 4.83
                heading: Plans
            failed:
            - url: https://example.com/missing
              error:
                code: target_unavailable
                message: 'could not fetch the page: the site answered 404; you were not charged'
            meta:
              request_id: req_01J9
              credits_used: 1
              latency_ms: 2210
              succeeded: 1
              failed: 1
    Error:
      description: Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    bearer:
      type: http
      scheme: bearer
    oauth:
      type: oauth2
      description: OAuth 2.1 for the remote MCP server only (authorization code + PKCE S256; app-api.serpkite.com is the authorization server).
      flows:
        authorizationCode:
          authorizationUrl: https://app-api.serpkite.com/oauth/authorize
          tokenUrl: https://app-api.serpkite.com/oauth/token
          refreshUrl: https://app-api.serpkite.com/oauth/token
          scopes:
            mcp: Use the SerpKite MCP tools, billed to your account
            offline_access: Stay connected with refresh tokens