Errors and status codes
Every error has the same shape: an HTTP status, a stable type and a message written for people. Here is every one, and what to do about it.
Updated
The error object
Every error, from every endpoint, has the same body: one error object with a type and a message.
{
"error": {
"type": "insufficient_credits",
"message": "These renders need 12 credits and this workspace has 5 left. Send fewer renders, or move to a larger plan in Settings → Workspace."
}
}typeis stable. Branch on it in your code.messageis written for people and may be reworded at any time. Log it or show it to your team, but never match on its text.- A refused request never charges anything.
Status codes
| Status | Meaning |
|---|---|
| 200 OK | The request worked. |
| 201 Created | A scene was added. |
| 202 Accepted | Renders were charged and queued; they finish in the background. |
| 400 Bad Request | The body is not JSON, or a header is malformed. |
| 401 Unauthorized | No key, or a key that is not valid. |
| 402 Payment Required | Not enough credits for the whole request. |
| 403 Forbidden | The key cannot do this, or your storage is full. |
| 404 Not Found | No such object in your workspace. |
| 409 Conflict | The object, or the Idempotency-Key, is in a state that blocks the request. |
| 422 Unprocessable Content | The request is well formed but cannot be done as sent. |
| 429 Too Many Requests | Rate limited, or a daily limit reached. |
| 500 Internal Server Error | A fault on our side. |
Error types
| Type | Status | When |
|---|---|---|
authentication_required | 401 | The request has no key. Send one in the Authorization header. |
invalid_api_key | 401 | The key is not valid: mistyped, or revoked. |
key_kind_not_allowed | 403 | A publishable key was sent to an endpoint that needs a secret key. |
origin_not_allowed | 403 | Reserved. No endpoint takes a publishable key yet; the visualizer turns away websites not listed on its key itself. |
storage_full | 403 | Your workspace's image storage is full, so a new scene cannot be added. |
insufficient_credits | 402 | There are not enough credits for the whole request. Nothing was charged. |
not_found | 404 | The scene, product or render does not exist in your workspace. |
invalid_request | 400, 409, 422 | The request cannot be done as sent. The message says what to change. |
conflict | 409 | The request clashes with the object's state, such as cancelling a render that has started. |
rate_limited | 429 | Too many requests: wait for Retry-After. Also a workspace's daily scene limit. |
server_error | 500 | Something went wrong on our side. A render request that fails this way charges nothing. |
An object in another workspace is reported as not_found, exactly like one that does not exist, so nothing about other workspaces can be learned from an error.
Error messages by endpoint
Every message the API sends, as it sends it, with an example value where one is filled in. Messages may be reworded over time; the type and status will not change.
Every endpoint
| Status and type | Message | Cause and fix |
|---|---|---|
401authentication_required | Send your API key as Authorization: Bearer <key>. | No Authorization header, or one not in the Bearer form. Fix: Send Authorization: Bearer, a space, then your secret key. |
401invalid_api_key | This API key is not valid. It may have been revoked. | The key is mistyped, cut short or revoked, or the API is not switched on for the workspace yet. Fix: Copy the key again, or create a new one in Settings → Developers. |
403key_kind_not_allowed | A publishable key cannot call this endpoint. Use a secret key from your server. | A publishable key was sent to the API. Fix: Use a secret key, from your server. |
429rate_limited | Too many requests. Try again in 17 seconds. | The key made more requests this minute than its limit. Fix: Wait for Retry-After, then send the same request again. |
500server_error | Something went wrong on our side. | A fault on our side. Fix: Retry with a growing wait. For a render request, keep the same Idempotency-Key. |
POST /scenes
| Status and type | Message | Cause and fix |
|---|---|---|
429rate_limited | This workspace has added 500 scenes through the API today, the most a day allows. Add more after midnight UTC. | The workspace reached its daily limit on new scenes. Fix: Add the rest after midnight UTC. Reuse scenes where you can. |
422invalid_request | Send a room picture as multipart field `image`, or JSON `image_url`. | No picture was sent. Fix: Send image as a multipart file, or image_url in a JSON body. |
422invalid_request | `setting` must be "indoor" or "outdoor". | setting is something else (Outdoor, outside, a typo). Fix: Send "indoor" or "outdoor", or leave setting out for indoors. |
422invalid_request | That host resolves to a private address. | image_url points inside a private network. Fix: Use a public link, or upload the file instead. |
422invalid_request | That address is not publicly routable. | image_url is an IP address that is not public. Fix: Use a public link, or upload the file instead. |
422invalid_request | Could not resolve images.example.com. | image_url's host name does not exist. Fix: Check the link. |
422invalid_request | That is not a valid URL. | image_url cannot be read as a link. Fix: Send a full https:// link. |
422invalid_request | Too many redirects. | image_url redirects too many times. Fix: Send the final link the picture is at. |
422invalid_request | That image took too long to fetch. | image_url did not answer within 20 seconds. Fix: Try again, or upload the file instead. |
422invalid_request | Could not fetch that image (HTTP 404). | The image_url answered with an error. Fix: Check the link opens without a login, or upload the file instead. |
422invalid_request | That image is too large. | The picture at image_url is larger than the limit. Fix: Send a smaller picture. |
422invalid_request | Image exceeds 30 MB limit. | The uploaded file is larger than the limit. Fix: Send a smaller picture. |
422invalid_request | Use a JPEG, PNG, or WebP photo. | The file is not one of the accepted formats. Fix: Convert it to JPEG, PNG or WebP. |
422invalid_request | That file could not be read as an image. | The file is damaged, or not really an image. Fix: Export the picture again and resend it. |
403storage_full | This workspace has used its 10 GB of image storage. Delete products or gallery images you no longer need, or move to Pro for 15 GB. Nothing was uploaded. | The workspace's image storage is full. Fix: Delete what you no longer need in the app, or move to a plan with more storage. |
403storage_full | This workspace holds 500 of its 500 uploads. Delete products you no longer need, or move to Pro for 15 GB. Nothing was uploaded. | The plan's uploads are used up. Room pictures count, as product images do. Fix: Delete products you no longer need, or move to a larger plan. |
GET /scenes/{id}
| Status and type | Message | Cause and fix |
|---|---|---|
404not_found | No such scene. | No scene with that id in your workspace. Fix: Check the id, and that the key belongs to the right workspace. |
POST /renders
| Status and type | Message | Cause and fix |
|---|---|---|
400invalid_request | Send a JSON body. | The body is not JSON. Fix: Send JSON with Content-Type: application/json. |
400invalid_request | Idempotency-Key must be 1 to 255 visible characters. | The Idempotency-Key header is empty, too long or has spaces. Fix: Use 1 to 255 visible ASCII characters. |
422invalid_request | Send scene_id with either product_id or paint: { hex }, or renders: [...] with up to 100 of them. | A field is missing or of the wrong type, both or neither of product_id and paint were sent, or there are no renders or too many. Fix: Send exactly one of product_id or paint in each render, and at most 100 renders. |
422invalid_request | A paint color needs a hex code like #A1B2C3. | paint.hex is not a color. Fix: Send six hex digits, or three, with or without #. |
404not_found | Scene 42 is not in your workspace. | A scene_id is not a scene of your workspace. Fix: Use ids from List all scenes. |
404not_found | Product 1077 is not in your catalog. | A product_id is not a product your workspace can render. Fix: Use ids from List all products. |
422invalid_request | "Library" is not a scene the API can render into. Use one listed by GET /v1/scenes. | The scene is not one renders can go into. Fix: Choose a scene from List all scenes. |
422invalid_request | "Library" has no picture to render into. Add the room again with POST /v1/scenes, or choose another scene. | The scene has no picture. Fix: Add the room again, or choose another scene. |
422invalid_request | We are still finding the surfaces in "Library". Try again in a minute. | The scene is still analyzing. Fix: Wait until the scene is ready, then send the request again. |
422invalid_request | The surfaces in "Library" have not been found. Add the room again with POST /v1/scenes, or choose another scene. | The scene's analysis failed, or never ran. Fix: Add the room again with a clearer picture, or choose another scene. |
422invalid_request | Scene "Library" has no surface with that surface_id. Use one listed by GET /v1/scenes/{id}, or leave surface_id out. | The surface_id is not one of the scene's surfaces. Fix: Use an id from the scene's surfaces, or leave surface_id out. |
422invalid_request | Emerald velvet can't go on Back wall in "Living room". Name a surface it suits, or leave surface_id out. | The named surface's type does not suit the product. Fix: Name a surface the product fits, or leave surface_id out. |
422invalid_request | Floor in "Living room" can't be painted. Name a wall, ceiling or cabinet surface, or leave surface_id out. | A paint render names a surface that is not a wall, ceiling or cabinet. Fix: Name a wall, ceiling or cabinet surface, or leave surface_id out. |
422invalid_request | "Oak herringbone" fits no surface found in "Library". Choose another scene, or name a surface with surface_id. | With no surface_id, the scene has no surface the product fits. Fix: Choose a scene with the right kind of surface. |
422invalid_request | "Back patio" has no wall, ceiling or cabinets to paint. Choose another scene. | A paint render's scene has nothing paint can go on. Fix: Choose another scene. |
422invalid_request | The same render is in this request twice, in "Living room". | Two items would make the same render, including after the surface is chosen for you. Fix: Remove the repeat. |
422invalid_request | We could not open the picture for "Library". Try again, or choose another scene. | The scene's picture could not be read at that moment. Fix: Send the request again. Nothing was charged. |
402insufficient_credits | These renders need 12 credits and this workspace has 5 left. Send fewer renders, or move to a larger plan in Settings → Workspace. | Not enough credits for every render in the request. Nothing was charged. Fix: Send fewer renders, or add credits. |
402insufficient_credits | This workspace has used all 1500 of its credits. They refresh with the next period, or move to a larger plan in Settings → Workspace for more. | No credits are left this period. Fix: Wait for credits to renew, or move to a larger plan. |
402insufficient_credits | This workspace has no credits yet. Move to a plan with credits in Settings → Workspace. | The workspace has no plan with credits. Fix: Choose a plan in Settings → Workspace. |
409invalid_request | A request with that Idempotency-Key is still being processed. | The first request with that key has not finished. Fix: Wait a few seconds, then send it again with the same key and body. |
409invalid_request | That Idempotency-Key is in use. Try again in a moment. | Another request with that key arrived at the same moment. Fix: Wait a moment, then send it again with the same key and body. |
409invalid_request | A request with that Idempotency-Key stopped while it was being charged and may have queued renders. Sending it again could pay twice; contact admin@skipshoot.com and we will sort it out. | Rarely: the first request was interrupted while it was being charged. Fix: Email us with the key. Do not send it with a new key. |
422invalid_request | That Idempotency-Key was already used for a different request. | The key was used before with a different body. Fix: Use a new key for new work. |
500server_error | These renders could not be queued. No credits were used. | The renders could not be queued, on our side. Fix: Send the request again, with the same Idempotency-Key. |
GET /renders/{id}
| Status and type | Message | Cause and fix |
|---|---|---|
404not_found | No such render. | No render with that id in your workspace, or the id is not a UUID. Fix: Use an id from Create renders. |
DELETE /renders/{id}
| Status and type | Message | Cause and fix |
|---|---|---|
404not_found | No such render. | No render with that id in your workspace. Fix: Use an id from Create renders. |
409conflict | This render has already started, so it cannot be cancelled. | The render is no longer queued. Fix: Nothing to do: it will finish, or fail at no charge. |
Handle errors in code
Check the status first, then the type. A small wrapper keeps this in one place; the client code has a complete one.
class SkipShootError extends Error {
constructor(status, type, message) {
super(message);
this.status = status;
this.type = type;
}
}
async function skipshoot(path, options = {}) {
const response = await fetch(`https://www.skipshoot.com/api/v1${path}`, {
...options,
headers: {
Authorization: `Bearer ${process.env.SKIPSHOOT_SECRET_KEY}`,
"Content-Type": "application/json",
...options.headers,
},
});
const body = await response.json();
if (!response.ok) {
throw new SkipShootError(response.status, body.error.type, body.error.message);
}
return body;
}Which errors to retry
| Response | Retry? |
|---|---|
| 429 rate_limited | Yes, after the number of seconds in Retry-After. A daily scene limit resets at midnight UTC. |
| 500 server_error, or no response at all | Yes, with a growing wait. For a render request, send the same Idempotency-Key and body, so a retry cannot charge twice. |
| 409 on an Idempotency-Key still being processed | Yes, after a few seconds, with the same key and body. |
| 402 insufficient_credits | Only once the workspace has more credits. |
| 400, 401, 403, 404, 422 | No. Fix the request, the key or the id first. |
Something these pages do not answer? Email admin@skipshoot.com and we’ll help.
