API reference · v1
Grabbit Screenshot API
POST a URL, get back a hosted image. JSON in, JSON out, one Bearer key. Every live grab costs $0.002; test keys are free.
Authentication
Base URL: https://api.grabbit.live/v1. Send Authorization: Bearer <token> on every request except /pricing.
- API keys. Create them in the console.
sk_test_keys return a free placeholder image, so you can build the integration before adding a card.sk_live_keys render real pages and spend one credit per successful grab. - OAuth 2.1. Authorization code with PKCE and dynamic client registration, one scope:
grabs. The metadata lives at /.well-known/oauth-authorization-server and /.well-known/oauth-protected-resource.
Quickstart
One request captures a page. The response holds a hosted image_url.
curl https://api.grabbit.live/v1/grabs \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "full_page": true}'{
"id": "5f0c6c3e-8a51-4d0b-9d0e-2b7a1c9e4f10",
"status": "done",
"target_url": "https://example.com",
"image_url": "https://grabbit.live/g/5f0c6c3e-8a51-4d0b-9d0e-2b7a1c9e4f10.png",
"width": 1280,
"height": 720,
"format": "png",
"bytes": 188231,
"execution_ms": 812,
"created_at": "2026-09-28T00:00:00Z"
}/v1/grabsCapture a screenshot of a URL
Renders a public web page in a real Chromium browser and returns a hosted image URL. Synchronous by default (the render times out after 25 seconds). Send `Prefer: respond-async` or `?async=true` to get a 202 with a grab id, then poll GET /grabs/{id}. Live keys spend one credit per successful grab; sk_test_ keys return a free placeholder image.
operationId: createGrab · Bearer token required
| Parameter | In | Type | Description |
|---|---|---|---|
| Idempotency-Key | header | string | Optional. Retries with the same key return the original response. |
| Prefer | header | string | Optional. `respond-async` queues the grab and returns 202. |
| async | query | boolean | Optional. Same as `Prefer: respond-async`. |
| Body field | Type | Description |
|---|---|---|
| url | string (required) | Absolute http(s) URL to capture. |
| width | integer | Viewport width, 320 to 1920. Default 1280. |
| height | integer | Viewport height, 240 to 1080. Default 720. |
| format | png | jpeg | webp | Image format. Default png. |
| full_page | boolean | Capture the whole scrollable page instead of the viewport. Default false. |
| delay_ms | integer | Wait this long after load before capturing, 0 to 10000. Default 0. |
| selector | string | CSS selector; capture only that element. Sync requests only. |
curl https://api.grabbit.live/v1/grabs \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "full_page": true}'/v1/grabsList recent grabs
Lists the calling key's grabs, newest first, scoped to the key's team and environment.
operationId: listGrabs · Bearer token required
| Parameter | In | Type | Description |
|---|---|---|---|
| limit | query | integer | 1 to 100. Default 25. |
| status | query | pending | processing | done | failed | Optional status filter. |
curl "https://api.grabbit.live/v1/grabs?limit=10" -H "Authorization: Bearer sk_test_..."/v1/grabs/{id}Fetch one grab
Returns a single grab. Poll this after an async create until status is done or failed.
operationId: getGrab · Bearer token required
| Parameter | In | Type | Description |
|---|---|---|---|
| id | path | uuid | The grab id. |
curl https://api.grabbit.live/v1/grabs/GRAB_ID -H "Authorization: Bearer sk_test_..."/v1/usageGet credit balance and usage
Returns remaining credits (subscription + prepaid), the plan, and 30-day grab counts. Check this before a large batch so you can top up first.
operationId: getUsage · Bearer token required
curl https://api.grabbit.live/v1/usage -H "Authorization: Bearer sk_live_..."/v1/pricingGet pricing and competitor comparison
Public, no auth. Flat per-grab price, prepaid packages, and a dated comparison against other screenshot APIs.
operationId: getPricing · No auth
curl https://api.grabbit.live/v1/pricingErrors
Every error, including a 404 on an unknown API path, uses the same JSON envelope. Branch on error.code; the message is for humans and may change.
{
"error": {
"code": "credits_exhausted",
"message": "Your team has 0 credits remaining. Please top up your balance in the Developer Console."
}
}| Code | HTTP | What to do |
|---|---|---|
| unauthorized | 401 | Missing or invalid Bearer token. Send an sk_live_/sk_test_ key or an OAuth token. |
| bad_request | 400 | A parameter is missing or malformed. The message names the field. |
| invalid_viewport | 400 | width must be 320 to 1920 and height 240 to 1080. |
| ssrf_detected | 400 | The URL resolves to a private or internal address. Only public URLs are captured. |
| credits_exhausted | 402 | No live credits left. Top up at https://grabbit.live/app/billing. |
| not_found | 404 | No grab with that id exists for this key, or the path is not an API route. |
| idempotency_conflict | 409 | A request with this Idempotency-Key is still running. Retry after Retry-After. |
| idempotency_mismatch | 400 | This Idempotency-Key was already used with a different request body. |
| rate_limit_exceeded | 429 | 60 requests per minute per team. Wait until X-RateLimit-Reset. |
| queue_limit_exceeded | 429 | At most 10 async grabs may be pending at once. Poll existing ones first. |
| render_blocked | 422 | The target site blocked the capture (bot wall). No credit is charged. |
| render_failed | 500 | The page could not be captured (timeout, DNS failure). No credit is charged. |
| internal_error | 500 | Unexpected server error. Safe to retry with the same Idempotency-Key. |
Limits and retries
- 60 grab requests per minute per team. Responses carry
X-RateLimit-Limit,X-RateLimit-Remaining, andX-RateLimit-Reset(Unix seconds). - Send an
Idempotency-Keyheader on POST /grabs. A retry with the same key and body returns the original response instead of capturing twice. - Async mode (
Prefer: respond-async) allows 10 pending grabs per team. Poll GET /grabs/{id} or configure agrab.succeeded/grab.failedwebhook in the console. - Only public URLs are captured. Private, loopback, and link-local addresses are refused with
ssrf_detected.
MCP server and CLI
Agents can skip HTTP entirely. The hosted MCP server at https://mcp.grabbit.live exposes grab, get_grab, list_grabs, get_usage, and get_pricing, with OAuth for claude.ai or an API key header for everything else. The CLI runs with npx grabbit.live <url>.
claude mcp add --transport http grabbit https://mcp.grabbit.live \
--header "Authorization: Bearer sk_live_..."Setup guides: Claude Code, Cursor, Codex, all agents. Questions: contact us.