screenshot.tools.town

API Reference

screenshot.tools.town is a JSON API. Send a URL, receive a signed PNG link. Every request must include an API key from dashboard.tools.town/keys.

Base URL: https://screenshot.tools.town

Authentication

Pass your API key in the X-API-Key header. The key must have the screenshot:capture scope.

Request header
X-API-Key: tt_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Get a key at dashboard.tools.town/keys. Keys are shown once at creation; store them in your environment variables.

POST /v1/capture

Render a URL in a headless browser and return a signed PNG link.

Request body (JSON)

Field Type Default Notes
url string required HTTPS only. Private IPs and internal hosts are blocked.
viewport.width number 1280 Clamped to server limits (max 1920).
viewport.height number 720 Clamped to server limits (max 1080).
fullPage boolean false Capture full page height, not just viewport.
waitForSelector string CSS selector. Browser waits for element to appear. Max 256 chars.
navigationTimeoutMs number 30000 Navigation timeout in ms. Clamped 3000–45000.

Optional headers

Header Notes
Idempotency-Key Up to 128 chars. Retries with the same key + URL will not double-charge.

Example

curl
curl -X POST https://screenshot.tools.town/v1/capture \
  -H "X-API-Key: tt_xxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "viewport": { "width": 1200, "height": 630 },
    "fullPage": false,
    "waitForSelector": "#main-content",
    "navigationTimeoutMs": 20000
  }'

GET /v1/meta

Returns current limits and defaults. Requires X-API-Key.

200 OK
{
  "sku": "screenshot_render",
  "max_viewport": { "width": 1920, "height": 1080 },
  "min_viewport": { "width": 200, "height": 100 },
  "default_viewport": { "width": 1280, "height": 720 },
  "navigation_timeout_ms": { "min": 3000, "max": 45000, "default": 30000 },
  "max_wait_for_selector_length": 256,
  "rate_limit_per_minute": 60
}

Response fields

Field Type Description
media_id string (UUID) Unique ID of the stored image object.
image_url string (URL) Signed URL to the PNG. Valid until expires_at.
expires_at string (ISO-8601) When the signed URL expires.
content_type string Always image/png in v1.
byte_size number PNG size in bytes.
balance_after number Remaining screenshot_render credits after this debit.

Error codes

All errors return {"error": "...", "code": "..."}.

HTTP code Meaning
400 bad_url URL is invalid, not HTTPS, or blocked (private IP).
400 too_many_redirects Redirect chain exceeded the maximum hops.
401 unauthorized Missing, invalid, or revoked API key.
403 forbidden Key exists but lacks screenshot:capture scope.
402 insufficient_credits No screenshot_render credits remaining.
429 rate_limited Exceeded 60 captures/minute for this key.
502 capture_failed Browser Rendering error. No credit was debited.
502 storage_failed Capture succeeded but media upload failed. Credit was debited — contact support.

Rate limits

Default: 60 captures per minute per API key, enforced per UTC minute via Cloudflare KV. Exceeding this returns 429 rate_limited — no credit is consumed.

Need a higher limit? Contact us via the dashboard.

Idempotency

Pass an Idempotency-Key header (up to 128 chars). Retrying a request with the same key and URL will not double-charge — the credit debit is keyed on hash(key_id + idempotency_key).

Idempotency-Key: req_2026-04-12_capture_xyz123