> ## Documentation Index
> Fetch the complete documentation index at: https://webscrape.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Dispatch run

> Returns immediately with a `run_id`. Poll `GET /v1/smartbrowse/runs/{id}`
for progress and final result.

**Cost:** 2 credits per page extracted (initial load + each pagination
hop). Charged on completion only. Failed and cancelled runs cost 0.


Dispatch a SmartBrowse recipe run. Comes back right away with a `run_id`; poll [`GET /v1/smartbrowse/runs/{id}`](/docs/api-reference/smartbrowse/get-run) for progress and the final result.

Recipes are authored visually in the [dashboard studio](https://webscrape.ai/app/smartbrowse) — click, type, and paginate against a real page. The API only dispatches and polls.

**Cost:** 2 credits per page extracted (initial load + each pagination hop). Billed on completion. Cancelled or timed-out runs cost 0.

## Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.webscrape.ai/v1/smartbrowse/recipes/m3Yc2tFvN8q/run \
    -H "X-API-Key: wsg_live_..."
  ```

  ```python Python theme={null}
  import requests

  env = requests.post(
      "https://api.webscrape.ai/v1/smartbrowse/recipes/m3Yc2tFvN8q/run",
      headers={"X-API-Key": "wsg_live_..."},
  ).json()

  run_id = env["data"]["run_id"]
  print("dispatched run:", run_id, "poll:", env["data"]["poll_url"])
  ```

  ```js Node theme={null}
  const env = await fetch(
    "https://api.webscrape.ai/v1/smartbrowse/recipes/m3Yc2tFvN8q/run",
    { method: "POST", headers: { "X-API-Key": "wsg_live_..." } },
  ).then(r => r.json());

  console.log("dispatched run:", env.data.run_id);
  ```

  ```go Go theme={null}
  req, _ := http.NewRequest("POST", "https://api.webscrape.ai/v1/smartbrowse/recipes/m3Yc2tFvN8q/run", nil)
  req.Header.Set("X-API-Key", "wsg_live_...")
  http.DefaultClient.Do(req)
  ```

  ```rust Rust theme={null}
  reqwest::Client::new()
      .post("https://api.webscrape.ai/v1/smartbrowse/recipes/m3Yc2tFvN8q/run")
      .header("X-API-Key", "wsg_live_...")
      .send()
      .await?;
  ```
</CodeGroup>

<Accordion title="Example response (queued)">
  ```json theme={null}
  {
    "status": "queued",
    "data": {
      "run_id": "k7Xb9dRmQ2p",
      "recipe_id": "m3Yc2tFvN8q",
      "run_status": "running",
      "poll_url": "/v1/smartbrowse/runs/k7Xb9dRmQ2p",
      "created_at": "2026-05-21T17:42:01Z"
    },
    "request_id": "req_aB3xY9Kp"
  }
  ```

  Poll [`GET /v1/smartbrowse/runs/{id}`](/docs/api-reference/smartbrowse/get-run) until `data.run_status` is `completed` or `failed`.
</Accordion>

## Tips

* We require 2 credits (one page's worth) up front. If you can't cover it, dispatch fails with `error.code: insufficient_credits`.
* Actual cost is 2 credits per page extracted, charged on completion. Failed runs cost 0.
* Pair with the [Schedules dashboard](https://webscrape.ai/app/smartbrowse) for cron-driven runs that fire webhooks on completion.

<Tip>
  Set up a [webhook](/docs/concepts/webhooks) on the recipe to receive `smartbrowse.completed` and `smartbrowse.failed` events. Push delivery is cheaper and faster than holding a poll loop open.
</Tip>

<Tip>
  If the data is on a static page — no clicks, no login, no JS-driven content — you don't need SmartBrowse. [Scrape](/docs/features/scrape) is 1 credit instead of 2 per page.
</Tip>

<Note>
  Each run has a hard 15-minute timeout. For very long crawls, split the work into multiple recipes you dispatch in parallel rather than one giant recipe.
</Note>

For recipe authoring, drift score interpretation, and scheduling, see the [SmartBrowse feature page](/docs/features/smartbrowse).


## OpenAPI

````yaml POST /smartbrowse/recipes/{id}/run
openapi: 3.1.0
info:
  title: webscrape.ai API
  version: '1.0'
  description: |
    The public webscrape.ai API. Fetch pages and get back structured JSON,
    HTML, markdown, or replayed browser output.

    Every response is wrapped in one of three envelope shapes —
    `completed`, `queued`, or `error`. Always check the top-level
    `status` first, then read `data` (success or queued) or `error`
    (failure).
  contact:
    name: webscrape.ai support
    email: hello@webscrape.ai
    url: https://webscrape.ai
servers:
  - url: https://api.webscrape.ai/v1
    description: Production
security:
  - ApiKeyAuth: []
tags:
  - name: Scrape
    description: Raw fetching and structured extraction.
  - name: SmartBrowse
    description: Real-Chrome recipe replay with pagination and interactions.
paths:
  /smartbrowse/recipes/{id}/run:
    post:
      tags:
        - SmartBrowse
      summary: Dispatch a SmartBrowse run
      description: >
        Returns immediately with a `run_id`. Poll `GET
        /v1/smartbrowse/runs/{id}`

        for progress and final result.


        **Cost:** 2 credits per page extracted (initial load + each pagination

        hop). Charged on completion only. Failed and cancelled runs cost 0.
      operationId: dispatchSmartBrowseRun
      parameters:
        - name: id
          in: path
          required: true
          description: Opaque recipe ID (~11 base62 chars).
          schema:
            type: string
            example: m3Yc2tFvN8q
      responses:
        '202':
          description: Run dispatched.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SmartBrowseRunQueued'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/PaymentRequired'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
        '502':
          $ref: '#/components/responses/ExtractionUnavailable'
components:
  schemas:
    SmartBrowseRunQueued:
      allOf:
        - $ref: '#/components/schemas/EnvelopeBase'
        - type: object
          required:
            - data
          properties:
            status:
              type: string
              enum:
                - queued
            data:
              $ref: '#/components/schemas/SmartBrowseRunDispatchData'
    EnvelopeBase:
      type: object
      required:
        - status
        - request_id
      properties:
        status:
          type: string
          enum:
            - completed
            - queued
            - error
          description: Discriminator for the envelope variant.
        request_id:
          type: string
          example: req_aB3xY9Kp
          description: |
            Per-request id. Also returned as the `X-Request-ID` response
            header. Include it when reporting issues.
    SmartBrowseRunDispatchData:
      type: object
      required:
        - run_id
        - recipe_id
        - run_status
        - poll_url
        - created_at
      properties:
        run_id:
          type: string
          example: k7Xb9dRmQ2p
          description: Opaque run ID (~11 base62 chars).
        recipe_id:
          type: string
          example: m3Yc2tFvN8q
          description: Opaque recipe ID (~11 base62 chars).
        run_status:
          type: string
          enum:
            - running
          description: |
            Always `running` on dispatch. The envelope's outer `status` is
            `queued` (no work billed yet); the `run_status` here describes
            the run's own lifecycle.
        poll_url:
          type: string
          example: /v1/smartbrowse/runs/k7Xb9dRmQ2p
        created_at:
          type: string
          format: date-time
    EnvelopeError:
      allOf:
        - $ref: '#/components/schemas/EnvelopeBase'
        - type: object
          required:
            - error
          properties:
            status:
              type: string
              enum:
                - error
            error:
              type: object
              required:
                - code
                - message
              properties:
                code:
                  $ref: '#/components/schemas/ErrorCode'
                message:
                  type: string
                  description: >-
                    Human-readable. May change between releases. Log it; don't
                    pattern-match.
                details:
                  description: >-
                    Optional structured context (e.g. `{balance, required}` for
                    `insufficient_credits`).
    ErrorCode:
      type: string
      description: Stable error code. SDKs branch on this.
      enum:
        - invalid_request
        - unauthorized
        - insufficient_credits
        - email_verification_required
        - forbidden
        - not_found
        - conflict
        - account_deletion_pending
        - validation_failed
        - rate_limited
        - internal_error
        - service_unavailable
  responses:
    BadRequest:
      description: 'Malformed request: missing field, invalid JSON, invalid URL.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EnvelopeError'
          example:
            status: error
            error:
              code: invalid_request
              message: url is required
            request_id: req_aB3xY9Kp
    Unauthorized:
      description: Missing, invalid, or revoked API key.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EnvelopeError'
          example:
            status: error
            error:
              code: unauthorized
              message: missing or invalid credentials
            request_id: req_aB3xY9Kp
    PaymentRequired:
      description: |
        Out of credits OR email not verified. Branch on `error.code`:
        `insufficient_credits` (with `details: {balance, required}`) vs
        `email_verification_required`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EnvelopeError'
          examples:
            insufficient:
              summary: Out of credits
              value:
                status: error
                error:
                  code: insufficient_credits
                  message: not enough credits to complete this request
                  details:
                    balance: 2
                    required: 5
                request_id: req_aB3xY9Kp
            unverified:
              summary: Email not verified
              value:
                status: error
                error:
                  code: email_verification_required
                  message: verify your email address before spending credits
                request_id: req_aB3xY9Kp
    NotFound:
      description: Resource does not exist or belongs to another user.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EnvelopeError'
          example:
            status: error
            error:
              code: not_found
              message: recipe not found
            request_id: req_aB3xY9Kp
    Conflict:
      description: |
        Resource is in a state that disallows the action. The most
        common case is `account_deletion_pending`: the account is in
        the 30-day deletion grace window and cannot spend credits until
        deletion is cancelled.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EnvelopeError'
          example:
            status: error
            error:
              code: account_deletion_pending
              message: account is scheduled for deletion — cancel to restore access
              details:
                deletion_scheduled_for: '2026-06-15T12:00:00Z'
            request_id: req_aB3xY9Kp
    RateLimited:
      description: |
        Per-plan throttle exceeded. `error.details.reason` distinguishes
        the cause:

          * `rate_limit_per_min`     — too many requests per minute.
          * `max_concurrent_requests` — too many in-flight at once.
          * `sb_runs_per_month`       — SmartBrowse run quota for the
                                        rolling 30-day window.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EnvelopeError'
          examples:
            rate_per_min:
              summary: Request rate exceeds plan
              value:
                status: error
                error:
                  code: rate_limited
                  message: request rate exceeds plan limit — upgrade plan or slow down
                  details:
                    limit_per_min: 60
                    reason: rate_limit_per_min
                request_id: req_aB3xY9Kp
            max_concurrent:
              summary: Too many in-flight requests
              value:
                status: error
                error:
                  code: rate_limited
                  message: too many in-flight requests for plan — upgrade plan or wait
                  details:
                    max_concurrent: 5
                    reason: max_concurrent_requests
                request_id: req_aB3xY9Kp
            sb_runs:
              summary: SmartBrowse monthly run quota exceeded
              value:
                status: error
                error:
                  code: rate_limited
                  message: >-
                    smartbrowse run quota exceeded for plan — upgrade for more
                    runs
                  details:
                    used: 50
                    limit: 50
                    window: 30d
                    reason: sb_runs_per_month
                request_id: req_aB3xY9Kp
    InternalError:
      description: Internal server error. Safe to retry with backoff.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EnvelopeError'
          example:
            status: error
            error:
              code: internal_error
              message: internal error
            request_id: req_aB3xY9Kp
    ExtractionUnavailable:
      description: |
        Extraction service is temporarily unreachable. Safe to retry
        with backoff.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EnvelopeError'
          example:
            status: error
            error:
              code: service_unavailable
              message: extraction service is unreachable
            request_id: req_aB3xY9Kp
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: |
        Generate from the [dashboard](https://webscrape.ai/app/api-keys).
        Format: `wsg_live_<32 base62 chars>`.

````