> ## 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.

# Render mockups with Airtable and SudoMock

> Render mockups from Airtable records with a script automation.

[Airtable](https://airtable.com) stores your designs as records. An automation
with a **Run a script** action calls the SudoMock render API when a record is
ready, and writes the finished image URL back onto the same record. There is
nothing to install.

## Before you start

* An API key from your [dashboard](https://sudomock.com/dashboard/api-keys).
* A template. [Upload a PSD](/docs/psd-mockups/upload-a-psd) if you do not have one.
* Artwork at a URL that loads without signing in, because SudoMock fetches it.

Two ids go into every render: the mockup uuid, and the uuid of the layer you
fill. Both arrive together from
[List PSD mockups](/docs/api-reference/psd-mockups/retrieve-a-list-of-psd-mockups),
where each entry carries its own `uuid` and a `smart_objects` array holding the
`uuid` of every layer you can fill. That page has the call ready to copy in
eight languages. Read the pair once and keep it.

## Guide

<Steps>
  <Step title="Lay out the table">
    Four fields are enough to start:

    | Field | Type | What it holds |
    | - | - | - |
    | Design URL | URL | The artwork to place |
    | Product | Single select | Which template to render |
    | Mockup URL | URL | Written back by the script |
    | Status | Single select | Pending, Done, or Error |
  </Step>

  <Step title="Create the automation">
    Open **Automations**, create one, and choose the trigger **When record
    matches conditions**. Set the condition to `Status is Pending` so a record
    enters the run exactly once.
  </Step>

  <Step title="Add the script action">
    Add a **Run a script** action. In the left panel add two input variables,
    `designUrl` mapped to the Design URL field and `product` mapped to the
    Product field, then paste the script.

    ```javascript theme={"theme":{"light":"github-light","dark":"vesper"}}
    const { designUrl, product } = input.config();

    const TEMPLATES = {
      't-shirt': {
        mockup: 'YOUR_MOCKUP_UUID',
        layer: 'YOUR_SMART_OBJECT_UUID',
      },
      mug: {
        mockup: 'YOUR_MOCKUP_UUID',
        layer: 'YOUR_SMART_OBJECT_UUID',
      },
    };

    const template = TEMPLATES[String(product).toLowerCase()];
    if (!template) {
      throw new Error(`No template mapped for ${product}`);
    }

    const response = await fetch(
      'https://api.sudomock.com/api/v1/renders',
      {
        method: 'POST',
        headers: {
          'x-api-key': 'sm_your_api_key',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          mockup_uuid: template.mockup,
          smart_objects: [
            {
              uuid: template.layer,
              asset: { url: designUrl, fit: 'crop' },
            },
          ],
          export_options: {
            image_format: 'webp',
            image_size: 1920,
            quality: 90,
          },
        }),
      },
    );

    const result = await response.json();
    if (!response.ok) {
      throw new Error(result.detail || 'Render failed');
    }

    output.set(
      'mockupUrl',
      result.data.print_files[0].export_path,
    );
    ```

    <Warning>
      `input.config()` is the only way to read a mapped field. A value typed
      into the script body is literal text, so the render runs against the
      placeholder instead of the record.
    </Warning>
  </Step>

  <Step title="Write the result back">
    Add an **Update record** action. Map Mockup URL to the script output
    `mockupUrl`, and set Status to Done. Add a second automation on
    `Status is Error` if you want failures to reach someone.
  </Step>
</Steps>

## What comes back

The finished image URL arrives at `data.print_files[0].export_path`. That single
string is what the Update record action writes, and the whole response, field by
field, is on
[Render a PSD mockup](/docs/api-reference/psd-mockups/render-a-psd-mockup).

## Filling a whole table at once

A script action is built for one record at a time, so a backlog is better sent
as asynchronous work. Add `is_async: true` to the same body and the render is
queued instead of awaited.

The call then answers `202` with `job_id`, `kind`, `status`, and `status_url` at
the top level, so nothing is nested under `data` on this path. Put the job id on
the record with `output.set`, then run a second, scheduled automation that reads
[Retrieve a job](/docs/api-reference/jobs/retrieve-a-single-job). Once `status` reads
`succeeded`, the image sits at `result_url` on that same body. A [webhook](/docs/webhooks/overview) removes
the polling entirely if you have somewhere to receive one.

## When a render fails

A `401` means the `x-api-key` header is missing or incomplete. A `422` names the
field it rejected, and is almost always an empty mapped value reaching the API
as literal text. A download failure means the design URL asks for a login. Every
status is listed in [Errors](/docs/errors).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.