Error Codes

When an error occurs, the API returns a JSON response with an error field.

Error Response Format

{
  "error": "error message here"
}

The 402 quota error includes additional fields:

{
  "error": "monthly quota exceeded",
  "plan": "free",
  "limit": 200,
  "used": 200,
  "resetAt": 1706745600,
  "upgrade": "Upgrade your plan at https://app.shotone.io/dashboard/billing"
}

Error Reference

400

Bad Request

The request body is invalid or missing required parameters.

Example messages:

  • url is required
  • invalid url format
  • url must use http or https scheme
  • url must have a host
  • invalid JSON body
  • format must be png, jpeg, webp, or pdf
  • quality must be between 1 and 100
  • width must be between 1 and 4096
  • height must be between 1 and 4096
  • storage must be empty or 'r2'
401

Unauthorized

Authentication failed.

Example messages:

  • missing API key
  • invalid API key
  • API key has been revoked
402

Payment Required

Monthly quota has been exceeded. Includes plan info and reset timestamp.

Example messages:

  • monthly quota exceeded
405

Method Not Allowed

Only POST is supported for the /screenshot endpoint.

Example messages:

  • method not allowed
429

Too Many Requests

Rate limit exceeded. Check the Retry-After header for when to retry.

Example messages:

  • rate limit exceeded
502

Bad Gateway

The screenshot capture or R2 upload failed.

Example messages:

  • screenshot failed: timeout
  • screenshot failed: page not found
  • screenshot failed: connection refused
  • failed to upload to R2: <details>

Real Response Examples

Here's what actual error responses look like, including headers:

401 — Invalid API Key

HTTP/2 401
content-type: application/json

{"error":"invalid API key"}

429 — Rate Limit Exceeded

Note the Retry-After header telling you how many seconds to wait:

HTTP/2 429
content-type: application/json
retry-after: 42
x-plan: free
x-ratelimit-limit: 5
x-ratelimit-remaining: 0
x-ratelimit-reset: 1706745702

{"error":"rate limit exceeded"}

402 — Monthly Quota Exceeded

Includes plan details and the Unix timestamp when your quota resets:

HTTP/2 402
content-type: application/json
x-plan: free
x-quota-limit: 200
x-quota-remaining: 0
x-quota-reset: 1709424000

{
  "error": "monthly quota exceeded",
  "plan": "free",
  "limit": 200,
  "used": 200,
  "resetAt": 1709424000,
  "upgrade": "Upgrade your plan at https://app.shotone.io/dashboard/billing"
}

Troubleshooting

400 Bad Request

  • Verify your JSON syntax is valid
  • Check that url is a valid HTTP/HTTPS URL
  • Ensure parameter values are within allowed ranges

401 Unauthorized

  • Check that you're including the X-API-Key header
  • Verify your API key is correct and hasn't been revoked
  • Create a new API key from the dashboard if needed

402 Payment Required

  • Check the resetAt field for when your quota resets
  • Monitor usage with X-Quota-Remaining response headers
  • Upgrade your plan for more screenshots

429 Too Many Requests

  • Read the Retry-After header to know when to retry
  • Implement exponential backoff in your code
  • Queue requests to stay within your plan's rate limit

502 Bad Gateway

  • The target URL may be down or blocking requests
  • Try again — the request is retried once automatically
  • Check if the URL is accessible from a browser
  • For R2 errors, verify your credentials in the dashboard