Use async jobs when a render may take longer than you want to hold an HTTP request open. This is common for authenticated pages, heavy dashboards, full-page captures, and batch workflows.

Queue a job

bash
curl -X POST "https://screenframed.com/v1/capture" \ -H "Authorization: Bearer $SCREENFRAMED_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/dashboard", "async": true, "webhook_url": "https://example.com/webhooks/screenframed", "device": "browser-macos", "background_preset": "midnight" }'

Response:

json
{ "job_id": "job_01KNS1WNPW9FCHZSK4XNTHMB0H", "status": "pending"}

Poll status

bash
curl "https://screenframed.com/v1/jobs/job_01KNS1WNPW9FCHZSK4XNTHMB0H" \ -H "Authorization: Bearer $SCREENFRAMED_API_KEY"

Completed response:

json
{ "id": "job_01KNS1WNPW9FCHZSK4XNTHMB0H", "status": "completed", "result": { "id": "cap_01K...", "url": "https://cdn.screenframed.com/r/cap_01K....png", "width": 1600, "height": 900, "format": "png", "credits_used": 3 }, "error": null, "webhook_url": "https://example.com/webhooks/screenframed", "webhook_status": "delivered", "created_at": "2026-04-27 15:00:00", "completed_at": "2026-04-27 15:00:04"}

CLI polling

bash
screenframed jobs status job_01K... --watch

Use --json when you want machine-readable output.

Webhook payloads

On success:

json
{ "job_id": "job_01K...", "status": "completed", "result": { "id": "cap_01K...", "url": "https://cdn.screenframed.com/r/cap_01K....png" }}

On failure:

json
{ "job_id": "job_01K...", "status": "failed", "error": "Render failed: navigation timeout"}

Operational guidance

Async capture checklist
Make webhooks idempotent

Store job ids and handle duplicate delivery safely.

Poll as a fallback

Use /v1/jobs/{id} if webhook delivery is delayed or unavailable.

Queue heavy work

Use async for full-page captures, private dashboards, and large batches.

Store result URLs

Save the final CDN URL in your product or CMS after completion.