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

# Pagination

> Walk long lists with offsets, cursors and page numbers.

List endpoints return one page at a time. Three patterns are in use. Pick the
one that matches the endpoint you are calling.

## Offset lists

`GET /api/v1/psd-mockups` and `GET /api/v1/photo-mockups` take `limit` and
`offset`. `limit` defaults to 20 and accepts up to 100.

<CodeGroup>
  ```js Node.js theme={"theme":{"light":"github-light","dark":"vesper"}}
  const response = await fetch("https://api.sudomock.com/api/v1/psd-mockups?limit=50&offset=50", {
    method: "GET",
    headers: { "x-api-key": "sm_your_api_key" },
  });

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

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

  $ch = curl_init("https://api.sudomock.com/api/v1/psd-mockups?limit=50&offset=50");
  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 theme={"theme":{"light":"github-light","dark":"vesper"}}
  import requests

  response = requests.get(
      "https://api.sudomock.com/api/v1/psd-mockups?limit=50&offset=50",
      headers={"x-api-key": "sm_your_api_key"},
  )

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

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

  uri = URI("https://api.sudomock.com/api/v1/psd-mockups?limit=50&offset=50")
  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 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/psd-mockups?limit=50&offset=50", 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 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/psd-mockups?limit=50&offset=50"))
      .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 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/psd-mockups?limit=50&offset=50");
  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 theme={"theme":{"light":"github-light","dark":"vesper"}}
  curl -X GET "https://api.sudomock.com/api/v1/psd-mockups?limit=50&offset=50" \
    -H "x-api-key: sm_your_api_key"
  ```
</CodeGroup>

The two endpoints report the same three counters in different places. PSD
mockups keep them inside `data`, photo mockups keep them at the top level.

<CodeGroup>
  ```json PSD mockups theme={"theme":{"light":"github-light","dark":"vesper"}}
  {
    "success": true,
    "data": {
      "mockups": [],
      "total": 312,
      "limit": 50,
      "offset": 50
    }
  }
  ```

  ```json Photo mockups theme={"theme":{"light":"github-light","dark":"vesper"}}
  {
    "success": true,
    "data": [],
    "total": 84,
    "limit": 50,
    "offset": 50
  }
  ```
</CodeGroup>

Keep requesting while `offset + limit < total`.

## Cursor lists

Two endpoint families use a cursor, and they hand the next one back in
different places.

`GET /api/v1/webhook-endpoints/events` and
`GET /api/v1/webhook-endpoints/{endpoint_id}/deliveries` take `cursor` and
`limit`, up to 200 per page. The next cursor arrives in the
`X-Webhook-Next-Cursor` response header and is absent on the last page.
[Webhooks](/docs/webhooks/overview) shows that loop in context.

`GET /api/v1/jobs` takes `cursor` and `limit`, up to 50 per page. Its next
cursor arrives in the response body as `next_cursor`, and it is `null` on the
last page.

```js theme={"theme":{"light":"github-light","dark":"vesper"}}
let cursor = null
const base = "https://api.sudomock.com/api/v1/jobs"

do {
  const url = new URL(base)
  url.searchParams.set("limit", "50")
  if (cursor) url.searchParams.set("cursor", cursor)

  const response = await fetch(url, {
    headers: { "x-api-key": key },
  })
  const body = await response.json()
  handle(body.jobs)

  cursor = body.next_cursor
} while (cursor)
```

<Note>
  A cursor is opaque. Store it as an unparsed string and send it
  back unchanged.
</Note>

## Numbered lists

`GET /api/v1/fonts` takes `page` and `per_page`. `page` starts at 1, `per_page`
defaults to 50 and accepts up to 100. The counters come back under
`pagination`.

```json theme={"theme":{"light":"github-light","dark":"vesper"}}
{
  "success": true,
  "data": [],
  "pagination": { "page": 1, "per_page": 50, "total": 1284 }
}
```

The last page is the one where `page * per_page >= total`.
[Fonts](/docs/text/fonts) covers the catalogue filters.

## Which endpoint uses which

| Pattern  | Parameters         | Next page                      | Endpoints                          |
| -------- | ------------------ | ------------------------------ | ---------------------------------- |
| Offset   | `limit`, `offset`  | `offset + limit`               | PSD mockups, photo mockups         |
| Cursor   | `limit`, `cursor`  | `X-Webhook-Next-Cursor` header | Webhook events, webhook deliveries |
| Cursor   | `limit`, `cursor`  | `next_cursor` in the body      | Jobs                               |
| Numbered | `page`, `per_page` | `page + 1`                     | Fonts                              |
