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.

402 Payment Required
{
  "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."
  }
}
  • type is stable. Branch on it in your code.
  • message is 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

StatusMeaning
200 OKThe request worked.
201 CreatedA scene was added.
202 AcceptedRenders were charged and queued; they finish in the background.
400 Bad RequestThe body is not JSON, or a header is malformed.
401 UnauthorizedNo key, or a key that is not valid.
402 Payment RequiredNot enough credits for the whole request.
403 ForbiddenThe key cannot do this, or your storage is full.
404 Not FoundNo such object in your workspace.
409 ConflictThe object, or the Idempotency-Key, is in a state that blocks the request.
422 Unprocessable ContentThe request is well formed but cannot be done as sent.
429 Too Many RequestsRate limited, or a daily limit reached.
500 Internal Server ErrorA fault on our side.

Error types

TypeStatusWhen
authentication_required401The request has no key. Send one in the Authorization header.
invalid_api_key401The key is not valid: mistyped, or revoked.
key_kind_not_allowed403A publishable key was sent to an endpoint that needs a secret key.
origin_not_allowed403Reserved. No endpoint takes a publishable key yet; the visualizer turns away websites not listed on its key itself.
storage_full403Your workspace's image storage is full, so a new scene cannot be added.
insufficient_credits402There are not enough credits for the whole request. Nothing was charged.
not_found404The scene, product or render does not exist in your workspace.
invalid_request400, 409, 422The request cannot be done as sent. The message says what to change.
conflict409The request clashes with the object's state, such as cancelling a render that has started.
rate_limited429Too many requests: wait for Retry-After. Also a workspace's daily scene limit.
server_error500Something 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 typeMessageCause and fix
401
authentication_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.
401
invalid_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.
403
key_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.
429
rate_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.
500
server_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 typeMessageCause and fix
429
rate_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.
422
invalid_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.
422
invalid_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.
422
invalid_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.
422
invalid_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.
422
invalid_request
Could not resolve images.example.com.image_url's host name does not exist. Fix: Check the link.
422
invalid_request
That is not a valid URL.image_url cannot be read as a link. Fix: Send a full https:// link.
422
invalid_request
Too many redirects.image_url redirects too many times. Fix: Send the final link the picture is at.
422
invalid_request
That image took too long to fetch.image_url did not answer within 20 seconds. Fix: Try again, or upload the file instead.
422
invalid_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.
422
invalid_request
That image is too large.The picture at image_url is larger than the limit. Fix: Send a smaller picture.
422
invalid_request
Image exceeds 30 MB limit.The uploaded file is larger than the limit. Fix: Send a smaller picture.
422
invalid_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.
422
invalid_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.
403
storage_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.
403
storage_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 typeMessageCause and fix
404
not_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 typeMessageCause and fix
400
invalid_request
Send a JSON body.The body is not JSON. Fix: Send JSON with Content-Type: application/json.
400
invalid_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.
422
invalid_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.
422
invalid_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 #.
404
not_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.
404
not_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.
422
invalid_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.
422
invalid_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.
422
invalid_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.
422
invalid_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.
422
invalid_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.
422
invalid_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.
422
invalid_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.
422
invalid_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.
422
invalid_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.
422
invalid_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.
422
invalid_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.
402
insufficient_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.
402
insufficient_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.
402
insufficient_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.
409
invalid_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.
409
invalid_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.
409
invalid_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.
422
invalid_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.
500
server_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 typeMessageCause and fix
404
not_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 typeMessageCause and fix
404
not_found
No such render.No render with that id in your workspace. Fix: Use an id from Create renders.
409
conflict
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

ResponseRetry?
429 rate_limitedYes, after the number of seconds in Retry-After. A daily scene limit resets at midnight UTC.
500 server_error, or no response at allYes, 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 processedYes, after a few seconds, with the same key and body.
402 insufficient_creditsOnly once the workspace has more credits.
400, 401, 403, 404, 422No. Fix the request, the key or the id first.

Something these pages do not answer? Email admin@skipshoot.com and we’ll help.