> ## Documentation Index
> Fetch the complete documentation index at: https://sudomock.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> The base URL is https://api.sudomock.com.
> Authenticate every request with the x-api-key header. Keys begin with sm_.
> A render returns the finished image at data.print_files[0].export_path. A request sent with is_async true returns a job_id to poll at GET /api/v1/jobs/{job_id}.
> Prefer the official SDKs over hand-written HTTP calls: npm install sudomock for Node, pip install sudomock for Python.

# Error codes and how to retry them

> Status codes, error_code values and safe retries.

Every failure returns a JSON body. Branch on `error_code` where it is present,
and always keep a default case that surfaces `message` and
`details.suggestion`, so an unfamiliar code degrades into a readable failure
instead of a crash.

Every endpoint answers with the same error envelope, so the codes below apply
across the API rather than per endpoint. The reference pages show the success
response; this page is where the failures live.

## Status codes

| Status | Meaning                                                                                                                                                                                                                                   |
| ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `200`  | Request succeeded.                                                                                                                                                                                                                        |
| `201`  | Resource created.                                                                                                                                                                                                                         |
| `204`  | Request succeeded with no body.                                                                                                                                                                                                           |
| `400`  | Invalid request format, missing fields, malformed JSON, or a PSD that could not be processed.                                                                                                                                             |
| `401`  | Missing, malformed or revoked credentials.                                                                                                                                                                                                |
| `402`  | The request cannot be paid for, or the account is in trial and the request exceeds a trial limit. Read `error_code` to tell the cases apart.                                                                                              |
| `403`  | Access is not available with this credential, or the account is at its stored PSD template ceiling.                                                                                                                                       |
| `404`  | Resource not found. Check `mockup_uuid`, `smart_object_uuid` or `key_id`.                                                                                                                                                                 |
| `409`  | The request conflicts with something that already exists or is still running: an `Idempotency-Key` reused for a different upload, a font name already on the account or the font ceiling reached, or a photo mockup still being prepared. |
| `413`  | The body is larger than the endpoint accepts. Applies to a PSD upload and to a background removal request.                                                                                                                                |
| `422`  | Body validation failed. Fix the input before retrying.                                                                                                                                                                                    |
| `429`  | Rate limit or concurrency limit exceeded. Read `Retry-After`.                                                                                                                                                                             |
| `500`  | Unexpected server error. Safe to retry with backoff.                                                                                                                                                                                      |
| `502`  | An upstream image source returned a `5xx`. Safe to retry with backoff.                                                                                                                                                                    |

## Error shapes

Most errors carry a human-readable message:

```json Standard error theme={"theme":{"light":"github-light","dark":"vesper"}}
{
  "detail": "Human-readable error message",
  "success": false
}
```

PSD and render failures add a machine-readable `error_code` and a `details`
object with a suggestion:

```json Structured error theme={"theme":{"light":"github-light","dark":"vesper"}}
{
  "error_code": "PSD_PARSE_FAILED",
  "message": "Failed to parse PSD file",
  "detail": "Failed to parse PSD file",
  "details": {
    "reason": "Invalid or corrupted PSD/PSB header",
    "suggestion": "Re-export the PSD from Adobe Photoshop"
  },
  "success": false
}
```

## Upload error codes

`POST /api/v1/psd/upload` returns these on `error_code`.

| Code                                  | HTTP | What to do                                                                                                                  |
| ------------------------------------- | ---- | --------------------------------------------------------------------------------------------------------------------------- |
| `PSD_DOWNLOAD_FAILED`                 | 400  | The file could not be fetched. Check that the URL is public and serving.                                                    |
| `PSD_PARSE_FAILED`                    | 400  | Invalid or corrupted PSD or PSB. Re-export from Photoshop.                                                                  |
| `DIMENSION_TOO_LARGE`                 | 400  | Pixel dimensions exceed 10000 by 10000. Resize the document.                                                                |
| `NO_SMART_OBJECTS`                    | 400  | The file has neither a visible smart object nor a text layer. Make one visible or add one.                                  |
| `UNSUPPORTED_FEATURE`                 | 400  | Flatten or simplify the layer that uses it.                                                                                 |
| `UNSUPPORTED_SMART_OBJECT_FORMAT`     | 400  | A smart object holds a vector format. Rasterize the layer in Photoshop.                                                     |
| `LINKED_SMART_OBJECT_CONTENT_MISSING` | 422  | Permanent. Run Embed Linked in Photoshop, or supply the design in the render request. Retrying the same file will not help. |
| `SMART_OBJECT_EXTRACTION_FAILED`      | 500  | The smart object may be damaged. Re-export it.                                                                              |
| `LAYER_RENDER_FAILED`                 | 500  | A layer could not be rendered. Simplify its effects.                                                                        |
| `INTERNAL_ERROR`                      | 500  | Retry the upload.                                                                                                           |

<Warning>
  `LINKED_SMART_OBJECT_CONTENT_MISSING` is permanent. Re-uploading the same file
  produces the same result. Most linked smart objects render fine as
  placeholders and do not need embedding.
</Warning>

## Render error codes

Render, text layer, font, artwork and photo mockup failures use the same
`error_code` field. Take the HTTP status from the response rather than from this
table.

| Code                        | Meaning                                                            | What to do                                                                                 |
| --------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
| `OUTPUT_RESOLUTION_LIMIT`   | The account is in trial and `image_size` is above the 1024 px cap. | Lower `image_size`, or add a payment method to render at full width.                       |
| `OUTPUT_TOO_LARGE_FOR_WEBP` | The requested WebP output is too large to encode.                  | Reduce `image_size`, or use PNG output.                                                    |
| `REUPLOAD_REQUIRED`         | The mockup data is incomplete or outdated.                         | Re-upload the PSD, then retry. Retrying the same render will keep failing.                 |
| `ASSET_UNREACHABLE`         | The artwork could not be downloaded.                               | Check that the artwork URL is public. Safe to retry once the source is back.               |
| `ASSET_BLOCKED`             | The artwork URL cannot be used.                                    | Host the artwork somewhere publicly reachable, or send it as base64.                       |
| `ARTWORK_TOO_LARGE`         | An artwork input exceeds the allowed file size.                    | Downscale or recompress it before sending.                                                 |
| `PRINT_AREA_NOT_FOUND`      | A `print_area_uuid` does not belong to this photo mockup.          | Re-read the print areas from the mockup, then retry.                                       |
| `MOCKUP_NAME_EXISTS`        | A photo mockup with this name already exists.                      | Pick a different name. Names are unique per account.                                       |
| `FONT_NOT_FOUND`            | An explicitly requested font identifier is not in your catalogue.  | Upload the font, or request one that is listed.                                            |
| `psd_limit_reached`         | The account is at its stored PSD template ceiling.                 | Delete a template, or move to a plan with a higher limit. Stored templates keep rendering. |

These are the codes integrations hit most often, not an exhaustive registry.

## Rate limits and concurrency limits

Two ceilings answer `429`: a request rate, and a cap on how many long
operations run at once. Both report their state in response headers, and
`error.type` says which one you hit.

<Card title="Usage limits" icon="gauge" href="/docs/api-reference/usage-limits" horizontal>
  The numbers, the headers, and both `429` bodies.
</Card>

## Retry strategy

Retry `429`, `500`, `502`, `503`, `504` and network errors. Do not retry `400`,
`401`, `402`, `403`, `404` or `422`: fix the request or the billing state first.

```javascript Retry with backoff theme={"theme":{"light":"github-light","dark":"vesper"}}
async function apiRequest(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, options)

    if (response.ok) return response.json()

    // A limit was hit. The server says how long to wait.
    if (response.status === 429) {
      const retryAfter = parseInt(
        response.headers.get('Retry-After') || '60',
      )
      await sleep(retryAfter * 1000)
      continue
    }

    // Server side or upstream. Back off and try again.
    if (response.status >= 500) {
      await sleep(Math.pow(2, attempt) * 1000)
      continue
    }

    // Client side. Fix the request instead of repeating it.
    const error = await response.json()
    throw new Error(
      error.detail || error.message || JSON.stringify(error),
    )
  }

  throw new Error('Max retries exceeded')
}

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms))
}
```

Credits are charged only on successful requests. A failed request is not
charged.

<CardGroup cols={2}>
  <Card title="Webhooks" icon="bell" href="/docs/webhooks/overview">
    Let long jobs call you back instead of polling them.
  </Card>

  <Card title="Plans and limits" icon="code" href="/docs/api-reference/packages/get-all-subscription-plans">
    Read the live concurrency and template ceilings for an account.
  </Card>
</CardGroup>
