---
title: "Queue many screenshots at once"
method: POST
path: "/api/v1/bulk"
tags: ["Jobs"]
---

# Queue many screenshots at once

`POST /api/v1/bulk`

## Request

- Base URL: `https://curlshot.com`
- URL: `https://curlshot.com/api/v1/bulk`
- Auth: one of:
  - API key in query parameter `access_key`
  - API key in header `X-Access-Key`
  - HTTP bearer

Each item in `requests` becomes its own background job, billed separately when it succeeds. Jobs are returned in the same order as the requests. The call counts as one request per item against the rate limit. An account may hold a limited number of unfinished jobs at a time (`queue_limit`), and its jobs render at most `concurrency` at once, in turn with the jobs of other accounts.

## Request body

- BulkRequest
  - `requests` ScreenshotOptions[], required
    - union: Options for one render. Exactly one of `url`, `html` or `markdown` is required. Groups: Source (What to render. Exactly one is required.) Output (File format, quality and size of the result.) Viewport (The browser window the page is rendered in.) Capture (Which part of the page ends up in the image.) Waiting (When the page counts as ready.) Customize (Change how the page looks before the capture.) Request (What the browser sends to the site.) Blocking (Remove ads, banners and other noise.) PDF (Options that apply when format is pdf.) Video (Options that apply when format is mp4, webm or gif.) Cache (Reuse a previous render instead of rendering again.) Async and webhooks (Render in the background.) Authentication (Who is making the request.)
      - object
        - `url` string, required: Address of the page to capture.
        - `html` string: HTML to render instead of a URL.
        - `markdown` string: Markdown to render as a styled page instead of a URL.
        - `format` 'png' | 'jpeg' | 'webp' | 'pdf' | 'mp4' | 'webm' | 'gif': File format of the result. mp4, webm and gif record a video of the page.
        - `image_quality` integer: Compression quality for jpeg and webp. From 1 to 100.
        - `image_width` integer: Resize the final image to this width. In CSS pixels.
        - `image_height` integer: Resize the final image to this height. In CSS pixels.
        - `omit_background` boolean: Keep the page background transparent (png and webp).
        - `response_type` 'by_format' | 'json': Return the file itself, or JSON with a link to it.
        - `viewport_width` integer: Width of the browser window. In CSS pixels.
        - `viewport_height` integer: Height of the browser window. A video uses 720 unless you set it. In CSS pixels.
        - `device_scale_factor` number: Pixel density; 2 gives a retina image.
        - `viewport_device` 'iphone_se' | 'iphone_12' | 'iphone_13' | 'iphone_13_mini' | 'iphone_14' | 'iphone_14_plus' | 'iphone_14_pro' | 'iphone_14_pro_max' | 'iphone_15' | 'iphone_15_plus' | 'iphone_15_pro' | 'iphone_15_pro_max' | 'iphone_16' | 'iphone_16_plus' | 'iphone_16_pro' | 'iphone_16_pro_max' | 'pixel_5' | 'pixel_7' | 'pixel_8' | 'pixel_8_pro' | 'pixel_9' | 'pixel_9_pro' | 'galaxy_s23' | 'galaxy_s24' | 'galaxy_s24_ultra' | 'galaxy_a54' | 'ipad' | 'ipad_mini' | 'ipad_air' | 'ipad_pro_11' | 'ipad_pro_13' | 'galaxy_tab_s9' | 'pixel_tablet' | 'macbook_air_13' | 'macbook_pro_14' | 'macbook_pro_16' | 'laptop_hd' | 'laptop_hidpi' | 'desktop_hd' | 'desktop_full_hd' | 'desktop_qhd' | 'desktop_4k' | 'imac_24': Emulate a phone, tablet or laptop preset.
        - `viewport_mobile` boolean: Render the mobile layout (honours the viewport meta tag).
        - `viewport_landscape` boolean: Rotate the viewport to landscape.
        - `full_page` boolean: Capture the whole page, not just the first screen.
        - `full_page_scroll` boolean: Scroll through the page first so lazy-loaded images appear.
        - `full_page_max_height` integer: Cut a full-page capture off at this height. In CSS pixels.
        - `selector` string: Capture only the first element matching this CSS selector.
        - `clip_x` integer: Left edge of the area to capture. In CSS pixels.
        - `clip_y` integer: Top edge of the area to capture. In CSS pixels.
        - `clip_width` integer: Width of the area to capture. In CSS pixels.
        - `clip_height` integer: Height of the area to capture. In CSS pixels.
        - `wait_until` 'load' | 'domcontentloaded' | 'networkidle' | 'commit': Page event that marks the page as loaded.
        - `delay` number: Extra time to wait after the page has loaded. In seconds.
        - `timeout` number: Give up if the page is not ready after this long. In seconds.
        - `wait_for_selector` string: Wait until this element is visible before capturing.
        - `dark_mode` boolean: Ask the page for its dark theme.
        - `reduced_motion` boolean: Ask the page to turn animations off.
        - `media_type` 'screen' | 'print': CSS media type to render with.
        - `hide_selectors` string[]: Hide every element matching these CSS selectors.
        - `styles` string: CSS to add to the page.
        - `scripts` string: JavaScript to run on the page before the capture.
        - `click` string: Click the first element matching this selector before the capture.
        - `user_agent` string: User-Agent header the browser sends.
        - `headers` union: Extra HTTP headers, as "Name: value".
          - object
          - string[]
        - `cookies` union[]: Cookies to set, as "name=value; Domain=example.com".
          - union
            - string: "name=value; Domain=example.com"
            - object
              - …
        - `authorization` string: Authorization header sent to the target site only.
        - `time_zone` string: IANA time zone the page sees.
        - `block_ads` boolean: Block requests to ad networks.
        - `block_trackers` boolean: Block analytics and tracking scripts.
        - `block_cookie_banners` boolean: Hide cookie consent banners.
        - `block_chats` boolean: Block live-chat widgets.
        - `block_resources` string[]: Block whole kinds of resources.
        - `block_requests` string[]: Block requests whose URL matches these patterns (* is a wildcard).
        - `pdf_paper_format` 'a0' | 'a1' | 'a2' | 'a3' | 'a4' | 'a5' | 'a6' | 'letter' | 'legal' | 'tabloid' | 'ledger': Paper size of the PDF.
        - `pdf_landscape` boolean: Use landscape pages.
        - `pdf_print_background` boolean: Print background colors and images.
        - `pdf_margin` string: Margin on all four sides.
        - `pdf_margin_top` string: Top margin; overrides pdf_margin.
        - `pdf_margin_right` string: Right margin; overrides pdf_margin.
        - `pdf_margin_bottom` string: Bottom margin; overrides pdf_margin.
        - `pdf_margin_left` string: Left margin; overrides pdf_margin.
        - `pdf_fit_one_page` boolean: Put the whole page on a single tall PDF page.
        - `video_duration` number: Length of the video. Left out, it follows the height of the page. In seconds.
        - `video_max_duration` number: Longest the video may get when its length follows the page. A taller page then scrolls faster. In seconds.
        - `video_fps` integer: Frames per second. A gif takes at most 15.
        - `video_scroll` boolean: Scroll from the top of the page to the bottom while recording.
        - `video_scroll_back` boolean: Scroll back to the top at the end, so the video loops cleanly.
        - `video_scroll_easing` 'ease_in_out' | 'linear': How the scroll moves: a soft start and stop, or one even speed.
        - `cache` boolean: Serve a stored copy when the same request was made before.
        - `cache_ttl` integer: How long a cached copy stays valid. In seconds.
        - `cache_key` string: Change this value to force a fresh render.
        - `async` boolean: Return at once and render in the background.
        - `webhook_url` string: Address that receives the result when the render is done.
        - `webhook_sign` boolean: Sign the webhook body so you can verify it came from us.
        - `signature` string: HMAC-SHA256 signature of the query string, for signed links.
        - `expires` integer: Unix time in seconds after which the request is refused. Put it in a signed link to give the link a lifetime.
      - object
        - `url` string: Address of the page to capture.
        - `html` string, required: HTML to render instead of a URL.
        - `markdown` string: Markdown to render as a styled page instead of a URL.
        - `format` 'png' | 'jpeg' | 'webp' | 'pdf' | 'mp4' | 'webm' | 'gif': File format of the result. mp4, webm and gif record a video of the page.
        - `image_quality` integer: Compression quality for jpeg and webp. From 1 to 100.
        - `image_width` integer: Resize the final image to this width. In CSS pixels.
        - `image_height` integer: Resize the final image to this height. In CSS pixels.
        - `omit_background` boolean: Keep the page background transparent (png and webp).
        - `response_type` 'by_format' | 'json': Return the file itself, or JSON with a link to it.
        - `viewport_width` integer: Width of the browser window. In CSS pixels.
        - `viewport_height` integer: Height of the browser window. A video uses 720 unless you set it. In CSS pixels.
        - `device_scale_factor` number: Pixel density; 2 gives a retina image.
        - `viewport_device` 'iphone_se' | 'iphone_12' | 'iphone_13' | 'iphone_13_mini' | 'iphone_14' | 'iphone_14_plus' | 'iphone_14_pro' | 'iphone_14_pro_max' | 'iphone_15' | 'iphone_15_plus' | 'iphone_15_pro' | 'iphone_15_pro_max' | 'iphone_16' | 'iphone_16_plus' | 'iphone_16_pro' | 'iphone_16_pro_max' | 'pixel_5' | 'pixel_7' | 'pixel_8' | 'pixel_8_pro' | 'pixel_9' | 'pixel_9_pro' | 'galaxy_s23' | 'galaxy_s24' | 'galaxy_s24_ultra' | 'galaxy_a54' | 'ipad' | 'ipad_mini' | 'ipad_air' | 'ipad_pro_11' | 'ipad_pro_13' | 'galaxy_tab_s9' | 'pixel_tablet' | 'macbook_air_13' | 'macbook_pro_14' | 'macbook_pro_16' | 'laptop_hd' | 'laptop_hidpi' | 'desktop_hd' | 'desktop_full_hd' | 'desktop_qhd' | 'desktop_4k' | 'imac_24': Emulate a phone, tablet or laptop preset.
        - `viewport_mobile` boolean: Render the mobile layout (honours the viewport meta tag).
        - `viewport_landscape` boolean: Rotate the viewport to landscape.
        - `full_page` boolean: Capture the whole page, not just the first screen.
        - `full_page_scroll` boolean: Scroll through the page first so lazy-loaded images appear.
        - `full_page_max_height` integer: Cut a full-page capture off at this height. In CSS pixels.
        - `selector` string: Capture only the first element matching this CSS selector.
        - `clip_x` integer: Left edge of the area to capture. In CSS pixels.
        - `clip_y` integer: Top edge of the area to capture. In CSS pixels.
        - `clip_width` integer: Width of the area to capture. In CSS pixels.
        - `clip_height` integer: Height of the area to capture. In CSS pixels.
        - `wait_until` 'load' | 'domcontentloaded' | 'networkidle' | 'commit': Page event that marks the page as loaded.
        - `delay` number: Extra time to wait after the page has loaded. In seconds.
        - `timeout` number: Give up if the page is not ready after this long. In seconds.
        - `wait_for_selector` string: Wait until this element is visible before capturing.
        - `dark_mode` boolean: Ask the page for its dark theme.
        - `reduced_motion` boolean: Ask the page to turn animations off.
        - `media_type` 'screen' | 'print': CSS media type to render with.
        - `hide_selectors` string[]: Hide every element matching these CSS selectors.
        - `styles` string: CSS to add to the page.
        - `scripts` string: JavaScript to run on the page before the capture.
        - `click` string: Click the first element matching this selector before the capture.
        - `user_agent` string: User-Agent header the browser sends.
        - `headers` union: Extra HTTP headers, as "Name: value".
          - object
          - string[]
        - `cookies` union[]: Cookies to set, as "name=value; Domain=example.com".
          - union
            - string: "name=value; Domain=example.com"
            - object
              - …
        - `authorization` string: Authorization header sent to the target site only.
        - `time_zone` string: IANA time zone the page sees.
        - `block_ads` boolean: Block requests to ad networks.
        - `block_trackers` boolean: Block analytics and tracking scripts.
        - `block_cookie_banners` boolean: Hide cookie consent banners.
        - `block_chats` boolean: Block live-chat widgets.
        - `block_resources` string[]: Block whole kinds of resources.
        - `block_requests` string[]: Block requests whose URL matches these patterns (* is a wildcard).
        - `pdf_paper_format` 'a0' | 'a1' | 'a2' | 'a3' | 'a4' | 'a5' | 'a6' | 'letter' | 'legal' | 'tabloid' | 'ledger': Paper size of the PDF.
        - `pdf_landscape` boolean: Use landscape pages.
        - `pdf_print_background` boolean: Print background colors and images.
        - `pdf_margin` string: Margin on all four sides.
        - `pdf_margin_top` string: Top margin; overrides pdf_margin.
        - `pdf_margin_right` string: Right margin; overrides pdf_margin.
        - `pdf_margin_bottom` string: Bottom margin; overrides pdf_margin.
        - `pdf_margin_left` string: Left margin; overrides pdf_margin.
        - `pdf_fit_one_page` boolean: Put the whole page on a single tall PDF page.
        - `video_duration` number: Length of the video. Left out, it follows the height of the page. In seconds.
        - `video_max_duration` number: Longest the video may get when its length follows the page. A taller page then scrolls faster. In seconds.
        - `video_fps` integer: Frames per second. A gif takes at most 15.
        - `video_scroll` boolean: Scroll from the top of the page to the bottom while recording.
        - `video_scroll_back` boolean: Scroll back to the top at the end, so the video loops cleanly.
        - `video_scroll_easing` 'ease_in_out' | 'linear': How the scroll moves: a soft start and stop, or one even speed.
        - `cache` boolean: Serve a stored copy when the same request was made before.
        - `cache_ttl` integer: How long a cached copy stays valid. In seconds.
        - `cache_key` string: Change this value to force a fresh render.
        - `async` boolean: Return at once and render in the background.
        - `webhook_url` string: Address that receives the result when the render is done.
        - `webhook_sign` boolean: Sign the webhook body so you can verify it came from us.
        - `signature` string: HMAC-SHA256 signature of the query string, for signed links.
        - `expires` integer: Unix time in seconds after which the request is refused. Put it in a signed link to give the link a lifetime.
      - object
        - `url` string: Address of the page to capture.
        - `html` string: HTML to render instead of a URL.
        - `markdown` string, required: Markdown to render as a styled page instead of a URL.
        - `format` 'png' | 'jpeg' | 'webp' | 'pdf' | 'mp4' | 'webm' | 'gif': File format of the result. mp4, webm and gif record a video of the page.
        - `image_quality` integer: Compression quality for jpeg and webp. From 1 to 100.
        - `image_width` integer: Resize the final image to this width. In CSS pixels.
        - `image_height` integer: Resize the final image to this height. In CSS pixels.
        - `omit_background` boolean: Keep the page background transparent (png and webp).
        - `response_type` 'by_format' | 'json': Return the file itself, or JSON with a link to it.
        - `viewport_width` integer: Width of the browser window. In CSS pixels.
        - `viewport_height` integer: Height of the browser window. A video uses 720 unless you set it. In CSS pixels.
        - `device_scale_factor` number: Pixel density; 2 gives a retina image.
        - `viewport_device` 'iphone_se' | 'iphone_12' | 'iphone_13' | 'iphone_13_mini' | 'iphone_14' | 'iphone_14_plus' | 'iphone_14_pro' | 'iphone_14_pro_max' | 'iphone_15' | 'iphone_15_plus' | 'iphone_15_pro' | 'iphone_15_pro_max' | 'iphone_16' | 'iphone_16_plus' | 'iphone_16_pro' | 'iphone_16_pro_max' | 'pixel_5' | 'pixel_7' | 'pixel_8' | 'pixel_8_pro' | 'pixel_9' | 'pixel_9_pro' | 'galaxy_s23' | 'galaxy_s24' | 'galaxy_s24_ultra' | 'galaxy_a54' | 'ipad' | 'ipad_mini' | 'ipad_air' | 'ipad_pro_11' | 'ipad_pro_13' | 'galaxy_tab_s9' | 'pixel_tablet' | 'macbook_air_13' | 'macbook_pro_14' | 'macbook_pro_16' | 'laptop_hd' | 'laptop_hidpi' | 'desktop_hd' | 'desktop_full_hd' | 'desktop_qhd' | 'desktop_4k' | 'imac_24': Emulate a phone, tablet or laptop preset.
        - `viewport_mobile` boolean: Render the mobile layout (honours the viewport meta tag).
        - `viewport_landscape` boolean: Rotate the viewport to landscape.
        - `full_page` boolean: Capture the whole page, not just the first screen.
        - `full_page_scroll` boolean: Scroll through the page first so lazy-loaded images appear.
        - `full_page_max_height` integer: Cut a full-page capture off at this height. In CSS pixels.
        - `selector` string: Capture only the first element matching this CSS selector.
        - `clip_x` integer: Left edge of the area to capture. In CSS pixels.
        - `clip_y` integer: Top edge of the area to capture. In CSS pixels.
        - `clip_width` integer: Width of the area to capture. In CSS pixels.
        - `clip_height` integer: Height of the area to capture. In CSS pixels.
        - `wait_until` 'load' | 'domcontentloaded' | 'networkidle' | 'commit': Page event that marks the page as loaded.
        - `delay` number: Extra time to wait after the page has loaded. In seconds.
        - `timeout` number: Give up if the page is not ready after this long. In seconds.
        - `wait_for_selector` string: Wait until this element is visible before capturing.
        - `dark_mode` boolean: Ask the page for its dark theme.
        - `reduced_motion` boolean: Ask the page to turn animations off.
        - `media_type` 'screen' | 'print': CSS media type to render with.
        - `hide_selectors` string[]: Hide every element matching these CSS selectors.
        - `styles` string: CSS to add to the page.
        - `scripts` string: JavaScript to run on the page before the capture.
        - `click` string: Click the first element matching this selector before the capture.
        - `user_agent` string: User-Agent header the browser sends.
        - `headers` union: Extra HTTP headers, as "Name: value".
          - object
          - string[]
        - `cookies` union[]: Cookies to set, as "name=value; Domain=example.com".
          - union
            - string: "name=value; Domain=example.com"
            - object
              - …
        - `authorization` string: Authorization header sent to the target site only.
        - `time_zone` string: IANA time zone the page sees.
        - `block_ads` boolean: Block requests to ad networks.
        - `block_trackers` boolean: Block analytics and tracking scripts.
        - `block_cookie_banners` boolean: Hide cookie consent banners.
        - `block_chats` boolean: Block live-chat widgets.
        - `block_resources` string[]: Block whole kinds of resources.
        - `block_requests` string[]: Block requests whose URL matches these patterns (* is a wildcard).
        - `pdf_paper_format` 'a0' | 'a1' | 'a2' | 'a3' | 'a4' | 'a5' | 'a6' | 'letter' | 'legal' | 'tabloid' | 'ledger': Paper size of the PDF.
        - `pdf_landscape` boolean: Use landscape pages.
        - `pdf_print_background` boolean: Print background colors and images.
        - `pdf_margin` string: Margin on all four sides.
        - `pdf_margin_top` string: Top margin; overrides pdf_margin.
        - `pdf_margin_right` string: Right margin; overrides pdf_margin.
        - `pdf_margin_bottom` string: Bottom margin; overrides pdf_margin.
        - `pdf_margin_left` string: Left margin; overrides pdf_margin.
        - `pdf_fit_one_page` boolean: Put the whole page on a single tall PDF page.
        - `video_duration` number: Length of the video. Left out, it follows the height of the page. In seconds.
        - `video_max_duration` number: Longest the video may get when its length follows the page. A taller page then scrolls faster. In seconds.
        - `video_fps` integer: Frames per second. A gif takes at most 15.
        - `video_scroll` boolean: Scroll from the top of the page to the bottom while recording.
        - `video_scroll_back` boolean: Scroll back to the top at the end, so the video loops cleanly.
        - `video_scroll_easing` 'ease_in_out' | 'linear': How the scroll moves: a soft start and stop, or one even speed.
        - `cache` boolean: Serve a stored copy when the same request was made before.
        - `cache_ttl` integer: How long a cached copy stays valid. In seconds.
        - `cache_key` string: Change this value to force a fresh render.
        - `async` boolean: Return at once and render in the background.
        - `webhook_url` string: Address that receives the result when the render is done.
        - `webhook_sign` boolean: Sign the webhook body so you can verify it came from us.
        - `signature` string: HMAC-SHA256 signature of the query string, for signed links.
        - `expires` integer: Unix time in seconds after which the request is refused. Put it in a signed link to give the link a lifetime.
  - `webhook_url` string, uri: Receives one event per finished job.

## Response `202`

The jobs were queued.

- BulkAccepted
  - `batch_id` string, required
  - `batch_url` string, uri, required: Where to read the state of every job at once.
  - `jobs` JobAccepted[], required
    - `job_id` string, required
    - `status` 'queued', required
    - `job_url` string, uri, required: Where to poll the job.
    - `status_url` string, uri, required: The same address as `job_url`.

## Other responses

- `400`: `invalid_request`: The request could not be read. Send a JSON object. `invalid_options`: One or more options are not valid.
- `401`: `access_key_required`: An access key is required. Pass `access_key` or the `X-Access-Key` header. `access_key_invalid`: The access key is not valid or has been revoked.
- `402`: `quota_exceeded`: The screenshot quota for this billing period is used up.
- `403`: `signature_required`: This access key only accepts signed requests. Add a `signature` parameter. `signature_invalid`: The request signature does not match. `request_expired`: This request has expired: its `expires` time is in the past. Create a new link with a later `expires`. `feature_not_available`: Your plan does not include this feature.
- `429`: `rate_limited`: Too many requests. Slow down and retry after the indicated delay. `queue_limit`: Too many async jobs of this account are waiting to render. Wait for some to finish, then retry. `failure_limit`: Too many renders of this account failed in the last minute. Fix the failing requests, then retry after the indicated delay.
- `503`: `service_unavailable`: The service is temporarily unavailable. Retry in a moment.

---

[API](https://skmtc.dev/curlshot/apis/curlshot-api.md) · [All operations](https://skmtc.dev/curlshot/apis/curlshot-api/llms.txt) · [OpenAPI document](https://skmtc.dev/curlshot/apis/curlshot-api/revisions/2022db7875af?raw)
