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

# Fonts

> Browse the catalogue and upload your own typefaces.

A font is the typeface a text layer is drawn in. Every account renders from a
shared catalogue, and Pro and Scale accounts add their own licensed files to
it. A render names the font it wants, and the layer comes back set in it.

Reach for the catalogue when you need to:

* **Match a brand**: render in the typeface your licence covers.
* **Pick without uploading**: use an open-licensed family already on the account.
* **Know before you render**: see which templates fall back to a default.

## Browse the catalogue

The catalogue is the open-licensed Google Fonts library, 2,000+ families under
the OFL, Apache and UFL licences, free to use in commercial work. Narrow it by
name, classification or origin.

<CodeGroup>
  ```js Node.js {1} theme={"theme":{"light":"github-light","dark":"vesper"}}
  const response = await fetch("https://api.sudomock.com/api/v1/fonts?search=Open&category=sans-serif", {
    method: "GET",
    headers: { "x-api-key": "sm_your_api_key" },
  });

  const data = await response.json();
  console.log(data);
  ```

  ```php PHP {3} theme={"theme":{"light":"github-light","dark":"vesper"}}
  <?php

  $ch = curl_init("https://api.sudomock.com/api/v1/fonts?search=Open&category=sans-serif");
  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
      "x-api-key: sm_your_api_key",
  ]);

  $response = curl_exec($ch);
  curl_close($ch);

  echo $response;
  ```

  ```python Python {4} theme={"theme":{"light":"github-light","dark":"vesper"}}
  import requests

  response = requests.get(
      "https://api.sudomock.com/api/v1/fonts?search=Open&category=sans-serif",
      headers={"x-api-key": "sm_your_api_key"},
  )

  response.raise_for_status()
  print(response.json())
  ```

  ```ruby Ruby {4} theme={"theme":{"light":"github-light","dark":"vesper"}}
  require "net/http"
  require "uri"

  uri = URI("https://api.sudomock.com/api/v1/fonts?search=Open&category=sans-serif")
  request = Net::HTTP::Get.new(uri)
  request["x-api-key"] = "sm_your_api_key"

  response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
    http.request(request)
  end

  puts response.body
  ```

  ```go Go {10} theme={"theme":{"light":"github-light","dark":"vesper"}}
  package main

  import (
  	"fmt"
  	"io"
  	"net/http"
  )

  func main() {
  	req, err := http.NewRequest("GET", "https://api.sudomock.com/api/v1/fonts?search=Open&category=sans-serif", nil)
  	if err != nil {
  		panic(err)
  	}
  	req.Header.Set("x-api-key", "sm_your_api_key")

  	res, err := http.DefaultClient.Do(req)
  	if err != nil {
  		panic(err)
  	}
  	defer res.Body.Close()

  	body, _ := io.ReadAll(res.Body)
  	fmt.Println(string(body))
  }
  ```

  ```java Java {7} theme={"theme":{"light":"github-light","dark":"vesper"}}
  import java.net.URI;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;

  HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create("https://api.sudomock.com/api/v1/fonts?search=Open&category=sans-serif"))
      .header("x-api-key", "sm_your_api_key")
      .GET()
      .build();

  HttpResponse<String> response = HttpClient.newHttpClient()
      .send(request, HttpResponse.BodyHandlers.ofString());

  System.out.println(response.body());
  ```

  ```csharp .NET {4} theme={"theme":{"light":"github-light","dark":"vesper"}}
  using System.Net.Http;
  using System.Text;

  var request = new HttpRequestMessage(HttpMethod.Get, "https://api.sudomock.com/api/v1/fonts?search=Open&category=sans-serif");
  request.Headers.Add("x-api-key", "sm_your_api_key");

  var client = new HttpClient();
  var response = await client.SendAsync(request);

  Console.WriteLine(await response.Content.ReadAsStringAsync());
  ```

  ```bash cURL {1} theme={"theme":{"light":"github-light","dark":"vesper"}}
  curl -X GET "https://api.sudomock.com/api/v1/fonts?search=Open&category=sans-serif" \
    -H "x-api-key: sm_your_api_key"
  ```
</CodeGroup>

<ParamField query="search" type="string">
  Part of a family name. Case does not matter, so `open` finds Open Sans.
</ParamField>

<ParamField query="category" type="string">
  One classification only. Possible values:

  * `sans-serif`
  * `serif`
  * `handwriting`
  * `display`
  * `monospace`
</ParamField>

<ParamField query="scope" type="string" default="all">
  Which fonts come back. Possible values:

  * `all`: the catalogue and your uploads
  * `system`: the catalogue alone
  * `custom`: your uploads alone
</ParamField>

`page` and `per_page` walk the result. See
[Pagination](/docs/api-reference/pagination).

## Upload your own font

Send one TTF or OTF per request, as the file itself or as a public link to it.

<CodeGroup>
  ```js Node.js {8-9} theme={"theme":{"light":"github-light","dark":"vesper"}}
  const response = await fetch("https://api.sudomock.com/api/v1/fonts", {
    method: "POST",
    headers: {
      "x-api-key": "sm_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      "url": "https://your-domain.com/fonts/MyBrand-Bold.ttf",
      "license_confirmed": true
    }),
  });

  const data = await response.json();
  console.log(data);
  ```

  ```php PHP {5-6} theme={"theme":{"light":"github-light","dark":"vesper"}}
  <?php

  $payload = <<<'JSON'
  {
    "url": "https://your-domain.com/fonts/MyBrand-Bold.ttf",
    "license_confirmed": true
  }
  JSON;

  $ch = curl_init("https://api.sudomock.com/api/v1/fonts");
  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
      "x-api-key: sm_your_api_key",
      "Content-Type: application/json",
  ]);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);

  $response = curl_exec($ch);
  curl_close($ch);

  echo $response;
  ```

  ```python Python {4-5} theme={"theme":{"light":"github-light","dark":"vesper"}}
  import requests

  payload = {
      "url": "https://your-domain.com/fonts/MyBrand-Bold.ttf",
      "license_confirmed": True,
  }

  response = requests.post(
      "https://api.sudomock.com/api/v1/fonts",
      headers={"x-api-key": "sm_your_api_key"},
      json=payload,
  )

  response.raise_for_status()
  print(response.json())
  ```

  ```ruby Ruby {11-12} theme={"theme":{"light":"github-light","dark":"vesper"}}
  require "net/http"
  require "uri"

  uri = URI("https://api.sudomock.com/api/v1/fonts")
  request = Net::HTTP::Post.new(uri)
  request["x-api-key"] = "sm_your_api_key"
  request["Content-Type"] = "application/json"

  request.body = <<~JSON
    {
      "url": "https://your-domain.com/fonts/MyBrand-Bold.ttf",
      "license_confirmed": true
    }
  JSON

  response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
    http.request(request)
  end

  puts response.body
  ```

  ```go Go {12-13} theme={"theme":{"light":"github-light","dark":"vesper"}}
  package main

  import (
  	"bytes"
  	"fmt"
  	"io"
  	"net/http"
  )

  func main() {
  	payload := []byte(`{
    "url": "https://your-domain.com/fonts/MyBrand-Bold.ttf",
    "license_confirmed": true
  }`)

  	req, err := http.NewRequest("POST", "https://api.sudomock.com/api/v1/fonts", bytes.NewBuffer(payload))
  	if err != nil {
  		panic(err)
  	}
  	req.Header.Set("x-api-key", "sm_your_api_key")
  	req.Header.Set("Content-Type", "application/json")

  	res, err := http.DefaultClient.Do(req)
  	if err != nil {
  		panic(err)
  	}
  	defer res.Body.Close()

  	body, _ := io.ReadAll(res.Body)
  	fmt.Println(string(body))
  }
  ```

  ```java Java {8-9} theme={"theme":{"light":"github-light","dark":"vesper"}}
  import java.net.URI;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;

  String payload = """
  {
    "url": "https://your-domain.com/fonts/MyBrand-Bold.ttf",
    "license_confirmed": true
  }
  """;

  HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create("https://api.sudomock.com/api/v1/fonts"))
      .header("x-api-key", "sm_your_api_key")
      .header("Content-Type", "application/json")
      .POST(HttpRequest.BodyPublishers.ofString(payload))
      .build();

  HttpResponse<String> response = HttpClient.newHttpClient()
      .send(request, HttpResponse.BodyHandlers.ofString());

  System.out.println(response.body());
  ```

  ```csharp .NET {6-7} theme={"theme":{"light":"github-light","dark":"vesper"}}
  using System.Net.Http;
  using System.Text;

  var payload = """
  {
    "url": "https://your-domain.com/fonts/MyBrand-Bold.ttf",
    "license_confirmed": true
  }
  """;

  var request = new HttpRequestMessage(HttpMethod.Post, "https://api.sudomock.com/api/v1/fonts");
  request.Headers.Add("x-api-key", "sm_your_api_key");
  request.Content = new StringContent(payload, Encoding.UTF8, "application/json");

  var client = new HttpClient();
  var response = await client.SendAsync(request);

  Console.WriteLine(await response.Content.ReadAsStringAsync());
  ```

  ```bash cURL {5-6} theme={"theme":{"light":"github-light","dark":"vesper"}}
  curl -X POST "https://api.sudomock.com/api/v1/fonts" \
    -H "x-api-key: sm_your_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "url": "https://your-domain.com/fonts/MyBrand-Bold.ttf",
      "license_confirmed": true
    }'
  ```

  ```bash cURL file upload {3-4} theme={"theme":{"light":"github-light","dark":"vesper"}}
  curl -X POST "https://api.sudomock.com/api/v1/fonts" \
    -H "x-api-key: sm_your_api_key" \
    -F "file=@MyBrand-Bold.ttf" \
    -F "license_confirmed=true"
  ```
</CodeGroup>

<ParamField body="file" type="file">
  The TTF or OTF file, sent as multipart form data. Send this or `url`.
</ParamField>

<ParamField body="url" type="string">
  A public link to a TTF or OTF file, sent in a JSON body. Send this or `file`.
</ParamField>

<ParamField body="license_confirmed" type="boolean" required>
  Confirmation that you hold the right to use and embed the font. Without it
  the upload comes back as a `422` reading
  `Confirm you have the right to use and embed this font.`
</ParamField>

<Info>
  Uploading is on the Pro and Scale plans, and every plan renders from the
  catalogue. Pro holds 10 custom fonts and Scale is unlimited.
</Info>

## Use a font in a render

Set `font` on a text layer override, to the `uuid` or the `postscript_name`.
Leave it out and the layer keeps the typeface the designer chose. The uuid is
the exact address, so prefer it when a name could match more than one font.

[Text layers](/docs/text/text-layers) carries the whole override, including the size
and colour you set alongside the font, and
[Render a PSD mockup](/docs/api-reference/psd-mockups/render-a-psd-mockup) carries
the request it belongs to.

## Response format

A font reads back as the same object from every endpoint that returns one. A
list wraps those objects in `data` alongside `pagination`, and an upload
returns the one it created, with `is_system` false.

```json Font object {2,5} theme={"theme":{"light":"github-light","dark":"vesper"}}
{
  "uuid": "9f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
  "family": "Open Sans",
  "subfamily": "Regular",
  "postscript_name": "OpenSans-Regular",
  "category": "sans-serif",
  "license": "OFL",
  "is_system": true,
  "created_at": "2026-07-13T00:00:00Z"
}
```

## Limitations

Uploading holds to a few fixed bounds:

* One file per upload, TTF or OTF, up to **5 MB**.
* Each weight is its own upload, so Regular, Medium and Bold is three uploads
  and three PostScript names.
* Catalogue fonts are read-only and cannot be deleted.
* Deleting your own is permanent. Update any template naming its uuid first.

## Troubleshooting

### A font you asked for is not available

A font you name explicitly never falls back. A uuid or PostScript name outside
your catalogue comes back as `422 FONT_NOT_FOUND`, so a brand typeface is never
silently swapped. Upload the file, or ask for one the catalogue lists.

### A name matches more than one font

The answer is `422 FONT_AMBIGUOUS` with a `candidates` list rather than a
choice made for you. Send one of those uuids as `font`.

### The template's own font is missing

Send no replacement and the layer renders in its original typeface, where that
is available. Where the file cannot be loaded, the render still succeeds in a
default font and carries a `TEXT_FONT_FALLBACK` warning. Read `font_available`
on each text layer of the upload response and you know which templates fall
back before you render one.

### The font lacks characters in your text

A font that is present but does not cover the replacement text carries a
`TEXT_FONT_MISSING_GLYPHS` warning. Pick a family that covers the script.

## API reference

* [Retrieve a list of fonts](/docs/api-reference/fonts/retrieve-a-list-of-fonts), with `search`, `category` and `scope`
* [Create a new font](/docs/api-reference/fonts/create-a-new-font), from a file or a link
* [Retrieve a single font](/docs/api-reference/fonts/retrieve-a-single-font), catalogue or your own
* [Remove an existing font](/docs/api-reference/fonts/remove-an-existing-font), answering `{ "success": true }`

<CardGroup cols={2}>
  <Card title="Text layers" icon="type" href="/docs/text/text-layers">
    Address a layer, override its wording, and read what renders.
  </Card>

  <Card title="Fonts in the dashboard" icon="layout-dashboard" href="/docs/dashboard/fonts">
    Browse the gallery and upload from the panel.
  </Card>
</CardGroup>
