Errors
This page lists every status the ScreenshotBuddy API answers with, what each one means, and which of them are worth sending again.
The shape of an error
Every error is JSON in the same shape, whatever went wrong.
-
Name
codeTypestringDescriptionThe reason the request was refused, as a short stable string. This is the field to branch on. Every code is listed under error codes below.
-
Name
messageTypestringDescriptionThe same reason in words, written for a person to read. It can be reworded or made more specific at any time, so show it to a human rather than matching your code against it.
-
Name
errorsTypeobjectDescriptionSent only when a particular parameter is at fault. It is keyed by the query parameter, with the messages for that parameter, and it is left out entirely otherwise.
-
Name
request_idTypestringDescriptionIdentifies that one answer, and it is in our logs against the request that produced it. Quote it when you ask us about a failure and we can look up exactly what happened.
You get JSON whatever Accept header you send, so a client that asks for nothing in particular
still gets an error it can parse rather than an HTML page.
The request_id is also sent as the X-Request-Id header, and the two are always the
same value. A successful render answers with the file rather than JSON, so the header is the one place the id
exists on every answer we send. Log it from there and you have it whether the request worked or not.
Statuses
-
Status
200Worth retryingsuccessDescriptionThe rendered file. The body is the image or the PDF itself rather than JSON, so write it to a file instead of parsing it. The Content-Type names the format that was rendered.
-
Status
304Worth retryingsuccessDescriptionThe rendering is byte for byte the copy already held by the caller, named in the `If-None-Match` of the request, so no body is sent. What it costs depends on how that was established. An answer the cache could give is free: no credit, and counted against neither per-minute budget. One that had to render the page first, because the request sent `cache=0` or because the entry had lapsed, costs exactly what that render costs, a credit and a slot of the render budget, and what the caller saves is the download. `X-Cache: HIT` marks the free one; anything else was rendered, and carries the X-RateLimit headers to say so.
-
Status
401Worth retryingdo not retryCodesunauthenticatedDescriptionThe request carried no bearer token, or a token that is unknown or revoked.
-
Status
402Worth retryingdo not retryCodesno_active_plancredit_limit_reachedDescriptionThe account has no active plan, or it has used every credit in the current period. The code says which of the two it is.
-
Status
403Worth retryingdo not retryCodesemail_unverifiedmissing_abilityDescriptionThe email address of the account has not been verified yet, or the token is not allowed to ask for the mode the request is in. The code says which of the two it is: a token carries a permission per mode, and one narrowed to screenshots cannot print a PDF.
-
Status
422Worth retryingdo not retryCodesvalidation_failedinvalid_urlblocked_hosttarget_unreachableDescriptionA query parameter did not validate, or the target URL could not be reached or loaded ("The target URL could not be reached or loaded. Check that it is publicly available and try again."). The errors object names the parameter at fault. No credit is charged.
-
Status
429Worth retryingretryCodesrate_limitedDescriptionThe account went over one of its two per-minute limits: the renders its plan allows, or the separate and far larger number of answers it may be served out of the cache. The X-RateLimit headers on this answer describe the limit that refused it. Wait for the number of seconds in the Retry-After header before sending the request again.
-
Status
500Worth retryingdo not retryCodesrender_failedserver_errorDescriptionThe render failed for a reason we did not recognise. The credit is refunded.
-
Status
502Worth retryingretryCodesupstream_errorupstream_quota_exceededDescriptionThe rendering service failed to process the request. The credit is refunded and the request is worth sending again.
-
Status
503Worth retryingretryCodesupstream_rate_limitedDescriptionThe rendering service was momentarily busy and stayed busy across our own retries. The credit is refunded. Unlike the 502 this is not a failure of anything: wait the few seconds in the Retry-After header and the same request goes through.
-
Status
504Worth retryingretryCodesrender_timeoutDescriptionThe render did not finish within its time budget. The credit is refunded and the request is worth sending again.
The statuses marked retry (429, 502, 503 and 504) carry a
Retry-After header with the number of seconds to wait before sending the same request again. Wait
that long rather than retrying straight away: a retry that arrives sooner is answered the same way.
The others describe a request that would fail the same way every time, so change something before you send it again. A render that fails after the request was accepted refunds its credit, so a retry costs you nothing you were not going to spend.
Error codes
Every code the API can answer with, and the status it comes back on. A status can carry more than one code,
because the status alone does not always say what happened: both 402s stop the request, but only
one of them is fixed by buying more credits.
-
Code
unauthenticatedStatus401DescriptionNo bearer token was sent, or the token is unknown or revoked.
-
Code
invalid_signatureStatus401DescriptionA signed URL did not verify. Either the signature does not match the query, or the token it names is unknown, revoked or expired. Rebuild the URL from the canonical form on the signed URLs page, and check that nothing was appended to it after it was signed.
-
Code
signed_url_expiredStatus401DescriptionA signed URL is past the `expires` moment it was signed with. The signature itself was fine, so sign a new URL with a later expiry.
-
Code
email_unverifiedStatus403DescriptionThe account exists but its email address has not been verified yet.
-
Code
missing_abilityStatus403DescriptionThe token is not allowed to ask for this mode. A token carries a permission per mode, `screenshot` and `pdf`, and both are granted unless the token was deliberately narrowed. Widen it in your dashboard, or send the request with a token that holds the permission.
-
Code
no_active_planStatus402DescriptionThe account is on no plan, so it has no credits to spend. Pick a plan and the same request works.
-
Code
credit_limit_reachedStatus402DescriptionEvery credit in the current period is spent. It resets at the end of the period.
-
Code
validation_failedStatus422DescriptionA query parameter is missing, malformed, or not accepted in the mode the request is in. The errors object names it.
-
Code
invalid_urlStatus422DescriptionThe url is missing or is not a URL the API will accept. Fix the string and send it again.
-
Code
blocked_hostStatus422DescriptionThe url points at a private, loopback or internal address. Reformatting it will not help; only a publicly reachable host is rendered.
-
Code
target_unreachableStatus422DescriptionThe page itself could not be reached or loaded. Check that it is publicly available.
-
Code
rate_limitedStatus429DescriptionThe account went over its renders per minute, or over the separate limit on the answers it may be served out of the cache. The X-RateLimit headers say which of the two. Wait for the Retry-After header and send the request again.
-
Code
render_failedStatus500DescriptionThe render failed for a reason we did not recognise. The credit is refunded.
-
Code
server_errorStatus500DescriptionSomething failed that we did not expect at all. The catch-all, and always worth reporting with the request id.
-
Code
upstream_errorStatus502DescriptionThe rendering service failed to process the request. The credit is refunded and a retry is worthwhile.
-
Code
upstream_quota_exceededStatus502DescriptionThe rendering service has spent its own capacity for the period. Nothing is broken, so back off for longer than you would on an ordinary upstream failure.
-
Code
upstream_rate_limitedStatus503DescriptionThe rendering service was busy and stayed busy while we retried. Nothing is broken and nothing about the request is wrong; wait the seconds in Retry-After and send it again.
-
Code
render_timeoutStatus504DescriptionThe render ran past its time budget. The credit is refunded and the same request may well succeed later.
-
Code
not_foundStatus404DescriptionNo endpoint exists at that path.
-
Code
method_not_allowedStatus405DescriptionThe endpoint exists but does not accept that HTTP method. The Allow header names the ones it does.
-
Code
api_movedStatus410DescriptionThe request went to the base URL the API used to be served on. Nothing about the request is wrong: send it to the base URL named in the message and the path after it, the parameters, the headers and the token all stay as they are.
Three of them are not tied to taking a screenshot: not_found, method_not_allowed and
server_error can answer any request under https://api.screenshotbuddy.io/v1, so handle them wherever you
call us rather than only around a render.
A fourth, api_moved, arrives from nowhere on this host at all:
it is what the base URL the API used to be served on answers now, and nothing but the base URL has to change to
make it go away.
Codes are a published contract. We add new ones as the API grows, so treat one you do not recognise the way you
would treat its status, and keep the request_id either way.
Validation errors
A request that leaves out url, or sends a parameter the mode it is in does not accept, comes back
as 422 with the parameter named in the errors object. The code says which kind of
failure it was: invalid_url for a url the API will not take, blocked_host for one it
will not visit, and validation_failed for any other parameter.
{
"code": "invalid_url",
"message": "The url query parameter is required.",
"errors": {
"url": [
"The url query parameter is required."
]
},
"request_id": "1f3c0e6a-6a5d-4a4c-9a3f-0a3f7d1c2b84"
}
Which parameters a mode accepts is on the taking
screenshots and creating PDFs pages. The
429 status has a page of its own under rate
limits.
See a real error before you handle one
The playground shows you the status and the message the API answers with, so you can read an error in the same shape your code will get it.