Errors and media lifecycle
API v1 uses one stable error envelope:
{ "error": { "code": "unsupported_url", "message": "Human-readable explanation", "details": null }}Clients should branch on error.code, not parse message. details may be null or contain structured context. New clients should also tolerate error codes added by future modules.
Common failure classes
Section titled “Common failure classes”Request and routing errors
Section titled “Request and routing errors”A malformed URL, unsupported host/path, or URL that does not match an enabled module fails before a scraper result is returned. unsupported_url is a typical routing error code.
Not found or unavailable content
Section titled “Not found or unavailable content”A platform can report that a post, track, or account-bound asset no longer exists or cannot be resolved. not_found is the canonical class for content that the module can confidently identify as absent.
Do not treat every upstream parsing failure as not_found: modules can fall back or surface a service/upstream failure when the content’s existence is uncertain.
Authentication errors
Section titled “Authentication errors”Machine routes reject missing/invalid X-API-Key values. Browser routes reject missing, invalid, or expired signed web-session bearer tokens. Those mechanisms are intentionally separate.
Upstream, restriction, and rate failures
Section titled “Upstream, restriction, and rate failures”Platforms can throttle, geo-restrict, require authentication, change response formats, or return temporary service errors. A module may retry or use a documented fallback, but clients should still be prepared for retriable service/rate conditions.
The human message is for diagnostics; application behavior should use the status and error code.
Protected media URLs
Section titled “Protected media URLs”A successful scrape does not make cached media public.
- Machine
/v1/scraperesponses can contain protected/media/...paths. Fetch them with the same machine-key boundary. - Browser
/v1/web/scraperesponses use protected/web/media/...paths. Pinchana Web rewrites them to same-origin/api/media/...and its BFF forwards the browser session.
Both media paths support the range behavior required for video/audio playback and resumable requests where the underlying file supports it.
Media dimensions
Section titled “Media dimensions”The gateway probes cached image/video files to populate dimensions: {width, height}. A visual asset can legitimately have dimensions: null when the file cannot be inspected. Audio assets have no visual dimensions.
Clients must not infer an error from missing dimensions.
Cache lifetime
Section titled “Cache lifetime”The shared scraper cache is working storage, not permanent object storage. Modules write files into the shared scraper-cache volume and the gateway serves them while present. Cache cleanup can remove old assets according to configured size/lifecycle behavior.
If an integration needs durable storage, copy the authenticated asset into storage you control rather than retaining a Pinchana cache URL indefinitely.
Browser GIF conversion
Section titled “Browser GIF conversion”POST /web/convert/gif operates only on an authenticated file already present in the Pinchana cache. It has bounded FFmpeg limits and does not accept arbitrary remote URLs or uploads.
That means a stale/removed cache asset cannot be converted later simply by replaying its old path.
DLP completed files
Section titled “DLP completed files”DLP output is separate from the normal scraper cache. Each job gets temporary host storage and an ephemeral worker. Completed files are streamed through the owner-bound DLP route, and job directories expire according to DLP retention settings.
Production defaults use a two-hour job lifetime. DLP storage is intentionally temporary and should not be backed up or synchronized.
Debugging order
Section titled “Debugging order”For a failed normal scrape:
- Confirm the request reached the gateway and authenticated successfully.
- Confirm the URL matches an enabled module.
- Inspect gateway/module logs without logging secrets or cookies.
- Check VPN/Gluetun health if the module depends on current egress.
- If scrape succeeds but file access fails, inspect the shared cache and media authentication separately.
For a failed YouTube DLP job, use the DLP operations/preflight path instead of debugging it as a scraper module.