openapi: 3.0.3
info:
  title: render-api
  version: 0.1.0
  description: >
    Screenshot + PDF rendering API. Turn any URL (or raw HTML) into a PNG/JPEG
    screenshot or a PDF document. Authenticated with an API key.
servers:
  - url: https://screenshot-e-pdf-render.p.rapidapi.com
    description: Production via RapidAPI gateway (send X-RapidAPI-Key + X-RapidAPI-Host)
  - url: https://api.rendershot.dev
    description: Backend (RapidAPI proxy only; /health, /docs, /openapi.yaml are public)
  - url: http://localhost:8080
    description: Local
security:
  - ApiKeyAuth: []
paths:
  /health:
    get:
      summary: Liveness probe
      security: []
      responses:
        '200':
          description: OK
  /v1/screenshot:
    get:
      summary: Capture a screenshot (query params)
      parameters:
        - { name: url, in: query, required: true, schema: { type: string, format: uri } }
        - { name: type, in: query, schema: { type: string, enum: [png, jpeg, webp], default: png } }
        - { name: fullPage, in: query, schema: { type: boolean, default: false } }
        - { name: width, in: query, schema: { type: integer, default: 1280 } }
        - { name: height, in: query, schema: { type: integer, default: 800 } }
        - { name: deviceScaleFactor, in: query, schema: { type: number, default: 1 } }
        - { name: quality, in: query, schema: { type: integer, minimum: 1, maximum: 100 }, description: JPEG only }
        - { name: omitBackground, in: query, schema: { type: boolean, default: false } }
        - { name: selector, in: query, schema: { type: string }, description: Capture a single element }
        - { name: waitForSelector, in: query, schema: { type: string }, description: Wait for a CSS selector to appear before capturing }
        - { name: device, in: query, schema: { type: string, enum: [iphone_15, iphone_se, pixel_7, galaxy_s9, ipad, ipad_pro] }, description: Emulate a device (overrides width/height) }
        - { name: darkMode, in: query, schema: { type: boolean, default: false }, description: Emulate dark color scheme }
        - { name: blockAds, in: query, schema: { type: boolean, default: false }, description: Block ad/tracker requests for cleaner captures }
        - { name: blockCookieBanners, in: query, schema: { type: boolean, default: false }, description: Hide common cookie/consent banners }
        - { name: waitUntil, in: query, schema: { type: string, enum: [load, domcontentloaded, networkidle, commit], default: load } }
        - { name: delay, in: query, schema: { type: integer, default: 0 }, description: Extra wait in ms }
        - { name: cache, in: query, schema: { type: boolean, default: true }, description: Set false to bypass the response cache }
        - { name: response, in: query, schema: { type: string, enum: [binary, json], default: binary } }
      responses:
        '200':
          description: Image bytes (binary) or base64 JSON
          content:
            image/png: { schema: { type: string, format: binary } }
            image/jpeg: { schema: { type: string, format: binary } }
            application/json:
              schema: { $ref: '#/components/schemas/Base64Response' }
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
        '429': { $ref: '#/components/responses/Error' }
        '504': { $ref: '#/components/responses/Error' }
    post:
      summary: Capture a screenshot (JSON body)
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ScreenshotRequest' }
      responses:
        '200':
          description: Image bytes (binary) or base64 JSON
          content:
            image/png: { schema: { type: string, format: binary } }
            image/jpeg: { schema: { type: string, format: binary } }
            application/json:
              schema: { $ref: '#/components/schemas/Base64Response' }
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
        '429': { $ref: '#/components/responses/Error' }
        '504': { $ref: '#/components/responses/Error' }
  /v1/usage:
    get:
      summary: Usage for the calling API key + cache stats
      responses:
        '200':
          description: Usage report
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UsageResponse' }
        '401': { $ref: '#/components/responses/Error' }
  /v1/pdf:
    post:
      summary: Render a PDF from a URL or raw HTML
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/PdfRequest' }
      responses:
        '200':
          description: PDF bytes (binary) or base64 JSON
          content:
            application/pdf: { schema: { type: string, format: binary } }
            application/json:
              schema: { $ref: '#/components/schemas/Base64Response' }
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
        '429': { $ref: '#/components/responses/Error' }
        '504': { $ref: '#/components/responses/Error' }
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-RapidAPI-Key
      description: >
        Your RapidAPI key. Call the RapidAPI gateway host and also send
        `X-RapidAPI-Host: screenshot-e-pdf-render.p.rapidapi.com`. RapidAPI
        handles authentication, billing and quota.
  responses:
    Error:
      description: Error
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
  schemas:
    Error:
      type: object
      properties:
        error: { type: string }
        message: { type: string }
    Base64Response:
      type: object
      properties:
        format: { type: string }
        encoding: { type: string, example: base64 }
        data: { type: string }
    UsageResponse:
      type: object
      properties:
        key: { type: string }
        usage:
          type: object
          properties:
            requests: { type: integer }
            errors: { type: integer }
            cacheHits: { type: integer }
            bytesOut: { type: integer }
            byEndpoint: { type: object, additionalProperties: { type: integer } }
            firstRequestAt: { type: integer }
            lastRequestAt: { type: integer }
        cache:
          type: object
          properties:
            entries: { type: integer }
            bytes: { type: integer }
            hits: { type: integer }
            misses: { type: integer }
            coalesced: { type: integer }
    ScreenshotRequest:
      type: object
      required: [url]
      properties:
        url: { type: string, format: uri }
        type: { type: string, enum: [png, jpeg, webp], default: png }
        fullPage: { type: boolean, default: false }
        width: { type: integer, default: 1280 }
        height: { type: integer, default: 800 }
        deviceScaleFactor: { type: number, default: 1 }
        quality: { type: integer, minimum: 1, maximum: 100 }
        omitBackground: { type: boolean, default: false }
        selector: { type: string }
        waitForSelector: { type: string }
        device: { type: string, enum: [iphone_15, iphone_se, pixel_7, galaxy_s9, ipad, ipad_pro] }
        darkMode: { type: boolean, default: false }
        blockAds: { type: boolean, default: false }
        blockCookieBanners: { type: boolean, default: false }
        waitUntil: { type: string, enum: [load, domcontentloaded, networkidle, commit], default: load }
        delay: { type: integer, default: 0 }
        timeout: { type: integer }
        cache: { type: boolean, default: true }
        response: { type: string, enum: [binary, json], default: binary }
    PdfRequest:
      type: object
      description: Provide either url or html.
      properties:
        url: { type: string, format: uri }
        html: { type: string }
        format: { type: string, enum: [A4, A3, A5, Letter, Legal, Tabloid], default: A4 }
        landscape: { type: boolean, default: false }
        printBackground: { type: boolean, default: true }
        scale: { type: number, default: 1, minimum: 0.1, maximum: 2 }
        marginTop: { type: string, default: '0' }
        marginBottom: { type: string, default: '0' }
        marginLeft: { type: string, default: '0' }
        marginRight: { type: string, default: '0' }
        waitUntil: { type: string, enum: [load, domcontentloaded, networkidle, commit], default: load }
        delay: { type: integer, default: 0 }
        timeout: { type: integer }
        pageRanges: { type: string, example: '1-3' }
        waitForSelector: { type: string, description: Wait for a CSS selector before rendering }
        header: { type: string, description: HTML template for the page header }
        footer: { type: string, description: HTML template for the page footer }
        pageNumbers: { type: boolean, default: false, description: Add "N / total" page numbers in the footer }
        cache: { type: boolean, default: true }
        response: { type: string, enum: [binary, json], default: binary }
