missing_required

missing_required means the request has no content to render. Every screenshot request needs exactly one input: url, html or markdown. The API found none of them, or found only empty values. Add the input and send the request again.

Field Value
HTTP status 400 Bad Request
error.type validation_error
error.code missing_required
error.param url
retryable false
Credit used No

Find the other validation codes in the error code reference.

Example response

{
  "error": {
    "type": "validation_error",
    "code": "missing_required",
    "message": "One of url, html, or markdown is required",
    "param": "url",
    "retryable": false,
    "docs": "https://docs.renderscreenshot.com/errors/missing_required"
  },
  "request_id": "req_e81b4c09d2a37f56"
}

param is url even when you meant to send html or markdown. It names the most common input, not the one you used.

The three inputs

Input Use it for Details
url A live web page Must be an absolute http or https URL, else invalid_url
html Markup you build, such as social cards or invoices Add html_base_url if the markup uses relative links
markdown Markdown text rendered with a theme Optional markdown_theme

The content input reference covers each one. An empty string or a value with only spaces counts as missing.

Common causes

The body is not read as JSON. This is the most common cause. curl -d sends application/x-www-form-urlencoded by default. The API then reads the whole JSON text as one strange form field name, and finds no url:

# Wrong: no Content-Type, so the JSON body is not parsed
curl -X POST https://api.renderscreenshot.com/v1/screenshot \
  -H "Authorization: Bearer $RS_API_KEY" \
  -d '{"url":"https://example.com"}'

# Right
curl -X POST https://api.renderscreenshot.com/v1/screenshot \
  -H "Authorization: Bearer $RS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com"}' \
  -o screenshot.png

The same problem happens with requests.post(url, data=json.dumps(body)) without a header, and with fetch when you forget Content-Type. In Python, json=body sets the header for you.

A variable is undefined. JSON.stringify({ url: undefined }) produces {}. The key disappears, so the API sees no input at all. In Python, None becomes null, with the same result.

The input has another name. URL, target, page_url and website are not parameters. The name must be lowercase url.

The input is nested in the wrong place. url belongs at the top level of the JSON body, not inside options, viewport or capture. In a GET request, it is the query parameter url.

The preset was wrong too. The API checks the preset before the input. If you just fixed an invalid_preset error, missing_required can be the next problem in the same request.

Handle it in code

Check the input before the request leaves your code. Then a missing value fails with a message that names your variable, not with an HTTP 400 from the API:

// required-input.mjs  (Node 22, no dependencies)
const API = process.env.RS_BASE_URL ?? 'https://api.renderscreenshot.com';

export async function render(input, options = {}) {
  // Exactly one source: url, html or markdown. JSON.stringify drops undefined values,
  // so a missing variable becomes a missing key, and the API answers missing_required.
  const sources = ['url', 'html', 'markdown'].filter((k) => typeof input[k] === 'string' && input[k].trim());
  if (sources.length !== 1) {
    throw new Error(`Pass exactly one of url, html or markdown (got: ${sources.join(', ') || 'none'})`);
  }

  const res = await fetch(`${API}/v1/screenshot`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.RS_API_KEY}`,
      'Content-Type': 'application/json', // without it, the JSON body is not read as parameters
    },
    body: JSON.stringify({ ...options, [sources[0]]: input[sources[0]] }),
  });
  if (!res.ok) {
    const { error } = await res.json();
    throw new Error(`${res.status} ${error.code}: ${error.message}`);
  }
  return Buffer.from(await res.arrayBuffer());
}

// render({ url: 'https://example.com' }, { preset: 'og_card' })
// render({ html: '<h1>Hello</h1>' })
// render({ url: process.env.PAGE_URL })  -> throws before the request if PAGE_URL is unset

Tested on 2026-10-15 with Node 22.18 against a local mock that returns the API's error envelope. The url and html calls returned images. The unset variable failed in the client with got: none. The curl request without Content-Type reproduced missing_required.

Related in this topic

Was this page helpful?