openapi: 3.1.0
info:
  title: dOCR API
  version: "1.0.0"
  description: |
    The dOCR API extracts structured data from documents — PDFs, scanned images,
    photos, and DOCX files — and returns typed JSON.

    All requests are authenticated with an API key sent as a Bearer token:

    ```
    Authorization: Bearer docr_sk_xxxxxxxxxxxxxxxxxxxxxxxx
    ```

    Create and manage keys in the dashboard under **Developers → API Credentials**.
servers:
  - url: https://app.docr.dev/api/v1
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Extractions
    description: Run extractions and retrieve their results.
  - name: Screenshots
    description: Render a URL or HTML to an image or PDF, and retrieve past renders.
  - name: Captures
    description: A unified view of everything you've captured — screenshots and uploaded documents.
  - name: Account
    description: Credit usage and the available device presets.
  - name: Document Types
    description: List the document types available to your organization.
paths:
  /extract:
    post:
      tags: [Extractions]
      operationId: createExtraction
      summary: Extract data from a document
      description: |
        Upload a single document and receive structured data. The request is
        processed synchronously and the completed extraction is returned.

        Accepted file types: `.pdf`, `.jpg`, `.jpeg`, `.png`, `.bmp`, `.webp`, `.docx`.
        Limits: 10 MB and 15 pages per document.
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [file]
              properties:
                file:
                  type: string
                  format: binary
                  description: The document to extract.
                documentType:
                  type: string
                  description: |
                    Name of the document type to extract against (e.g. `Invoice`).
                    If omitted, dOCR auto-detects the type.
                  example: Invoice
                processingMode:
                  type: string
                  enum: [highest_quality, fastest]
                  default: highest_quality
                  description: |
                    `highest_quality` uses the most capable model; `fastest`
                    optimizes for speed and cost.
      responses:
        "200":
          description: Extraction completed.
          content:
            application/json:
              schema:
                type: object
                properties:
                  extraction:
                    $ref: "#/components/schemas/Extraction"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "422":
          description: The file failed validation (unsupported type, too large, or too many pages).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
  /extractions:
    get:
      tags: [Extractions]
      operationId: listExtractions
      summary: List extractions
      description: Returns your organization's most recent extractions (up to 100).
      responses:
        "200":
          description: A list of extractions.
          content:
            application/json:
              schema:
                type: object
                properties:
                  extractions:
                    type: array
                    items:
                      $ref: "#/components/schemas/Extraction"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
  /extractions/{id}:
    get:
      tags: [Extractions]
      operationId: getExtraction
      summary: Retrieve an extraction
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: The extraction id.
      responses:
        "200":
          description: The extraction.
          content:
            application/json:
              schema:
                type: object
                properties:
                  extraction:
                    $ref: "#/components/schemas/Extraction"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /screenshots:
    post:
      tags: [Screenshots]
      operationId: createScreenshot
      summary: Render a screenshot
      description: |
        Render a web page (`url`) or a raw HTML string (`html`) to a PNG, JPEG,
        WebP image, or a PDF. Provide **exactly one** of `url` or `html`.

        By default the request is **synchronous**: dOCR renders the page and
        returns the finished screenshot record (with a hosted `url`) in the
        response. Set `async: true` to return immediately with a `pending` record
        and receive a [`screenshot.completed`](/docs/guides/webhooks) webhook when
        the render finishes.

        Each successful render costs **1 credit**. Cache hits and failed renders
        cost nothing. See the [Screenshots guide](/docs/guides/screenshots) for a
        full walkthrough of formats, devices, caching, and signed URLs.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ScreenshotRequest"
            examples:
              url:
                summary: Full-page PNG of a URL
                value:
                  url: https://example.com
                  format: png
                  fullPage: true
                  viewportWidth: 1280
              device:
                summary: Mobile screenshot via a device preset
                value:
                  url: https://example.com
                  device: iphone_15
                  blockCookieBanners: true
              html:
                summary: Render raw HTML to a PDF
                value:
                  html: "<h1>Hello, dOCR</h1>"
                  format: pdf
              async:
                summary: Async render delivered by webhook
                value:
                  url: https://example.com
                  async: true
                  webhookUrl: https://api.yourapp.com/hooks/docr
      responses:
        "200":
          description: |
            The render completed. Returns the screenshot record. When `store` is
            `false`, the response body is the raw image bytes instead of JSON,
            with the matching `Content-Type` (`image/png`, `image/jpeg`,
            `image/webp`).
          content:
            application/json:
              schema:
                type: object
                properties:
                  screenshot:
                    $ref: "#/components/schemas/Screenshot"
            image/png:
              schema:
                type: string
                format: binary
        "202":
          description: Accepted for async rendering. Returns a `pending` record.
          content:
            application/json:
              schema:
                type: object
                properties:
                  screenshot:
                    $ref: "#/components/schemas/Screenshot"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "402":
          $ref: "#/components/responses/PaymentRequired"
        "403":
          $ref: "#/components/responses/Forbidden"
        "422":
          description: The options failed validation (e.g. invalid `url`, or both `url` and `html` provided).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
    get:
      tags: [Screenshots]
      operationId: listScreenshots
      summary: List screenshots
      description: Returns your organization's most recent screenshots (up to 100), newest first.
      responses:
        "200":
          description: A list of screenshots.
          content:
            application/json:
              schema:
                type: object
                properties:
                  screenshots:
                    type: array
                    items:
                      $ref: "#/components/schemas/Screenshot"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
  /screenshots/{id}:
    get:
      tags: [Screenshots]
      operationId: getScreenshot
      summary: Retrieve a screenshot
      description: |
        Fetch a single screenshot by id. Useful for polling the `status` of an
        `async` render until it becomes `ready` (or `failed`).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: The screenshot id.
      responses:
        "200":
          description: The screenshot.
          content:
            application/json:
              schema:
                type: object
                properties:
                  screenshot:
                    $ref: "#/components/schemas/Screenshot"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /take:
    get:
      tags: [Screenshots]
      operationId: takeScreenshot
      summary: Render a screenshot from a signed URL
      description: |
        A signed, embeddable variant of `POST /screenshots` that returns the raw
        image bytes directly — so a signed URL can be dropped straight into an
        `<img src>` with **no API key**. PDF output is not supported here; use
        `POST /screenshots` for PDFs.

        Authentication is by **signature**, not a Bearer token. The `signature`
        query parameter is an HMAC-SHA256 of the canonical query string (every
        parameter except `signature`, sorted by key and joined with `&`), keyed
        by your organization's signing secret. See
        [Signed URLs](/docs/guides/screenshots#signed-urls) for how to generate one.

        Every rendering option from `POST /screenshots` (for example `format`,
        `fullPage`, `device`, `darkMode`, `cache`) may be passed as a query
        parameter. Responses set `X-docr-Cache: hit` or `miss` and a one-hour
        `Cache-Control`.
      security: []
      parameters:
        - name: t
          in: query
          required: true
          schema:
            type: string
          description: Your organization id (the signing tenant).
        - name: signature
          in: query
          required: true
          schema:
            type: string
          description: HMAC-SHA256 of the canonical query string (hex).
        - name: url
          in: query
          schema:
            type: string
            format: uri
          description: URL to render. Provide exactly one of `url` or `html`.
        - name: html
          in: query
          schema:
            type: string
          description: Raw HTML to render. Provide exactly one of `url` or `html`.
        - name: format
          in: query
          schema:
            type: string
            enum: [png, jpeg, webp]
            default: png
          description: Image format. `pdf` is not available on this endpoint.
        - name: fullPage
          in: query
          schema:
            type: boolean
            default: false
          description: Capture the full scrollable height of the page.
        - name: cache
          in: query
          schema:
            type: boolean
            default: false
          description: Reuse a stored render for identical options (0 credits on a hit).
      responses:
        "200":
          description: The rendered image bytes.
          headers:
            X-docr-Cache:
              schema:
                type: string
                enum: [hit, miss]
              description: Whether the render was served from cache.
            Cache-Control:
              schema:
                type: string
              description: "`public, max-age=3600`."
          content:
            image/png:
              schema:
                type: string
                format: binary
            image/jpeg:
              schema:
                type: string
                format: binary
            image/webp:
              schema:
                type: string
                format: binary
        "401":
          description: The signature was missing or invalid.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: Invalid signature
        "402":
          $ref: "#/components/responses/PaymentRequired"
        "422":
          description: The options failed validation, or `pdf` was requested.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
  /captures:
    get:
      tags: [Captures]
      operationId: listCaptures
      summary: List captures
      description: |
        Returns a unified, newest-first list of everything your organization has
        captured — both rendered screenshots and uploaded documents — up to 100
        items. Use the `kind` field to tell them apart.
      responses:
        "200":
          description: A list of captures.
          content:
            application/json:
              schema:
                type: object
                properties:
                  captures:
                    type: array
                    items:
                      $ref: "#/components/schemas/Capture"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
  /captures/{id}:
    get:
      tags: [Captures]
      operationId: getCapture
      summary: Retrieve a capture
      description: Fetch a single capture by id, looked up across screenshots and uploaded documents.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: The capture id.
      responses:
        "200":
          description: The capture.
          content:
            application/json:
              schema:
                type: object
                properties:
                  capture:
                    $ref: "#/components/schemas/Capture"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /usage:
    get:
      tags: [Account]
      operationId: getUsage
      summary: Get credit usage
      description: Returns the current billing period's credit usage for the API key's organization.
      responses:
        "200":
          description: Current usage.
          content:
            application/json:
              schema:
                type: object
                properties:
                  usage:
                    type: object
                    properties:
                      plan: { type: string, example: free }
                      planStatus: { type: string, example: active }
                      included: { type: integer, example: 100 }
                      used: { type: integer, example: 37 }
                      available: { type: integer, example: 63 }
                      periodStart: { type: string, example: "2026-06-01" }
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
  /devices:
    get:
      tags: [Account]
      operationId: listDevices
      summary: List device presets
      description: Returns the device presets usable via the `device` screenshot option.
      responses:
        "200":
          description: A list of device presets.
          content:
            application/json:
              schema:
                type: object
                properties:
                  devices:
                    type: array
                    items:
                      type: object
                      properties:
                        name: { type: string, example: iphone_15 }
                        width: { type: integer, example: 393 }
                        height: { type: integer, example: 852 }
                        deviceScaleFactor: { type: number, example: 3 }
                        mobile: { type: boolean, example: true }
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
  /document-types:
    get:
      tags: [Document Types]
      operationId: listDocumentTypes
      summary: List document types
      description: Returns the document types available to your organization, with their fields.
      responses:
        "200":
          description: A list of document types.
          content:
            application/json:
              schema:
                type: object
                properties:
                  documentTypes:
                    type: array
                    items:
                      $ref: "#/components/schemas/DocumentType"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: "API key as a Bearer token: `Authorization: Bearer docr_sk_…`"
  responses:
    BadRequest:
      description: The request was malformed.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Unauthorized:
      description: Missing or invalid API key.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error: Invalid or revoked API key
    Forbidden:
      description: The request IP is not in the organization's whitelist.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error: "IP 203.0.113.4 is not whitelisted"
    NotFound:
      description: The resource was not found.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    PaymentRequired:
      description: The organization's monthly credit allowance is exhausted (Free plan) and the request was blocked.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error: Credit limit reached (100/100). Upgrade your plan.
  schemas:
    Extraction:
      type: object
      properties:
        id:
          type: string
          example: 6a382443304f240b189f228a
        status:
          type: string
          enum: [pending, running, completed, failed]
        documentTypeName:
          type: string
          example: Invoice
        detectedType:
          type: string
          description: Set when the type was auto-detected.
        processingMode:
          type: string
          enum: [highest_quality, fastest]
        confidence:
          type: number
          format: float
          example: 0.98
        pagesProcessed:
          type: integer
          example: 1
        modelUsed:
          type: string
          example: anthropic/claude-opus-4-8
        outputJson:
          $ref: "#/components/schemas/ExtractionOutput"
        error:
          type: string
          description: Present when status is `failed`.
        createdAt:
          type: string
          format: date-time
    ExtractionOutput:
      type: object
      description: The structured result of an extraction.
      properties:
        documentType:
          type: string
          example: Invoice
        fields:
          type: object
          additionalProperties: true
          description: Extracted field values, keyed by the document type's field keys.
          example:
            vendorName: Northwind Traders LLC
            invoiceNumber: INV-2026-00842
            total: 729.61
        confidence:
          type: number
          format: float
        pagesProcessed:
          type: integer
    DocumentType:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
          example: Invoice
        slug:
          type: string
          example: invoice
        isBuiltIn:
          type: boolean
        autoDetectEnabled:
          type: boolean
        fields:
          type: array
          items:
            $ref: "#/components/schemas/Field"
    Field:
      type: object
      properties:
        key:
          type: string
          example: invoiceNumber
        label:
          type: string
          example: Invoice Number
        type:
          type: string
          enum: [string, number, date, boolean, array, object]
        required:
          type: boolean
        description:
          type: string
    Error:
      type: object
      properties:
        error:
          type: string
          description: A human-readable error message.
    ScreenshotRequest:
      type: object
      description: |
        Rendering options. Provide exactly one of `url` or `html`. All other
        fields are optional and fall back to the defaults shown.
      properties:
        url:
          type: string
          format: uri
          description: URL to render. Provide exactly one of `url` or `html`.
          example: https://example.com
        html:
          type: string
          description: Raw HTML to render. Provide exactly one of `url` or `html`.
        format:
          type: string
          enum: [png, jpeg, webp, avif, tiff, pdf]
          default: png
          description: Output format.
        fullPage:
          type: boolean
          default: false
          description: Capture the entire scrollable page rather than just the viewport.
        viewportWidth:
          type: integer
          minimum: 100
          maximum: 3840
          default: 1280
          description: Viewport width in pixels. Ignored when `device` is set.
        viewportHeight:
          type: integer
          minimum: 100
          maximum: 4320
          default: 1024
          description: Viewport height in pixels. Ignored when `device` is set.
        device:
          type: string
          enum: [iphone_15, iphone_se, pixel_8, ipad, macbook, desktop]
          description: |
            A device preset. When set, it overrides `viewportWidth`,
            `viewportHeight`, and `deviceScaleFactor`.
        deviceScaleFactor:
          type: number
          minimum: 1
          maximum: 3
          default: 1
          description: Pixel density. `2` produces a retina-resolution image.
        imageQuality:
          type: integer
          minimum: 0
          maximum: 100
          default: 80
          description: Compression quality for `jpeg` and `webp`. Ignored for `png`.
        omitBackground:
          type: boolean
          default: false
          description: Render a transparent background (PNG/WebP).
        blockAds:
          type: boolean
          default: false
          description: Block known ad networks before rendering.
        blockCookieBanners:
          type: boolean
          default: false
          description: Hide common cookie-consent banners.
        blockChats:
          type: boolean
          default: false
          description: Hide common chat and support widgets.
        delay:
          type: integer
          minimum: 0
          maximum: 30
          default: 0
          description: Seconds to wait after the page loads before capturing.
        waitUntil:
          type: string
          enum: [load, domcontentloaded, networkidle0, networkidle2]
          default: load
          description: The navigation lifecycle event to wait for before capturing.
        waitForSelector:
          type: string
          description: Wait until this CSS selector appears before capturing.
        timeout:
          type: integer
          minimum: 1
          maximum: 90
          default: 60
          description: Maximum seconds to wait for navigation before failing.
        darkMode:
          type: boolean
          description: "Emulate `prefers-color-scheme: dark`."
        cache:
          type: boolean
          default: false
          description: |
            Reuse a previously stored render for an identical set of options.
            A cache hit returns instantly and costs 0 credits.
        cacheTtl:
          type: integer
          minimum: 14400
          maximum: 2592000
          description: How long a cached render stays valid, in seconds (4 hours–30 days).
        async:
          type: boolean
          default: false
          description: |
            Render in the background. Returns a `202` with a `pending` record;
            completion is delivered to `webhookUrl` and your account webhooks.
        webhookUrl:
          type: string
          format: uri
          description: URL to receive the completion event when `async` is true.
        store:
          type: boolean
          default: true
          description: |
            Persist the render to storage and return a hosted `url`. Set to
            `false` to stream the raw bytes back in the response without storing.
        # ── Capture targeting ──
        selector:
          type: string
          description: CSS selector of a single element to screenshot (instead of the page).
        scrollIntoView:
          type: string
          description: CSS selector to scroll into view before capturing.
        clipX:
          type: integer
          description: Left offset of the capture region (with clipY/clipWidth/clipHeight).
        clipY:
          type: integer
          description: Top offset of the capture region.
        clipWidth:
          type: integer
          description: Width of the capture region. Must be set together with clipHeight.
        clipHeight:
          type: integer
          description: Height of the capture region. Must be set together with clipWidth.
        # ── Viewport extras ──
        viewportMobile:
          type: boolean
          default: false
          description: Emulate a mobile device (respects the meta viewport tag).
        viewportHasTouch:
          type: boolean
          default: false
          description: Emulate touch support.
        viewportLandscape:
          type: boolean
          default: false
          description: Emulate landscape orientation.
        # ── Image ──
        imageWidth:
          type: integer
          description: Resize the output image to this width (thumbnail), preserving aspect ratio.
        imageHeight:
          type: integer
          description: Resize the output image to this height (thumbnail), preserving aspect ratio.
        # ── Full page ──
        fullPageScroll:
          type: boolean
          default: false
          description: Scroll to the bottom and back before capturing, to trigger lazy-loaded content.
        fullPageMaxHeight:
          type: integer
          description: Cap the height (px) of a full-page capture; handles infinite-scroll pages.
        # ── PDF ──
        pdfPrintBackground:
          type: boolean
          default: true
          description: Print background graphics in the PDF.
        pdfLandscape:
          type: boolean
          default: false
          description: Use landscape orientation.
        pdfPaperFormat:
          type: string
          enum: [a0, a1, a2, a3, a4, a5, a6, letter, legal, tabloid, ledger]
          description: Paper size for the PDF.
        pdfFitOnePage:
          type: boolean
          default: false
          description: Size the PDF page to fit the full content on one page.
        pdfMargin:
          type: number
          description: Uniform PDF margin in px (overridden by per-side margins).
        pdfMarginTop:
          type: number
        pdfMarginRight:
          type: number
        pdfMarginBottom:
          type: number
        pdfMarginLeft:
          type: number
        # ── Emulations ──
        reducedMotion:
          type: boolean
          default: false
          description: "Emulate `prefers-reduced-motion: reduce`."
        mediaType:
          type: string
          enum: [screen, print]
          description: Emulate the CSS media type.
        # ── Customization ──
        hideSelectors:
          type: array
          items: { type: string }
          description: CSS selectors to hide (display:none) before capturing.
        click:
          type: string
          description: CSS selector to click before capturing.
        hover:
          type: string
          description: CSS selector to hover before capturing.
        styles:
          type: string
          description: Custom CSS injected into the page.
        scripts:
          type: string
          description: Custom JavaScript evaluated in the page before capturing.
        # ── Blocking ──
        blockTrackers:
          type: boolean
          default: false
          description: Block common analytics/tracker requests.
        blockResources:
          type: array
          items:
            type: string
            enum: [document, stylesheet, image, media, font, script, texttrack, xhr, fetch, eventsource, websocket, manifest, other]
          description: Block requests of these resource types.
        blockRequests:
          type: array
          items: { type: string }
          description: Block requests whose URL matches these glob patterns (e.g. `*.ads.com/*`).
        # ── Request ──
        userAgent:
          type: string
          description: Override the User-Agent header.
        authorization:
          type: string
          description: Value for the Authorization request header (for protected pages).
        cookies:
          type: array
          items: { type: string }
          description: Cookies to set, each `name=value; Domain=...; Path=/; Secure`.
        headers:
          type: array
          items: { type: string }
          description: "Extra request headers, each `Header-Name: value`."
        timeZone:
          type: string
          description: Emulate this IANA time zone (e.g. `America/New_York`).
        bypassCsp:
          type: boolean
          default: false
          description: Bypass the page's Content-Security-Policy (needed for some injected scripts).
        navigationTimeout:
          type: integer
          minimum: 1
          maximum: 30
          default: 30
          description: Max seconds to wait for the target site to respond.
        # ── Error guards ──
        ignoreHostErrors:
          type: boolean
          default: false
          description: Screenshot the page even when the host responds with a 4xx/5xx status.
        failIfRequestFailed:
          type: boolean
          default: false
          description: Fail the render if any network request fails during load.
        failIfContentContains:
          type: string
          description: Fail the render if the page text contains this string (case-insensitive).
        failIfContentMissing:
          type: string
          description: Fail the render if the page text does NOT contain this string.
        # ── Metadata ──
        metadataImageSize:
          type: boolean
          default: false
          description: Return the rendered image's width/height/bytes in `metadata`.
        metadataPageTitle:
          type: boolean
          default: false
          description: Return the page `<title>` in `metadata`.
        metadataIcon:
          type: boolean
          default: false
          description: Return the page favicon URL in `metadata`.
        metadataOpenGraph:
          type: boolean
          default: false
          description: Return Open Graph / Twitter card tags in `metadata`.
        metadataContent:
          type: boolean
          default: false
          description: Return the page HTML content in `metadata`.
        metadataHttpStatusCode:
          type: boolean
          default: false
          description: Return the host HTTP status code in `metadata`.
        metadataHttpHeaders:
          type: boolean
          default: false
          description: Return the host HTTP response headers in `metadata`.
        # ── Caching / webhooks ──
        cacheKey:
          type: string
          description: Custom cache key (overrides the computed one) when `cache` is true.
        webhookSign:
          type: boolean
          default: true
          description: Sign the one-off `webhookUrl` delivery with your org signing secret.
        webhookErrors:
          type: boolean
          default: false
          description: Also deliver `screenshot.failed` events to `webhookUrl`.
        externalIdentifier:
          type: string
          description: Correlation id echoed back in webhook events and the `X-docr-External-Identifier` header.
      required: []
    Screenshot:
      type: object
      properties:
        id:
          type: string
          example: 6a382443304f240b189f228a
        orgId:
          type: string
        kind:
          type: string
          enum: [screenshot]
        status:
          type: string
          enum: [pending, rendering, ready, failed]
        format:
          type: string
          enum: [png, jpeg, webp, avif, tiff, pdf]
        url:
          type: string
          nullable: true
          description: Hosted URL of the rendered file. `null` until `status` is `ready`.
          example: https://res.cloudinary.com/docr/image/upload/screenshot-6a382443.png
        width:
          type: integer
          example: 1280
        height:
          type: integer
          example: 3840
        fullPage:
          type: boolean
        cacheHit:
          type: boolean
          description: True when the record was served from cache (billed 0 credits).
        creditsUsed:
          type: integer
          description: Credits charged for this render. `0` for cache hits and failures.
          example: 1
        externalIdentifier:
          type: string
          nullable: true
          description: The caller-supplied correlation id, if one was set.
        metadata:
          type: object
          nullable: true
          additionalProperties: true
          description: |
            On-demand metadata, present only when requested via the `metadata*`
            options — e.g. `title`, `openGraph`, `icon`, `httpStatusCode`,
            `httpHeaders`, `imageSize`, `content`.
        error:
          type: string
          nullable: true
          description: Present when `status` is `failed`.
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    Capture:
      type: object
      properties:
        id:
          type: string
        orgId:
          type: string
        kind:
          type: string
          enum: [screenshot, upload]
          description: Whether the capture is a rendered screenshot or an uploaded document.
        status:
          type: string
          enum: [pending, rendering, ready, failed]
        format:
          type: string
          nullable: true
        url:
          type: string
          nullable: true
          description: Hosted URL of the captured file.
        sourceUrl:
          type: string
          nullable: true
          description: For uploads, the original source URL (when applicable).
        width:
          type: integer
          nullable: true
        height:
          type: integer
          nullable: true
        pageCount:
          type: integer
          nullable: true
          description: Number of pages, for multi-page captures such as PDFs.
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
