Skip to main content

screenshotfreeapi/
error.rs

1/// All errors that can be returned by the ScreenshotFreeAPI client.
2#[derive(Debug, thiserror::Error)]
3pub enum ScreenshotFreeAPIError {
4    /// An underlying HTTP transport error from `reqwest`.
5    #[error("HTTP error: {0}")]
6    Http(#[from] reqwest::Error),
7
8    /// The API key or JWT was missing, invalid, or has been revoked (HTTP 401).
9    #[error("Authentication failed: {message}")]
10    Authentication { message: String },
11
12    /// The caller does not have permission to access this resource (HTTP 403).
13    #[error("Forbidden: {message}")]
14    Forbidden { message: String },
15
16    /// The requested resource was not found or does not belong to this API key (HTTP 404).
17    #[error("Not found: {message}")]
18    NotFound { message: String },
19
20    /// The request body failed validation (HTTP 400).
21    #[error("Validation error: {message}")]
22    Validation { message: String },
23
24    /// The rate limit was hit. The client should wait `retry_after_seconds` before retrying (HTTP 429).
25    #[error("Rate limited, retry after {retry_after_seconds}s")]
26    RateLimit { retry_after_seconds: u64 },
27
28    /// The monthly screenshot quota for this plan has been exhausted (HTTP 429 with quota body).
29    #[error("Quota exceeded")]
30    QuotaExceeded,
31
32    /// Payment is required — subscription cancelled or payment overdue (HTTP 402).
33    #[error("Payment required: {message}")]
34    PaymentRequired { message: String },
35
36    /// The screenshot job completed with a failure state.
37    #[error("Job failed: {reason}")]
38    JobFailed { job_id: String, reason: String },
39
40    /// The caller's polling loop exceeded `timeout_ms` without the job completing.
41    #[error("Job timed out after {timeout_ms}ms")]
42    JobTimeout { timeout_ms: u64 },
43
44    /// The `X-ScreenshotFree-Signature` header did not match the computed HMAC-SHA256 of the body.
45    #[error("Invalid webhook signature")]
46    InvalidSignature,
47
48    /// An unexpected HTTP status code was returned that does not map to any typed variant.
49    #[error("Unexpected status {status}: {message}")]
50    Unexpected { status: u16, message: String },
51}
52
53/// Convenience alias used throughout this crate.
54pub type Result<T> = std::result::Result<T, ScreenshotFreeAPIError>;