openapi: 3.1.0
info:
  title: ScrapeNest Customer API
  description: Customer-facing API for submitting scraping jobs, monitoring status, managing access, and
    downloading artifacts.
  termsOfService: https://scrapenest.com/legal/terms
  contact:
    name: ScrapeNest Support
    url: https://scrapenest.com/contact
    email: support@scrapenest.com
  license:
    name: Proprietary
    url: https://scrapenest.com/legal/terms
  version: 1.0.0
servers:
- url: https://api.scrapenest.com
  description: Production
security:
- ApiKeyAuth: []
paths:
  /api/v1/artifacts/{artifact_id}/download:
    get:
      tags:
      - Artifacts
      summary: Get artifact download URL
      description: Issue a short-lived presigned download URL for an artifact. Requires the `artifacts.read`
        scope.
      operationId: getArtifactDownload
      parameters:
      - $ref: '#/components/parameters/ArtifactId'
      - $ref: '#/components/parameters/TtlSeconds'
      responses:
        '200':
          description: Download URL response
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ArtifactDownloadResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
  /api/v1/jobs:
    get:
      tags:
      - Jobs
      summary: List jobs
      description: List the organization's jobs. Requires the `jobs.read` scope. Results are paginated
        with `limit`/`offset` and ordered newest-first.
      operationId: listJobs
      parameters:
      - name: status
        in: query
        required: false
        schema:
          type: string
          enum:
          - queued
          - running
          - succeeded
          - failed
      - name: job_type
        in: query
        required: false
        schema:
          type: string
          enum:
          - light
          - standard
          - stealth
      - name: job_id
        in: query
        required: false
        schema:
          type: string
          format: uuid
      - name: target_url
        in: query
        required: false
        schema:
          type: string
          format: uri
      - name: tag
        in: query
        required: false
        schema:
          type: string
      - name: from
        in: query
        description: Only jobs created at or after this instant (ISO-8601).
        required: false
        schema:
          type: string
          format: date-time
      - name: to
        in: query
        description: Only jobs created at or before this instant (ISO-8601).
        required: false
        schema:
          type: string
          format: date-time
      - $ref: '#/components/parameters/Limit'
      - $ref: '#/components/parameters/Offset'
      responses:
        '200':
          description: Job list
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JobListResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerError'
    post:
      tags:
      - Jobs
      summary: Create a scraping job
      description: 'Submit a scraping job. Requires the `jobs.create` scope. Supply `idempotency_token`
        to make retries safe: re-submitting the same token returns the original job with HTTP 200 instead
        of creating a new one (201).'
      operationId: createJob
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/JobCreateRequest'
      responses:
        '201':
          description: Job created
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JobAccepted'
        '200':
          description: Existing job returned (idempotent replay).
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JobAccepted'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerError'
      x-codeSamples:
      - lang: Python
        label: Python SDK
        source: 'from scrapenest import ScrapeNestClient


          client = ScrapeNestClient(api_key="sn_live_...", base_url="https://api.scrapenest.com")

          result = client.scrape_sync(job_type="light", target_url="https://example.com")

          print(result.status, result.artifact_count)'
      - lang: Shell
        label: curl
        source: "curl -X POST \"https://api.scrapenest.com/api/v1/jobs\" \\\n  -H \"X-API-Key: sn_live_...\"\
          \ \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"job_type\": \"light\", \"target_url\"\
          : \"https://example.com\"}'"
  /api/v1/jobs/{job_id}:
    get:
      tags:
      - Jobs
      summary: Get job status
      description: Fetch a single job. Requires the `jobs.read` scope. Pass `include_download_urls=true`
        to receive presigned artifact URLs (also returned automatically for terminal jobs); when omitted/false,
        each artifact's `download_url` and `expires_at` are null.
      operationId: getJob
      parameters:
      - $ref: '#/components/parameters/JobId'
      - name: include_download_urls
        in: query
        description: Include presigned artifact download URLs in the response. Presigned URLs are also
          returned automatically once a job reaches a terminal state, so this flag only matters while
          a job is still running. Defaults to false.
        required: false
        schema:
          type: boolean
      - name: ttl_seconds
        in: query
        description: Override presigned URL TTL in seconds when include_download_urls is true.
        required: false
        schema:
          type: integer
          maximum: 86400
          minimum: 60
      responses:
        '200':
          description: Job status
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Job'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/ServerError'
  /api/v1/org/security/ip-allowlist:
    get:
      tags:
      - Organization Security
      summary: Get organization IP allowlist
      operationId: getOrgAllowlist
      responses:
        '200':
          description: Org allowlist
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrgAllowlistResponse'
    put:
      tags:
      - Organization Security
      summary: Update organization IP allowlist
      operationId: updateOrgAllowlist
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrgAllowlistRequest'
      responses:
        '200':
          description: Org allowlist updated
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrgAllowlistResponse'
  /api/v1/org/retention-holds:
    get:
      tags:
      - Retention
      summary: List legal holds for the current organization
      operationId: listRetentionHolds
      responses:
        '200':
          description: Legal holds
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RetentionHoldListResponse'
    post:
      tags:
      - Retention
      summary: Create a legal hold
      operationId: createRetentionHold
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RetentionHoldCreateRequest'
      responses:
        '201':
          description: Hold created
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RetentionHoldResponse'
  /api/v1/org/retention-holds/{hold_id}/release:
    post:
      tags:
      - Retention
      summary: Release a legal hold
      description: Release an active legal hold. Requires the `retention.manage` scope.
      operationId: releaseRetentionHold
      parameters:
      - $ref: '#/components/parameters/HoldId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RetentionHoldReleaseRequest'
      responses:
        '200':
          description: Hold released
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RetentionHoldReleaseResponse'
        '404':
          $ref: '#/components/responses/NotFound'
  /api/v1/org/retention-policy:
    get:
      tags:
      - Retention
      summary: Get retention policy for the current organization
      operationId: getRetentionPolicy
      responses:
        '200':
          description: Retention policy
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RetentionPolicyResponse'
    put:
      tags:
      - Retention
      summary: Update retention policy for the current organization
      operationId: updateRetentionPolicy
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RetentionPolicyUpdateRequest'
      responses:
        '200':
          description: Retention policy updated
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RetentionPolicyResponse'
        '409':
          $ref: '#/components/responses/Conflict'
  /api/v1/webhook-endpoints:
    get:
      tags:
      - Webhooks
      summary: List webhook endpoints
      operationId: listWebhookEndpoints
      responses:
        '200':
          description: Webhook endpoints list
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpointListResponse'
    post:
      tags:
      - Webhooks
      summary: Create webhook endpoint
      operationId: createWebhookEndpoint
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEndpointCreateRequest'
      responses:
        '201':
          description: Webhook endpoint created
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpointCreateResponse'
  /api/v1/webhook-endpoints/{endpoint_id}:
    put:
      tags:
      - Webhooks
      summary: Update webhook endpoint
      operationId: updateWebhookEndpoint
      parameters:
      - $ref: '#/components/parameters/EndpointId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEndpointUpdateRequest'
      responses:
        '200':
          description: Webhook endpoint updated
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpointUpdateResponse'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      tags:
      - Webhooks
      summary: Delete webhook endpoint
      description: Soft-delete a webhook endpoint. Requires the `webhooks.manage` scope.
      operationId: deleteWebhookEndpoint
      parameters:
      - $ref: '#/components/parameters/EndpointId'
      responses:
        '204':
          description: Webhook endpoint deleted
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          $ref: '#/components/responses/ServerError'
  /api/v1/webhook-endpoints/{endpoint_id}/rotate-secret:
    post:
      tags:
      - Webhooks
      summary: Rotate webhook endpoint secret
      operationId: rotateWebhookEndpointSecret
      parameters:
      - $ref: '#/components/parameters/EndpointId'
      responses:
        '200':
          description: Webhook endpoint secret rotated
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpointRotateResponse'
        '404':
          $ref: '#/components/responses/NotFound'
  /api/v1/webhook-endpoints/{endpoint_id}/pause:
    post:
      tags:
      - Webhooks
      summary: Pause webhook endpoint
      operationId: pauseWebhookEndpoint
      parameters:
      - $ref: '#/components/parameters/EndpointId'
      responses:
        '200':
          description: Webhook endpoint paused
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpointPauseResponse'
        '404':
          $ref: '#/components/responses/NotFound'
  /api/v1/webhook-endpoints/{endpoint_id}/resume:
    post:
      tags:
      - Webhooks
      summary: Resume webhook endpoint
      operationId: resumeWebhookEndpoint
      parameters:
      - $ref: '#/components/parameters/EndpointId'
      responses:
        '200':
          description: Webhook endpoint resumed
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpointResumeResponse'
        '404':
          $ref: '#/components/responses/NotFound'
  /api/v1/webhook-endpoints/{endpoint_id}/deliveries:
    get:
      tags:
      - Webhooks
      summary: List webhook delivery attempts
      operationId: listWebhookDeliveries
      parameters:
      - $ref: '#/components/parameters/EndpointId'
      - name: event_id
        in: query
        required: false
        schema:
          type: string
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 200
          minimum: 1
      - name: offset
        in: query
        required: false
        schema:
          type: integer
          minimum: 0
      responses:
        '200':
          description: Webhook delivery attempts
          headers:
            x-api-version:
              $ref: '#/components/headers/ApiVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookDeliveryAttemptListResponse'
        '404':
          $ref: '#/components/responses/NotFound'
tags:
- name: Jobs
  description: Scraping job submission and status.
- name: Artifacts
  description: Job artifact download URLs.
- name: Webhooks
  description: Webhook endpoint management and delivery history.
- name: Retention
  description: Artifact retention policy and legal holds.
- name: Organization Security
  description: Organization-level IP allowlist controls.
components:
  schemas:
    WebhookDeliveryAttemptListResponse:
      required:
      - endpoint_id
      - items
      - limit
      - offset
      properties:
        endpoint_id:
          type: string
          format: uuid
        items:
          type: array
          items:
            $ref: '#/components/schemas/WebhookDeliveryAttemptSummary'
        limit:
          type: integer
          minimum: 1
        offset:
          type: integer
          minimum: 0
      type: object
    RetentionHoldResponse:
      required:
      - hold_id
      - org_id
      - scope_type
      - scope_ref
      - status
      - justification
      - created_at
      - expires_at
      - released_at
      properties:
        hold_id:
          type: string
          format: uuid
        org_id:
          type: string
          format: uuid
        scope_type:
          type: string
          enum:
          - org
          - job
          - artifact
        scope_ref:
          type:
          - string
          - 'null'
          format: uuid
        status:
          type: string
          enum:
          - active
          - released
        justification:
          type: string
        created_at:
          type: string
          format: date-time
        expires_at:
          type:
          - string
          - 'null'
          format: date-time
        released_at:
          type:
          - string
          - 'null'
          format: date-time
      type: object
    RetentionPolicyResponse:
      required:
      - org_id
      - retention_days
      - max_retention_days
      - legal_hold_enabled
      - policy_version
      - updated_at
      properties:
        org_id:
          type: string
          format: uuid
        retention_days:
          type: integer
          minimum: 1
        max_retention_days:
          description: Upper bound the organization may set for retention_days.
          type: integer
          minimum: 1
        legal_hold_enabled:
          type: boolean
        policy_version:
          type: integer
          minimum: 1
        updated_at:
          type:
          - string
          - 'null'
          format: date-time
      type: object
    WebhookEndpointListResponse:
      required:
      - items
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/WebhookEndpointSummary'
      type: object
    WebhookEndpointUpdateResponse:
      required:
      - endpoint_id
      - name
      - description
      - url
      - status
      - metadata
      - retry_config
      - updated_at
      properties:
        endpoint_id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type:
          - string
          - 'null'
        url:
          type: string
          format: uri
        status:
          type: string
          enum:
          - active
          - paused
          - disabled
          - deleted
        metadata:
          oneOf:
          - $ref: '#/components/schemas/WebhookMetadata'
          - type: 'null'
        retry_config:
          oneOf:
          - $ref: '#/components/schemas/WebhookRetryConfig'
          - type: 'null'
        updated_at:
          type: string
          format: date-time
      type: object
    RetentionPolicyUpdateRequest:
      description: Full replacement of the retention policy. retention_days must not exceed max_retention_days
        (see the policy response); requests that would shorten retention below an active legal hold are
        rejected with 409.
      required:
      - retention_days
      - legal_hold_enabled
      properties:
        retention_days:
          type: integer
          maximum: 3650
          minimum: 1
        legal_hold_enabled:
          type: boolean
      type: object
      additionalProperties: false
    WebhookEndpointCreateResponse:
      description: 'New endpoints start in `active`. Deliveries are signed using the Svix scheme: each
        POST carries `svix-id`, `svix-timestamp`, and `svix-signature` headers. The signature is `v1,<base64>`
        where `<base64>` is the HMAC-SHA256 of `"<svix-id>.<svix-timestamp>.<raw_body>"` keyed by `secret`.
        Reject deliveries whose timestamp is outside the allowed tolerance (default 5 minutes).'
      required:
      - endpoint_id
      - name
      - description
      - url
      - status
      - secret
      - secret_prefix
      - metadata
      - retry_config
      - dispatcher_endpoint_id
      - created_at
      - updated_at
      properties:
        endpoint_id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type:
          - string
          - 'null'
        url:
          type: string
          format: uri
        status:
          type: string
          enum:
          - active
          - paused
          - disabled
          - deleted
        secret:
          description: Signing secret — shown once only.
          type: string
        secret_prefix:
          type: string
        metadata:
          oneOf:
          - $ref: '#/components/schemas/WebhookMetadata'
          - type: 'null'
        retry_config:
          oneOf:
          - $ref: '#/components/schemas/WebhookRetryConfig'
          - type: 'null'
        dispatcher_endpoint_id:
          type:
          - string
          - 'null'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      type: object
    RetentionHoldReleaseResponse:
      required:
      - hold_id
      - status
      - released_at
      properties:
        hold_id:
          type: string
          format: uuid
        status:
          type: string
          enum:
          - released
        released_at:
          type: string
          format: date-time
      type: object
    OrgAllowlistRequest:
      description: Replaces the organization IP allowlist. An empty array removes the org-level restriction;
        the effective allowlist for a key is this list intersected with any non-empty key allowlist.
      required:
      - allowed_cidrs
      properties:
        allowed_cidrs:
          type: array
          items:
            $ref: '#/components/schemas/CidrBlock'
          uniqueItems: true
      type: object
      additionalProperties: false
    WebhookEndpointCreateRequest:
      required:
      - name
      - url
      properties:
        name:
          type: string
          maxLength: 120
          minLength: 1
        url:
          description: HTTPS endpoint that will receive signed event POSTs. Plain HTTP is rejected except
            for localhost in non-production. Every endpoint receives all event types.
          type: string
          format: uri
        description:
          type:
          - string
          - 'null'
          maxLength: 500
        metadata:
          oneOf:
          - $ref: '#/components/schemas/WebhookMetadata'
          - type: 'null'
        retry_config:
          oneOf:
          - $ref: '#/components/schemas/WebhookRetryConfig'
          - type: 'null'
      type: object
      additionalProperties: false
    OrgAllowlistResponse:
      required:
      - org_id
      - allowed_cidrs
      properties:
        org_id:
          type: string
          format: uuid
        allowed_cidrs:
          type: array
          items:
            $ref: '#/components/schemas/CidrBlock'
      type: object
    RetentionHoldCreateRequest:
      required:
      - scope_type
      - justification
      properties:
        scope_type:
          type: string
          enum:
          - org
          - job
          - artifact
        scope_ref:
          description: Target id. Required when scope_type is job or artifact; must be null/omitted when
            scope_type is org.
          type:
          - string
          - 'null'
          format: uuid
        justification:
          type: string
          maxLength: 2000
          minLength: 1
        expires_at:
          description: Optional auto-expiry; null keeps the hold until explicitly released.
          type:
          - string
          - 'null'
          format: date-time
      type: object
      additionalProperties: false
    WebhookEndpointRotateResponse:
      description: Rotation returns a new signing secret and invalidates the previous one. Update consumers
        before rotating.
      required:
      - endpoint_id
      - secret
      - secret_prefix
      - rotated_at
      properties:
        endpoint_id:
          type: string
          format: uuid
        secret:
          description: New signing secret — shown once only.
          type: string
        secret_prefix:
          type: string
        rotated_at:
          type: string
          format: date-time
      type: object
    ArtifactDownloadResponse:
      required:
      - artifact_id
      - download_url
      - expires_at
      properties:
        artifact_id:
          type: string
          format: uuid
        download_url:
          type: string
          format: uri
        expires_at:
          type: string
          format: date-time
      type: object
    WebhookEndpointUpdateRequest:
      description: Full replacement of the endpoint configuration. Nullable fields sent as null are cleared.
      required:
      - name
      - url
      properties:
        name:
          type: string
          maxLength: 120
          minLength: 1
        url:
          type: string
          format: uri
        description:
          type:
          - string
          - 'null'
          maxLength: 500
        metadata:
          oneOf:
          - $ref: '#/components/schemas/WebhookMetadata'
          - type: 'null'
        retry_config:
          oneOf:
          - $ref: '#/components/schemas/WebhookRetryConfig'
          - type: 'null'
      type: object
      additionalProperties: false
    RetentionHoldListResponse:
      required:
      - org_id
      - items
      properties:
        org_id:
          type: string
          format: uuid
        items:
          type: array
          items:
            $ref: '#/components/schemas/RetentionHoldResponse'
      type: object
    Error:
      description: Standard error envelope returned for every non-2xx response.
      required:
      - error
      properties:
        error:
          $ref: '#/components/schemas/ErrorBody'
      type: object
      additionalProperties: false
    JobCreateRequest:
      description: Submit a scraping job. The allowed fields depend on `job_type`.
      discriminator:
        propertyName: job_type
        mapping:
          light: '#/components/schemas/LightJobCreateRequest'
          standard: '#/components/schemas/StandardJobCreateRequest'
          stealth: '#/components/schemas/StealthJobCreateRequest'
      oneOf:
      - $ref: '#/components/schemas/LightJobCreateRequest'
      - $ref: '#/components/schemas/StandardJobCreateRequest'
      - $ref: '#/components/schemas/StealthJobCreateRequest'
    WebhookEndpointSummary:
      required:
      - endpoint_id
      - name
      - description
      - url
      - status
      - secret_prefix
      - metadata
      - retry_config
      - dispatcher_endpoint_id
      - consecutive_failures
      - last_health_status
      - last_health_checked_at
      - created_at
      - updated_at
      properties:
        endpoint_id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type:
          - string
          - 'null'
        url:
          type: string
          format: uri
        status:
          type: string
          enum:
          - active
          - paused
          - disabled
          - deleted
        secret_prefix:
          type: string
        metadata:
          oneOf:
          - $ref: '#/components/schemas/WebhookMetadata'
          - type: 'null'
        retry_config:
          oneOf:
          - $ref: '#/components/schemas/WebhookRetryConfig'
          - type: 'null'
        dispatcher_endpoint_id:
          type:
          - string
          - 'null'
        consecutive_failures:
          type: integer
          minimum: 0
        last_health_status:
          description: Result of the most recent health probe; null before the first probe.
          type:
          - string
          - 'null'
        last_health_checked_at:
          type:
          - string
          - 'null'
          format: date-time
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      type: object
    Job:
      required:
      - job_id
      - job_type
      - status
      - target_url
      - tags
      - created_at
      - completed_at
      - failure_reason
      - artifact_ids
      - artifacts
      properties:
        job_id:
          type: string
          format: uuid
        job_type:
          description: Worker tier that ran the job.
          type: string
          enum:
          - light
          - standard
          - stealth
        status:
          type: string
          enum:
          - queued
          - running
          - succeeded
          - failed
        target_url:
          type: string
          format: uri
        tags:
          type: array
          items:
            type: string
        created_at:
          type: string
          format: date-time
        completed_at:
          type:
          - string
          - 'null'
          format: date-time
        failure_reason:
          type:
          - string
          - 'null'
        artifact_ids:
          type: array
          items:
            type: string
            format: uuid
        artifacts:
          type: array
          items:
            $ref: '#/components/schemas/JobArtifact'
      type: object
    WebhookEndpointPauseResponse:
      required:
      - endpoint_id
      - status
      - paused_at
      properties:
        endpoint_id:
          type: string
          format: uuid
        status:
          type: string
          enum:
          - paused
        paused_at:
          type: string
          format: date-time
      type: object
    JobListResponse:
      required:
      - items
      - total
      - limit
      - offset
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/JobSummary'
        total:
          type: integer
          minimum: 0
        limit:
          type: integer
          minimum: 1
        offset:
          type: integer
          minimum: 0
      type: object
    LightJobCreateRequest:
      description: HTTP-only job (Light tier).
      allOf:
      - $ref: '#/components/schemas/JobCreateBase'
      - required:
        - job_type
        properties:
          job_type:
            type: string
            enum:
            - light
          method:
            description: HTTP method.
            type: string
            default: GET
            enum:
            - GET
            - POST
            - PUT
            - PATCH
            - DELETE
            - HEAD
          body:
            description: Raw request body for POST/PUT/PATCH (sent verbatim).
            type: string
          follow_redirects:
            description: Follow 3xx redirects.
            type: boolean
            default: true
          retry_policy:
            $ref: '#/components/schemas/JobRetryPolicy'
        type: object
    RetentionHoldReleaseRequest:
      required:
      - release_notes
      properties:
        release_notes:
          type: string
          maxLength: 2000
          minLength: 1
      type: object
      additionalProperties: false
    WebhookEndpointResumeResponse:
      required:
      - endpoint_id
      - status
      - resumed_at
      properties:
        endpoint_id:
          type: string
          format: uuid
        status:
          type: string
          enum:
          - active
        resumed_at:
          type: string
          format: date-time
      type: object
    JobAccepted:
      description: Acknowledgement returned when a job is accepted. Poll GET /jobs/{job_id} (or use webhooks)
        for the full job once it runs.
      required:
      - job_id
      - status
      - created_at
      - artifact_ids
      properties:
        job_id:
          type: string
          format: uuid
        status:
          type: string
          enum:
          - queued
          - running
          - succeeded
          - failed
        created_at:
          type: string
          format: date-time
        artifact_ids:
          type: array
          items:
            type: string
            format: uuid
      type: object
    WebhookDeliveryAttemptSummary:
      required:
      - id
      - event_id
      - event_type
      - attempt_no
      - status
      - status_code
      - latency_ms
      - dispatched_at
      - recorded_at
      - dispatcher_node
      - request_id
      - error_message
      properties:
        id:
          type: string
          format: uuid
        event_id:
          description: Id of the event being delivered.
          type: string
        event_type:
          description: Event topic, e.g. job.succeeded, job.failed, artifact.created.
          type: string
        attempt_no:
          type: integer
          minimum: 1
        status:
          description: Outcome of this attempt (e.g. success, failure).
          type: string
        status_code:
          description: HTTP status returned by the consumer endpoint.
          type:
          - integer
          - 'null'
        latency_ms:
          type:
          - integer
          - 'null'
          minimum: 0
        dispatched_at:
          type: string
          format: date-time
        recorded_at:
          type: string
          format: date-time
        dispatcher_node:
          type:
          - string
          - 'null'
        request_id:
          type:
          - string
          - 'null'
        error_message:
          type:
          - string
          - 'null'
      type: object
    JobSummary:
      required:
      - job_id
      - job_type
      - status
      - target_url
      - tags
      - created_at
      - updated_at
      - completed_at
      properties:
        job_id:
          type: string
          format: uuid
        job_type:
          type: string
          enum:
          - light
          - standard
          - stealth
        status:
          type: string
          enum:
          - queued
          - running
          - succeeded
          - failed
        target_url:
          type: string
          format: uri
        tags:
          type: array
          items:
            type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type:
          - string
          - 'null'
          format: date-time
        completed_at:
          type:
          - string
          - 'null'
          format: date-time
      type: object
    CidrBlock:
      description: An IPv4 or IPv6 CIDR block.
      type: string
      pattern: ^([0-9]{1,3}\.){3}[0-9]{1,3}(/([0-9]|[1-2][0-9]|3[0-2]))?$|^([0-9a-fA-F:]+)(/(1[0-2][0-8]|[0-9]?[0-9]))?$
      example: 10.0.0.0/8
    WebhookMetadata:
      description: Customer-defined string key/value pairs echoed back on the endpoint. Max 20 keys.
      maxProperties: 20
      type: object
      additionalProperties:
        type: string
    StandardJobCreateRequest:
      description: Headless-browser job (Standard tier).
      allOf:
      - $ref: '#/components/schemas/JobCreateBase'
      - $ref: '#/components/schemas/BrowserJobFields'
      - required:
        - job_type
        properties:
          job_type:
            type: string
            enum:
            - standard
        type: object
    WebhookRetryConfig:
      description: Delivery retry policy. Omitted fields fall back to platform defaults.
      properties:
        max_attempts:
          description: Maximum delivery attempts before the event is abandoned.
          type: integer
          maximum: 20
          minimum: 1
        initial_delay_seconds:
          description: Delay before the first retry, in seconds.
          type: integer
          maximum: 3600
          minimum: 1
        max_delay_seconds:
          description: Upper bound on the retry delay, in seconds.
          type: integer
          maximum: 86400
          minimum: 1
        backoff_multiplier:
          description: Exponential backoff multiplier.
          type: number
          maximum: 10
          minimum: 1
        timeout_seconds:
          description: Per-attempt HTTP timeout, in seconds.
          type: integer
          maximum: 60
          minimum: 1
      type: object
    JobCreateBase:
      description: Fields common to every job tier.
      required:
      - job_type
      - target_url
      properties:
        job_type:
          type: string
          enum:
          - light
          - standard
          - stealth
        target_url:
          description: Target URL to scrape (http or https).
          type: string
          format: uri
        timeout_ms:
          description: Overall job timeout in ms.
          type: integer
          default: 30000
          maximum: 300000
          minimum: 1000
        tags:
          description: Free-form labels for filtering and grouping.
          type: array
          items:
            type: string
          maxItems: 20
        idempotency_token:
          description: Idempotency token — re-submitting with the same token returns the original job
            (HTTP 200 instead of 201).
          type: string
        headers:
          description: Request/navigation headers to send to the target. Hop-by-hop and auth headers (Host,
            Content-Length, Connection, Authorization, Cookie, Proxy-Authorization, Transfer-Encoding)
            are rejected.
          type: object
          additionalProperties:
            type: string
        user_agent:
          description: Override the User-Agent header.
          type: string
        artifact_options:
          $ref: '#/components/schemas/JobArtifactOptions'
        extraction:
          $ref: '#/components/schemas/JobExtraction'
      type: object
    ErrorBody:
      required:
      - code
      - message
      properties:
        code:
          description: Stable, machine-readable error code.
          type: string
          example: not_found
        message:
          description: Human-readable explanation.
          type: string
          example: Resource not found.
        request_id:
          description: Correlation id for this request; quote it in support tickets.
          type:
          - string
          - 'null'
          example: req_01HZX9K3M7N4P5Q6R7S8T9V0W1
        details:
          description: Field-level validation problems, when applicable.
          type:
          - array
          - 'null'
          items:
            $ref: '#/components/schemas/ErrorDetail'
      type: object
      additionalProperties: false
    StealthJobCreateRequest:
      description: Anti-blocking browser job (Stealth tier).
      allOf:
      - $ref: '#/components/schemas/JobCreateBase'
      - $ref: '#/components/schemas/BrowserJobFields'
      - required:
        - job_type
        properties:
          job_type:
            type: string
            enum:
            - stealth
          os_name:
            description: Spoof the OS profile.
            type: string
            enum:
            - windows
            - macos
            - linux
          browser_extensions:
            description: Helper extension slugs.
            type: array
            items:
              type: string
              enum:
              - ublock
              - isdcac
            uniqueItems: true
          proxy:
            $ref: '#/components/schemas/JobProxy'
        type: object
    JobExtraction:
      description: Built-in structured data extraction. Up to 25 hooks per job, 50 results per hook.
      required:
      - hooks
      properties:
        hooks:
          type: array
          items:
            $ref: '#/components/schemas/JobExtractionHook'
          maxItems: 25
          minItems: 1
      type: object
      additionalProperties: false
    JobRetryPolicy:
      description: Per-job retry rules (Light tier).
      required:
      - max_attempts
      properties:
        max_attempts:
          type: integer
          maximum: 10
          minimum: 1
          example: 3
        retry_on_status:
          type: array
          items:
            type: integer
            maximum: 599
            minimum: 100
          uniqueItems: true
          example:
          - 429
          - 500
          - 502
        retry_methods:
          type: array
          items:
            type: string
            enum:
            - GET
            - HEAD
            - OPTIONS
            - PUT
            - DELETE
            - POST
            - PATCH
          uniqueItems: true
          example:
          - GET
      type: object
      additionalProperties: false
    JobExtractionHook:
      description: A single extraction rule. The required fields depend on `type`.
      discriminator:
        propertyName: type
        mapping:
          css: '#/components/schemas/CssExtractionHook'
          regex: '#/components/schemas/RegexExtractionHook'
          jsonpath: '#/components/schemas/JsonPathExtractionHook'
      oneOf:
      - $ref: '#/components/schemas/CssExtractionHook'
      - $ref: '#/components/schemas/RegexExtractionHook'
      - $ref: '#/components/schemas/JsonPathExtractionHook'
    JobArtifactOptions:
      description: Selects which artifacts a job produces and how the page loads. Browser-only flags apply
        to Standard/Stealth.
      properties:
        include_html:
          type: boolean
          default: true
        include_response_body:
          type: boolean
          default: false
        include_extraction:
          description: Run extraction hooks and save results as JSON.
          type: boolean
          default: false
        include_screenshot:
          description: Browser tiers only. Capture a PNG screenshot.
          type: boolean
          default: false
        include_har:
          description: Browser tiers only. Capture a network HAR trace.
          type: boolean
          default: false
        include_console:
          description: Browser tiers only. Capture console logs.
          type: boolean
          default: false
        block_images:
          description: Browser tiers only.
          type: boolean
          default: false
        block_stylesheets:
          description: Browser tiers only.
          type: boolean
          default: false
        block_media:
          description: Browser tiers only.
          type: boolean
          default: false
        block_fonts:
          description: Browser tiers only.
          type: boolean
          default: false
        no_scroll:
          description: Browser tiers only. Disable auto-scroll before capture.
          type: boolean
          default: false
      type: object
      additionalProperties: false
    JobProxy:
      description: Custom egress proxy (Stealth tier). Omit to use the managed pool.
      required:
      - server
      properties:
        server:
          type: string
          format: uri
          example: http://host:3128
        bypass:
          description: Comma-separated hosts to bypass the proxy for.
          type:
          - string
          - 'null'
          example: '*.example.com'
        username:
          description: Proxy username, when the proxy requires authentication.
          type:
          - string
          - 'null'
        password:
          description: Proxy password, when the proxy requires authentication.
          type:
          - string
          - 'null'
      type: object
      additionalProperties: false
    JobArtifact:
      required:
      - artifact_id
      - artifact_type
      - byte_size
      - content_hash
      - created_at
      - download_url
      - expires_at
      properties:
        artifact_id:
          type: string
          format: uuid
        artifact_type:
          type: string
          enum:
          - html
          - response_body
          - screenshot
          - har
          - console
          - extraction
          - manifest
          example: html
        byte_size:
          type: integer
          minimum: 0
        content_hash:
          description: SHA-256 of the artifact content (hex).
          type: string
          pattern: ^[a-f0-9]{64}$
        created_at:
          type: string
          format: date-time
        download_url:
          description: Presigned download URL; null unless include_download_urls was requested.
          type:
          - string
          - 'null'
          format: uri
        expires_at:
          description: Expiry of download_url; null when download_url is null.
          type:
          - string
          - 'null'
          format: date-time
      type: object
    BrowserJobFields:
      description: Browser navigation options shared by the Standard and Stealth tiers.
      properties:
        headless:
          description: Run headless.
          type: boolean
          default: true
        browser:
          description: Browser engine. Defaults to chromium on the Standard tier and to the hardened camoufox
            engine on the Stealth tier.
          type: string
          enum:
          - chromium
          - camoufox
          - firefox
        wait_until:
          description: When navigation is considered complete.
          type: string
          default: load
          enum:
          - load
          - domcontentloaded
          - networkidle
          - commit
        navigation_timeout_ms:
          description: Per-navigation timeout in ms.
          type: integer
          maximum: 300000
          minimum: 1000
        viewport:
          $ref: '#/components/schemas/JobViewport'
        locale:
          description: BCP-47 locale.
          type: string
          example: en-US
        timezone_id:
          description: IANA timezone.
          type: string
          example: Europe/Paris
        actions:
          description: Ordered interactions performed after load.
          type: array
          items:
            $ref: '#/components/schemas/JobAction'
      type: object
    JobAction:
      description: A scripted browser interaction performed after load (Standard/Stealth tiers). Required
        fields depend on `action`.
      discriminator:
        propertyName: action
        mapping:
          click: '#/components/schemas/ClickAction'
          fill: '#/components/schemas/FillAction'
          wait_for_selector: '#/components/schemas/WaitForSelectorAction'
          wait_for_timeout: '#/components/schemas/WaitForTimeoutAction'
          evaluate: '#/components/schemas/EvaluateAction'
          screenshot: '#/components/schemas/ScreenshotAction'
          navigate: '#/components/schemas/NavigateAction'
      oneOf:
      - $ref: '#/components/schemas/ClickAction'
      - $ref: '#/components/schemas/FillAction'
      - $ref: '#/components/schemas/WaitForSelectorAction'
      - $ref: '#/components/schemas/WaitForTimeoutAction'
      - $ref: '#/components/schemas/EvaluateAction'
      - $ref: '#/components/schemas/ScreenshotAction'
      - $ref: '#/components/schemas/NavigateAction'
    JsonPathExtractionHook:
      description: Extract content matched by a JSONPath expression.
      required:
      - hook_id
      - type
      - path
      properties:
        hook_id:
          description: Unique id for this hook within the job.
          type: string
        type:
          type: string
          enum:
          - jsonpath
        path:
          description: JSONPath expression.
          type: string
        all_matches:
          description: Return every match instead of the first.
          type: boolean
          default: false
        timeout_ms:
          description: Per-hook timeout in ms.
          type: integer
          default: 1000
          maximum: 30000
          minimum: 1
      type: object
      additionalProperties: false
    ErrorDetail:
      description: A single field-level validation problem.
      required:
      - message
      properties:
        field:
          description: Request field the problem relates to, when applicable.
          type:
          - string
          - 'null'
          example: target_url
        message:
          type: string
          example: Must be a valid HTTPS URL.
      type: object
      additionalProperties: false
    RegexExtractionHook:
      description: Extract content matched by a regular expression.
      required:
      - hook_id
      - type
      - pattern
      properties:
        hook_id:
          description: Unique id for this hook within the job.
          type: string
        type:
          type: string
          enum:
          - regex
        pattern:
          description: Regular expression.
          type: string
        flags:
          description: 'Regex flags: any of i, m, s.'
          type:
          - string
          - 'null'
          pattern: ^[ims]*$
        group:
          description: Capture group to return.
          type: integer
          default: 0
          minimum: 0
        all_matches:
          description: Return every match instead of the first.
          type: boolean
          default: false
        timeout_ms:
          description: Per-hook timeout in ms.
          type: integer
          default: 1000
          maximum: 30000
          minimum: 1
      type: object
      additionalProperties: false
    CssExtractionHook:
      description: Extract content matched by a CSS selector.
      required:
      - hook_id
      - type
      - selector
      properties:
        hook_id:
          description: Unique id for this hook within the job.
          type: string
        type:
          type: string
          enum:
          - css
        selector:
          description: CSS selector.
          type: string
        attribute:
          description: Return this attribute instead of the element text.
          type:
          - string
          - 'null'
        all_matches:
          description: Return every match instead of the first.
          type: boolean
          default: false
        timeout_ms:
          description: Per-hook timeout in ms.
          type: integer
          default: 1000
          maximum: 30000
          minimum: 1
      type: object
      additionalProperties: false
    ScreenshotAction:
      description: Capture a screenshot as a `screenshot` artifact.
      required:
      - action
      properties:
        action:
          type: string
          enum:
          - screenshot
        selector:
          description: CSS selector to screenshot a single element; omit for the page.
          type:
          - string
          - 'null'
        full_page:
          description: Capture the full scrollable page (ignored when `selector` is set).
          type: boolean
          default: true
        filename:
          description: Artifact filename; `.png` is appended when no extension is given.
          type: string
      type: object
      additionalProperties: false
    WaitForSelectorAction:
      description: Wait until the element matched by `selector` appears.
      required:
      - action
      - selector
      properties:
        action:
          type: string
          enum:
          - wait_for_selector
        selector:
          description: CSS selector to wait for.
          type: string
        timeout_ms:
          description: Timeout waiting for the selector, in ms.
          type: integer
          maximum: 300000
          minimum: 0
      type: object
      additionalProperties: false
    JobViewport:
      description: Browser viewport dimensions (Standard/Stealth tiers).
      required:
      - width
      - height
      properties:
        width:
          type: integer
          maximum: 7680
          minimum: 320
        height:
          type: integer
          maximum: 4320
          minimum: 240
      type: object
      additionalProperties: false
    WaitForTimeoutAction:
      description: Wait for a fixed duration.
      required:
      - action
      - timeout_ms
      properties:
        action:
          type: string
          enum:
          - wait_for_timeout
        timeout_ms:
          description: Milliseconds to wait.
          type: integer
          maximum: 300000
          minimum: 0
      type: object
      additionalProperties: false
    EvaluateAction:
      description: Run a JavaScript snippet in the page context.
      required:
      - action
      - script
      properties:
        action:
          type: string
          enum:
          - evaluate
        script:
          description: JavaScript evaluated in the page (Playwright page.evaluate).
          type: string
      type: object
      additionalProperties: false
    ClickAction:
      description: Click the element matched by `selector`.
      required:
      - action
      - selector
      properties:
        action:
          type: string
          enum:
          - click
        selector:
          description: CSS selector to click.
          type: string
        timeout_ms:
          description: Timeout waiting for the selector, in ms.
          type: integer
          maximum: 300000
          minimum: 0
      type: object
      additionalProperties: false
    NavigateAction:
      description: Navigate to a new URL mid-script.
      required:
      - action
      - url
      properties:
        action:
          type: string
          enum:
          - navigate
        url:
          description: URL to navigate to.
          type: string
          format: uri
        wait_until:
          description: When navigation is considered complete.
          type: string
          default: networkidle
          enum:
          - load
          - domcontentloaded
          - networkidle
          - commit
      type: object
      additionalProperties: false
    FillAction:
      description: Type `value` into the element matched by `selector`.
      required:
      - action
      - selector
      - value
      properties:
        action:
          type: string
          enum:
          - fill
        selector:
          description: CSS selector to fill.
          type: string
        value:
          description: Text to type.
          type: string
        timeout_ms:
          description: Timeout waiting for the selector, in ms.
          type: integer
          maximum: 300000
          minimum: 0
      type: object
      additionalProperties: false
  parameters:
    EndpointId:
      name: endpoint_id
      in: path
      required: true
      schema:
        type: string
        format: uuid
    TtlSeconds:
      name: ttl_seconds
      in: query
      description: Presigned URL lifetime in seconds.
      required: false
      schema:
        type: integer
        default: 900
        maximum: 86400
        minimum: 60
    Offset:
      name: offset
      in: query
      description: Number of items to skip.
      required: false
      schema:
        type: integer
        default: 0
        minimum: 0
    Limit:
      name: limit
      in: query
      description: Maximum number of items to return.
      required: false
      schema:
        type: integer
        default: 50
        maximum: 100
        minimum: 1
    HoldId:
      name: hold_id
      in: path
      required: true
      schema:
        type: string
        format: uuid
    ArtifactId:
      name: artifact_id
      in: path
      required: true
      schema:
        type: string
        format: uuid
    JobId:
      name: job_id
      in: path
      required: true
      schema:
        type: string
        format: uuid
  responses:
    BadRequest:
      description: Malformed request.
      headers:
        x-api-version:
          $ref: '#/components/headers/ApiVersion'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: Resource not found.
      headers:
        x-api-version:
          $ref: '#/components/headers/ApiVersion'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ServerError:
      description: Unexpected server error.
      headers:
        x-api-version:
          $ref: '#/components/headers/ApiVersion'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RateLimited:
      description: Rate limit exceeded.
      headers:
        x-api-version:
          $ref: '#/components/headers/ApiVersion'
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
        X-RateLimit-Limit:
          $ref: '#/components/headers/RateLimitLimit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/RateLimitRemaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/RateLimitReset'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: Authenticated but not permitted (missing scope or tenant).
      headers:
        x-api-version:
          $ref: '#/components/headers/ApiVersion'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    UnprocessableEntity:
      description: Validation failed.
      headers:
        x-api-version:
          $ref: '#/components/headers/ApiVersion'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Conflict:
      description: Request conflicts with the current state of the resource.
      headers:
        x-api-version:
          $ref: '#/components/headers/ApiVersion'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Missing or invalid authentication credentials.
      headers:
        x-api-version:
          $ref: '#/components/headers/ApiVersion'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  headers:
    ApiVersion:
      description: Version of the API that served the response.
      schema:
        type: string
        example: '1.0'
    RateLimitLimit:
      description: Request quota for the current window.
      schema:
        type: integer
        minimum: 0
        example: 600
    RateLimitRemaining:
      description: Requests remaining in the current window.
      schema:
        type: integer
        minimum: 0
        example: 599
    RetryAfter:
      description: Seconds to wait before retrying the request.
      schema:
        type: integer
        minimum: 0
        example: 30
    RateLimitReset:
      description: Unix epoch seconds when the current window resets.
      schema:
        type: integer
        minimum: 0
        example: 1735689600
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      description: Customer API key. Send the plaintext key (e.g. `sn_live_…`) in the `X-API-Key` header.
      name: X-API-Key
      in: header
