openapi: 3.0.0
info:
  title: Scrape API
  description: |
    Scrape any public web page with one GET or POST request. Send the URL in a JSON body or as a query parameter, and get back the page's HTML, the site's status code, the final URL and the site's response headers.

    **Authentication**: send your API key in the `Authorization` header as `Bearer YOUR_API_KEY`. A GET request can instead send it as the `api_key` query parameter. A POST request cannot.

    **JavaScript**: the answer is the HTML that the site sends. Scripts are not run, so content that a page loads with JavaScript is not in `outputs.html`.

    **Credits**: a scrape costs 1 search credit when the site answers with a page, a redirect or a client error that your request caused, such as a 404. The credit comes from the same balance as your searches. A site's own server error and failed scrapes are free. `scrape_metadata.credits` shows what each scrape cost.

    **Sessions**: requests with the same `session_id` are sent from the same IP address, for up to 10 minutes.

    **Access**: the Scrape API is turned on per account. Contact support to turn it on.
  version: 1.0.0
servers:
  - url: https://www.searchapi.io/api/v1
paths:
  /scrape:
    get:
      summary: Scrape a Web Page with a GET Request
      description: Sends a `GET` to the site, with the same answer and cost as a POST. Use a POST to send a `POST` to the site, and for long URLs or many headers.
      security:
        - ApiKeyAuth: []
        - ApiKeyQuery: []
      parameters:
        - name: url
          in: query
          required: true
          description: The page to scrape, percent-encoded. It follows the same rules as `url` in the POST body.
          schema:
            type: string
            maxLength: 8192
        - name: headers
          in: query
          required: false
          description: Request headers sent to the site, each as `headers[Name]=value`, such as `headers[Accept-Language]=de-DE`.
          style: deepObject
          explode: true
          schema:
            type: object
            maxProperties: 100
            additionalProperties:
              type: string
        - name: cookies
          in: query
          required: false
          description: Cookies sent to the site, percent-encoded, such as `currency%3DEUR`.
          schema:
            type: string
        - name: country
          in: query
          required: false
          description: The country the request is sent from, as a two-letter lowercase code.
          schema:
            $ref: '#/components/schemas/ScrapeRequest/properties/country'
        - name: session_id
          in: query
          required: false
          description: Requests with the same `session_id` are sent from the same IP address, for up to 10 minutes.
          schema:
            $ref: '#/components/schemas/ScrapeRequest/properties/session_id'
        - name: zero_retention
          in: query
          required: false
          description: Set to `true` to disable all logging and persistent storage. The answer then has no `id`. Enterprise only.
          schema:
            type: boolean
      responses:
        '200':
          $ref: '#/paths/~1scrape/post/responses/200'
        '400':
          $ref: '#/paths/~1scrape/post/responses/400'
        '401':
          $ref: '#/paths/~1scrape/post/responses/401'
        '403':
          $ref: '#/paths/~1scrape/post/responses/403'
        '413':
          $ref: '#/paths/~1scrape/post/responses/413'
        '429':
          $ref: '#/paths/~1scrape/post/responses/429'
        '500':
          $ref: '#/paths/~1scrape/post/responses/500'
        '502':
          $ref: '#/paths/~1scrape/post/responses/502'
        '503':
          $ref: '#/paths/~1scrape/post/responses/503'
        '504':
          $ref: '#/paths/~1scrape/post/responses/504'
    post:
      summary: Scrape a Web Page
      security:
        - ApiKeyAuth: []
      parameters:
        - name: zero_retention
          in: query
          required: false
          description: Same as `zero_retention` in the body. When both are sent, this one is used. Enterprise only.
          schema:
            type: boolean
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScrapeRequest'
      responses:
        '200':
          description: The site answered. `target.status` is the site's own status code, which can be an error such as 404.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScrapeResponse'
        '400':
          description: '`invalid_parameter`: the request is not valid, and `error` names the first problem. `blocked_destination`: the URL, or a page it redirected to, points to a site or address that is not scraped.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScrapeError'
        '401':
          description: The API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: '`not_enabled`: the Scrape API is not turned on for this account. `zero_retention_forbidden`: Zero Data Retention is only available for Enterprise accounts.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScrapeError'
        '413':
          description: '`response_too_large`: the page, or the JSON answer with it, is over 20,000,000 bytes.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScrapeError'
        '429':
          description: An account limit was reached, such as no credits left for the month, the hourly limit or too many scrapes at the same time.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: '`internal_error`: the scrape failed on our side.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScrapeError'
        '502':
          description: '`target_blocked`: the website blocked the request. `target_unreachable`: the website, or a page it redirected to, could not be reached. `target_unreadable`: the website answered, but its page is not text or could not be decoded. `upstream_error`: the scrape could not be completed.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScrapeError'
        '503':
          description: '`service_unavailable`: the scrape service is temporarily unavailable. `session_unavailable`: the session is no longer available, and the same request starts a new one.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScrapeError'
        '504':
          description: '`timeout`: the scrape did not finish within 85 seconds.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScrapeError'
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: 'Use Bearer authentication. Format: "Bearer YOUR_API_KEY"'
    ApiKeyQuery:
      type: apiKey
      in: query
      name: api_key
      description: Your API key as a query parameter, on GET requests only.
  schemas:
    ScrapeRequest:
      type: object
      additionalProperties: false
      required: [url]
      properties:
        url:
          type: string
          maxLength: 8192
          description: 'The page to scrape, as a full `https://` URL on port 80 or 443, without a user name or password, such as `https://en.wikipedia.org/wiki/Web_scraping`. Up to 8,192 bytes. A redirect to an `http://` page is not followed: the response is the redirect itself.'
        method:
          type: string
          enum: [GET, POST]
          default: GET
          description: The HTTP method sent to the site.
        body:
          type: string
          description: The request body sent to the site, up to 1,000,000 bytes. Only `POST` takes a body. Set its `Content-Type` in `headers`.
        headers:
          type: object
          maxProperties: 100
          additionalProperties:
            type: string
          description: 'Request headers sent to the site, such as `{"Accept-Language": "de-DE"}`. A few headers, such as `User-Agent`, `Accept-Encoding` and `Cookie`, are set for you and can''t be sent. `headers` and `cookies` together can be up to 65,536 bytes.'
        cookies:
          type: string
          description: Cookies sent to the site, such as `currency=EUR; theme=dark`.
        country:
          type: string
          default: us
          description: The country the request is sent from, as a two-letter lowercase code.
          enum: ["ad", "ae", "af", "ag", "ai", "al", "am", "ao", "ar", "as", "at", "au", "aw", "az", "ba", "bb", "bd", "be", "bf", "bg", "bh", "bi", "bj", "bm", "bn", "bo", "br", "bs", "bt", "bw", "by", "bz", "ca", "cd", "cg", "ch", "ci", "cl", "cm", "co", "cr", "cv", "cy", "cz", "de", "dj", "dk", "dm", "do", "dz", "ec", "ee", "eg", "es", "fi", "fj", "fm", "fo", "fr", "ga", "gb", "gd", "ge", "gf", "gg", "gh", "gi", "gl", "gm", "gn", "gp", "gq", "gr", "gt", "gu", "gw", "gy", "hk", "hn", "hr", "ht", "hu", "id", "ie", "il", "im", "in", "iq", "is", "it", "je", "jm", "jo", "jp", "ke", "kg", "kh", "km", "kn", "kr", "kw", "ky", "kz", "la", "lb", "lc", "li", "lk", "lr", "ls", "lt", "lu", "lv", "ly", "ma", "mc", "md", "me", "mg", "mk", "ml", "mm", "mn", "mo", "mp", "mq", "mr", "ms", "mt", "mu", "mv", "mw", "mx", "my", "mz", "na", "nc", "ne", "ng", "ni", "nl", "no", "np", "nz", "om", "pa", "pe", "pf", "pg", "ph", "pk", "pl", "pm", "pr", "ps", "pt", "pw", "py", "qa", "re", "ro", "rs", "ru", "rw", "sa", "sc", "sd", "se", "sg", "si", "sk", "sl", "sm", "sn", "so", "sr", "st", "sv", "sy", "sz", "tc", "td", "tg", "th", "tj", "tl", "tm", "tn", "tr", "tt", "tw", "tz", "ua", "ug", "us", "uy", "uz", "vc", "ve", "vg", "vi", "vn", "vu", "ye", "za", "zm", "zw"]
        session_id:
          type: string
          minLength: 1
          maxLength: 255
          pattern: '^[!-~]+$'
          description: Requests with the same `session_id` are sent from the same IP address, for up to 10 minutes. Letters, digits or symbols, without spaces, such as `crawl-42`.
        zero_retention:
          type: boolean
          description: Set to `true` to disable all logging and persistent storage. The answer then has no `id`. Enterprise only.
    ScrapeResponse:
      type: object
      required: [scrape_metadata, target, outputs]
      properties:
        scrape_metadata:
          type: object
          required: [status, created_at, request_time_taken, credits]
          properties:
            id:
              type: string
              description: The scrape's id.
            status:
              type: string
              enum: [completed]
              description: The scrape's outcome.
            created_at:
              type: string
              format: date-time
              description: When the scrape was created, in UTC.
            request_time_taken:
              type: number
              description: How long the scrape took, in seconds.
            credits:
              type: integer
              enum: [0, 1]
              description: What the scrape cost.
        target:
          type: object
          required: [status, final_url, headers]
          properties:
            status:
              type: integer
              description: The site's HTTP status code.
            final_url:
              type: string
              description: The URL of the page, after any redirects.
            headers:
              type: object
              additionalProperties:
                type: array
                items:
                  type: string
              description: The site's response headers, with lowercase names, each with a list of values.
        outputs:
          type: object
          required: [html]
          properties:
            html:
              type: string
              description: The page as text, decoded to UTF-8.
    ScrapeError:
      type: object
      required: [scrape_metadata, error_code, error]
      properties:
        scrape_metadata:
          type: object
          required: [status]
          properties:
            id:
              type: string
              description: The scrape's id.
            status:
              type: string
              enum: [failed]
              description: The scrape's outcome.
            created_at:
              type: string
              format: date-time
              description: When the scrape was created, in UTC.
            request_time_taken:
              type: number
              description: How long the scrape took, in seconds.
            credits:
              type: integer
              enum: [0]
              description: What the scrape cost.
        error_code:
          type: string
          enum: [invalid_parameter, blocked_destination, not_enabled, zero_retention_forbidden, response_too_large, internal_error, target_blocked, target_unreachable, target_unreadable, upstream_error, service_unavailable, session_unavailable, timeout]
          description: Why the scrape failed.
        error:
          type: string
          description: What went wrong, ending with "You were not charged."
        target:
          type: object
          required: [status]
          properties:
            status:
              type: integer
              description: The site's HTTP status code.
    ErrorResponse:
      type: object
      required: [error]
      properties:
        error:
          type: string
          description: What went wrong.
