> ## 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 from a Go service

> Upload a PSD and render it with net/http and encoding/json.

<Prompt description="Rules for an agent adding SudoMock to a Go service." icon="sparkles" actions={["copy", "cursor"]}>
  You are adding SudoMock mockup rendering to a Go service.

  Setup

  * Use `net/http` and `encoding/json` from the standard library. Add no dependency.
  * Read the key with `os.Getenv("SUDOMOCK_API_KEY")` and fail at startup when it is empty.
  * The base URL is `https://api.sudomock.com`.
  * The official client libraries are Node and Python, listed at `https://sudomock.com/docs/sdks`. In Go, call the API directly.

  The two calls

  * `POST /api/v1/psd/upload` with `psd_file_url` and an optional `psd_name`. Read `data.uuid` and `data.smart_objects[].uuid` from the reply. Run this once at setup, never per render.
  * `POST /api/v1/renders` with `mockup_uuid`, `smart_objects` and `export_options`. Read the finished image from `data.print_files[0].export_path`.

  ALWAYS DO

  * Send the key in the `x-api-key` header, plus `Content-Type: application/json`.
  * Give the `http.Client` a timeout and build requests with `http.NewRequestWithContext`.
  * Reuse one `*http.Client` for the whole process rather than one per call.
  * Keep the mockup UUID and the smart object UUID in configuration and reuse them.
  * Check the status code before decoding, and read `error_code` and `detail` from a failed reply.
  * Carry the status and `error_code` on a typed error, so a caller branches with `errors.As` on values rather than on message text.
  * Retry `429`, `500` and `502` with backoff, waiting out `Retry-After` when the reply carries it. Never retry `400`, `401`, `402`, `404` or `422`.
  * For a render that takes a while, send `is_async` as `true`, read `job_id` from the `202`, then poll `GET /api/v1/jobs/{job_id}` or let a webhook call the service back.

  NEVER DO

  * Never hardcode the key, commit it, or send it from browser code.
  * Never send the key in an `Authorization` header. It goes in `x-api-key`.
  * Never invent a field name. `fit` is one of `fill`, `fit` or `crop`, and `image_format` is one of `png`, `jpg` or `webp`.
  * Never upload the PSD again on every render.
  * Never treat `402` as a transient failure. An account on trial credits caps `image_size`, and a larger value comes back as `OUTPUT_RESOLUTION_LIMIT` rather than a quietly smaller image. Read `error_code`, then fix the request or the billing state.

  Verify

  * `GET https://api.sudomock.com/api/v1/me` with the same header returns the account. Use it to prove the key works before rendering anything.
  * Every code a call can return is listed at `https://sudomock.com/docs/errors`.
</Prompt>

## Prerequisites

* An API key from [API keys](/docs/dashboard/api-keys).
* A PSD holding at least one smart object. See
  [Preparing a PSD](/docs/psd-mockups/preparing-a-psd).

## Guide

<Steps>
  <Step title="Set the API key">
    The key lives in the environment, so it never reaches the binary and never
    reaches a commit. No `go get` follows.

    <CodeGroup>
      ```bash macOS and Linux theme={"theme":{"light":"github-light","dark":"vesper"}}
      go mod init example.com/storefront
      export SUDOMOCK_API_KEY="sm_your_api_key"
      ```

      ```powershell Windows theme={"theme":{"light":"github-light","dark":"vesper"}}
      go mod init example.com/storefront
      $env:SUDOMOCK_API_KEY = "sm_your_api_key"
      ```
    </CodeGroup>
  </Step>

  <Step title="Upload the PSD once">
    `POST /api/v1/psd/upload` takes a public URL to the file and answers with the
    mockup plus every layer a render can address. Run it once with
    `go run ./cmd/upload`.

    ```go cmd/upload/main.go theme={"theme":{"light":"github-light","dark":"vesper"}}
    package main

    import (
    	"context"
    	"encoding/json"
    	"fmt"
    	"io"
    	"log"
    	"net/http"
    	"os"
    	"strings"
    	"time"
    )

    var client = &http.Client{Timeout: 120 * time.Second}

    type uploadReply struct {
    	Data struct {
    		UUID         string `json:"uuid"`
    		SmartObjects []struct {
    			UUID      string `json:"uuid"`
    			LayerName string `json:"layer_name"`
    		} `json:"smart_objects"`
    	} `json:"data"`
    }

    func main() {
    	body := strings.NewReader(`{
    	  "psd_file_url": "https://example.com/tee.psd",
    	  "psd_name": "Heavyweight tee front"
    	}`)

    	req, err := http.NewRequestWithContext(
    		context.Background(),
    		http.MethodPost,
    		"https://api.sudomock.com/api/v1/psd/upload",
    		body,
    	)
    	if err != nil {
    		log.Fatal(err)
    	}
    	req.Header.Set("x-api-key", os.Getenv("SUDOMOCK_API_KEY"))
    	req.Header.Set("Content-Type", "application/json")

    	res, err := client.Do(req)
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer res.Body.Close()
    	if res.StatusCode != http.StatusOK {
    		payload, _ := io.ReadAll(res.Body)
    		log.Fatalf("sudomock %d: %s", res.StatusCode, payload)
    	}

    	var reply uploadReply
    	err = json.NewDecoder(res.Body).Decode(&reply)
    	if err != nil {
    		log.Fatal(err)
    	}

    	fmt.Println("mockup:", reply.Data.UUID)
    	for _, o := range reply.Data.SmartObjects {
    		fmt.Println("layer:", o.UUID, o.LayerName)
    	}
    }
    ```

    ```text theme={"theme":{"light":"github-light","dark":"vesper"}}
    mockup: 8f2c1d90-6b4e-4a37-9e55-0d1c7a3f21b8
    layer: b41a7e52-93c8-4d61-8f07-2ae5c9d04713 Front print
    ```

    Keep both UUIDs in configuration. Every render from here reuses them.
  </Step>

  <Step title="Render the mockup">
    `POST /api/v1/renders` fills the smart object with artwork and answers with
    the finished image at `data.print_files[0].export_path`. Run it with
    `go run ./cmd/render`.

    ```go cmd/render/main.go theme={"theme":{"light":"github-light","dark":"vesper"}}
    package main

    import (
    	"context"
    	"encoding/json"
    	"fmt"
    	"io"
    	"log"
    	"net/http"
    	"os"
    	"strings"
    	"time"
    )

    var client = &http.Client{Timeout: 120 * time.Second}

    type renderReply struct {
    	Data struct {
    		PrintFiles []struct {
    			ExportPath string `json:"export_path"`
    		} `json:"print_files"`
    	} `json:"data"`
    }

    func main() {
    	body := strings.NewReader(`{
    	  "mockup_uuid": "8f2c1d90-6b4e-4a37-9e55-0d1c7a3f21b8",
    	  "smart_objects": [
    	    {
    	      "uuid": "b41a7e52-93c8-4d61-8f07-2ae5c9d04713",
    	      "asset": {
    	        "url": "https://example.com/artwork.png",
    	        "fit": "crop"
    	      }
    	    }
    	  ],
    	  "export_options": {
    	    "image_format": "webp",
    	    "image_size": 1920,
    	    "quality": 90
    	  }
    	}`)

    	req, err := http.NewRequestWithContext(
    		context.Background(),
    		http.MethodPost,
    		"https://api.sudomock.com/api/v1/renders",
    		body,
    	)
    	if err != nil {
    		log.Fatal(err)
    	}
    	req.Header.Set("x-api-key", os.Getenv("SUDOMOCK_API_KEY"))
    	req.Header.Set("Content-Type", "application/json")

    	res, err := client.Do(req)
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer res.Body.Close()
    	if res.StatusCode != http.StatusOK {
    		payload, _ := io.ReadAll(res.Body)
    		log.Fatalf("sudomock %d: %s", res.StatusCode, payload)
    	}

    	var reply renderReply
    	err = json.NewDecoder(res.Body).Decode(&reply)
    	if err != nil {
    		log.Fatal(err)
    	}

    	fmt.Println(reply.Data.PrintFiles[0].ExportPath)
    }
    ```
  </Step>
</Steps>

## Next steps

<CardGroup cols={3}>
  <Card title="Upload a PSD" icon="upload" href="/docs/api-reference/psd-mockups/create-a-mockup-from-a-psd">
    The upload call and its reply.
  </Card>

  <Card title="Render a mockup" icon="image" href="/docs/api-reference/psd-mockups/render-a-psd-mockup">
    Every field a render takes.
  </Card>

  <Card title="Jobs" icon="clock" href="/docs/api-reference/jobs/retrieve-a-single-job">
    Follow a long render by id.
  </Card>

  <Card title="Quickstart" icon="terminal" href="/docs/quickstart">
    The same two calls in cURL.
  </Card>

  <Card title="Fit and blend modes" icon="crop" href="/docs/concepts/fit-and-blend-modes">
    How artwork meets the layer.
  </Card>

  <Card title="Webhooks" icon="bell" href="/docs/webhooks/overview">
    Let a finished render call you.
  </Card>

  <Card title="Errors" icon="triangle-alert" href="/docs/errors">
    Every code, and what to do.
  </Card>

  <Card title="Custom domains" icon="globe" href="/docs/dashboard/custom-domains">
    Serve renders from your domain.
  </Card>
</CardGroup>
