Skip to content

Reference

Responses and errors

The answer envelope, every error the API can send back, and how to handle each one.

On this page

Every answer from the API has the same shape, whether the capture worked or not. Your code reads the same four fields every time.

EnvelopeLink to this section

  • successbooleanAlways

    true when the screenshot was created, false for every error.

  • codenumberAlways

    The HTTP status of the answer, repeated in the body.

  • messagestringAlways

    What happened, in plain words. Safe to show to your own users.

  • dataobject | nullAlways

    The result on success. null on most errors, or the list of what is wrong when fields are missing.

The HTTP status of the answer is always the same as code, so you can check either one.

SuccessLink to this section

A finished capture answers with status 200, and data holds the hosted link and the image itself.

200 OK
{
  "success": true,
  "code": 200,
  "message": "Screenshot was generated.",
  "data": {
    "scrUrl": "https://.../screenshots/.../8f3c2a91d4e5b6c7.png",
    "scrBase64": "iVBORw0KGgoAAAANSUhEUgAA..."
  }
}

ErrorsLink to this section

An error answers with success set to false, a matching status and a readable message. data is usually null.

401 Unauthorized
{
  "success": false,
  "code": 401,
  "message": "User is not authorized to create screenshot!",
  "data": null
}

When required fields are missing, data lists them:

400 Bad Request
{
  "success": false,
  "code": 400,
  "message": "Missing parameters on the payload please include all the required values!",
  "data": ["token"]
}

Error messagesLink to this section

These are every message the screenshot endpoint can send back. The wording never changes, so it is safe to match on, and it is written to be shown to your own users as it is.

  • 400

    Inital request missing required parameters!

    The request was not sent as JSON. data says what is wrong with the Content-Type header.

  • 400

    Missing parameters on the payload please include all the required values!

    url or token is missing. data lists the missing fields.

  • 401

    User is not authorized to create screenshot!

    The token does not belong to any account, or it was regenerated.

  • 402

    URL is not valid, please check the link!

    The url could not be read as a web address.

  • 400

    You don't have enough credits to generate a screenshot!

    The balance is lower than the cost of the capture.

  • 405

    This method is not allowed!

    The request was not a POST.

  • 429

    You cannot start more than 3 concurrent screenshots. If you want to increase the limit contact support!

    Too many captures are already running for the account. The number is your own limit.

  • 400

    Screenshot was not generated because of a problem!

    The page could not be captured. The credits are returned.

  • 503

    The screenshot service is not available right now, please try again later!

    The capture browser is temporarily unavailable. No credits are used.

  • 500

    Screenshot was not generated because of a problem!

    Something failed on our side. The credits are returned.

Handling errorsLink to this section

  • Check success first. When it is false, show or log message.
  • 401, 402, 405 and the missing field errors need a change to the request. Sending it again as it is gives the same answer.
  • 429 means your captures in progress are at your limit. Wait for one to finish, or see limits.
  • 503 is temporary. Try again after a short wait, with a longer wait each time.
  • When a page cannot be captured, try a later takeScreenshotWhen step or a waitBeforeScreenshot. Your dashboard shows why each capture failed.

A small retry helper for the temporary errors:

capture.mjs
const RETRY = new Set([429, 503])

async function capture(body, attempt = 1) {
    const response = await fetch('https://url2image.modulify.website/api/screenshots/create', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body)
    })

    const result = await response.json()

    if (result.success) return result.data

    // Busy or briefly unavailable: wait a little longer each time
    if (RETRY.has(result.code) && attempt < 3) {
        await new Promise(resolve => setTimeout(resolve, attempt * 5000))

        return capture(body, attempt + 1)
    }

    throw new Error(result.message)
}

Something unclear or missing on this page?

Tell us