{"openapi":"3.1.0","info":{"title":"Screenshot API","version":"1.0.0","description":"Capture complete websites and receive a full-page screenshot, AI-optimized slices, and a ZIP bundle."},"servers":[{"url":"https://capture.darkfunnel.pro"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"CaptureRequest":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"Single website URL. Mutually exclusive with urls."},"urls":{"type":"array","minItems":1,"maxItems":5,"description":"Up to 5 websites captured concurrently in one request (counts as 1 against the capture rate limit). Each item is a URL string or { url, viewport }.","items":{"anyOf":[{"type":"string","format":"uri"},{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"},"viewport":{"type":"string","enum":["desktop","mobile"]}},"additionalProperties":false}]}},"viewport":{"type":"string","enum":["desktop","mobile"],"default":"desktop","description":"Default viewport for string items in urls."}},"additionalProperties":false}}},"paths":{"/api/v1/captures":{"post":{"operationId":"captureWebsite","summary":"Capture one website — or up to 5 concurrently via urls","description":"Send { url } for a single capture or { urls: [...] } (1-5 items) for a batch. Batch sites capture concurrently and the response is a batch manifest with one combined ZIP (one folder per website). A batch counts as 1 request against the capture rate limit.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptureRequest"}}}},"responses":{"200":{"description":"Target showed a bot wall: body has status blocked with reason cloudflare|captcha|access-denied|login-required, and no screenshots. Do not treat it as the site's design. Cloudflare blocks on single captures additionally carry a relay ticket for completing the capture from a real user browser."},"201":{"description":"Single capture manifest (status ready), or batch manifest when urls was sent (partial per-item failures ride in `failures`; blocked sites carry CAPTURE_BLOCKED:<reason>)"},"400":{"description":"Invalid request or URL"},"401":{"description":"Missing or invalid API key"},"429":{"description":"Capture rate limit exceeded"},"502":{"description":"Website capture failed (all batch items failed)"}}}},"/api/v1/batches/{id}":{"get":{"operationId":"getBatch","summary":"Get batch manifest and refresh artifact URLs","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Batch manifest"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Batch not found"}}}},"/api/v1/batches/{id}/bundle":{"get":{"operationId":"downloadBatchBundle","summary":"Download the combined AI agent kit ZIP (one folder per website)","description":"Returns a ZIP with one folder per website (same layout as a single-capture bundle) plus a root manifest.json. Does not consume capture rate-limit quota.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Combined ZIP bundle","content":{"application/zip":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Missing or invalid API key"},"404":{"description":"Batch not found"}}}},"/api/v1/captures/{id}":{"get":{"operationId":"getCapture","summary":"Get capture and refresh artifact URLs","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Capture manifest"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Capture not found"}}}},"/api/v1/captures/{id}/download":{"get":{"operationId":"downloadCaptureFullPage","summary":"Download the lossless full-page screenshot","description":"Returns the full-page master PNG as an attachment. Does not consume capture rate-limit quota.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Full-page PNG","content":{"image/png":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Missing or invalid API key"},"404":{"description":"Capture not found"}}}},"/api/v1/captures/{id}/slices/{index}":{"get":{"operationId":"downloadCaptureSlice","summary":"Download one AI slice","description":"Returns a single slice image (WebP) as an attachment. Key-authed, never expires, does not consume capture rate-limit quota. Prefer these permanent downloadUrl links over the 1-hour signed URLs when fetching slices individually.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"index","in":"path","required":true,"schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"Slice WebP","content":{"image/webp":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Missing or invalid API key"},"404":{"description":"Capture or slice not found"}}}},"/api/v1/captures/{id}/bundle":{"get":{"operationId":"downloadCaptureBundle","summary":"Download the AI agent kit ZIP","description":"Returns a ZIP containing the full-page image, all AI slices, and manifest.json. Does not consume capture rate-limit quota.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"ZIP bundle","content":{"application/zip":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Missing or invalid API key"},"404":{"description":"Capture not found"}}}},"/api/v1/relays/{id}":{"get":{"operationId":"getRelay","summary":"Poll a browser-relay handoff","description":"Pending relays return upload instructions for a real user browser; completed relays return the finished capture manifest (captureMode relay). Issued automatically on cloudflare blocks — see POST /api/v1/captures 200 response.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Pending relay instructions or finished capture"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Relay not found"},"410":{"description":"Relay ticket expired"}}}},"/api/v1/relays/{id}/artifacts":{"post":{"operationId":"uploadRelayArtifacts","summary":"Complete a relay with real-browser pixels","description":"Raw PNG body (the page as the user's own browser rendered it) plus viewport/finalUrl/dpr query params. Runs the identical encode/store pipeline as a server capture and flips the relay to ready. Consumes one capture-rate-limit hit.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"viewport","in":"query","required":false,"schema":{"type":"string","enum":["desktop","mobile"]}},{"name":"finalUrl","in":"query","required":false,"schema":{"type":"string","format":"uri"}},{"name":"dpr","in":"query","required":false,"schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"image/png":{"schema":{"type":"string","format":"binary"}}}},"responses":{"201":{"description":"Relay capture manifest (captureMode relay)"},"400":{"description":"Invalid PNG, Relay already completed, or bad params"},"401":{"description":"Missing or invalid API key"},"404":{"description":"Relay not found"},"410":{"description":"Relay ticket expired"},"429":{"description":"Capture rate limit exceeded"}}}}}}