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

# Introduction

> Base URL, authentication, async renders and versioning.

<Info>
  The official SDKs handle authentication, retries and response parsing for
  you. Read [SDKs](/docs/sdks) before writing HTTP calls by hand.
</Info>

## Base URL

Every request goes to a single host.

```
https://api.sudomock.com
```

## Authentication

Every request carries an API key in the `x-api-key` header. Keys begin with
`sm_`.

<CodeGroup>
  ```js Node.js theme={"theme":{"light":"github-light","dark":"vesper"}}
  const response = await fetch("https://api.sudomock.com/api/v1/me", {
    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/me");
  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/me",
      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/me")
  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/me", 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/me"))
      .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/me");
  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/me" \
    -H "x-api-key: sm_your_api_key"
  ```
</CodeGroup>

[Authentication](/docs/authentication) covers where to find your key and how to
check it works.

## Responses

A successful response carries `success: true` and a `data` object. A failure
carries the same envelope on every endpoint, so you branch on `error_code`
once rather than per endpoint.

| Status | Meaning                                                                |
| ------ | ---------------------------------------------------------------------- |
| `200`  | Request succeeded.                                                     |
| `201`  | Resource created.                                                      |
| `202`  | Work accepted and queued. Poll the job or wait for the webhook.        |
| `400`  | Check the request format and the fields you sent.                      |
| `401`  | The key is missing, malformed or revoked.                              |
| `402`  | The request cannot be paid for. Read `error_code` for the case.        |
| `403`  | Not available with this credential, or an account ceiling was reached. |
| `404`  | Resource not found. Check the identifier you passed.                   |
| `422`  | Body validation failed. Fix the input before retrying.                 |
| `429`  | Rate limit or concurrency limit. Read `Retry-After`.                   |
| `5xx`  | Our side. Safe to retry with backoff.                                  |

[Errors](/docs/errors) holds every `error_code` behind these statuses and a retry
loop you can copy.

## Rate limits

The sustained rate is 1,000 requests per minute, and a separate ceiling counts
how many renders run at once. Both answer with a `429`, and `error.type` tells
them apart: slow down, or wait for work already in flight.

[Usage limits](/docs/api-reference/usage-limits) holds the concurrency numbers per
plan and the headers that report both ceilings on every response.

## Synchronous and asynchronous

A render returns the finished image at `data.print_files[0].export_path`. Send
`is_async: true` and the same call returns a `job_id` instead, which you poll
at `GET /api/v1/jobs/{job_id}` or receive over a
[webhook](/docs/webhooks/overview).

[Pagination](/docs/api-reference/pagination) covers how the list endpoints hand back the
next page.

## Versioning

The API is versioned in the path, and `v1` is current. Paths that carried an
earlier name still answer under it and are marked `deprecated` in the spec.
[Legacy paths](/docs/changes/legacy-paths) maps the older spellings.

## Frequently asked

<AccordionGroup>
  <Accordion title="Which endpoints can I call from a browser?">
    None of them. A key with the `sm_` prefix is a server credential, and a
    key that reaches a browser bundle should be treated as leaked. Put the
    call behind your own route and keep the key on the server.
  </Accordion>

  <Accordion title="Do I have to poll for an async render?">
    No. A [webhook](/docs/webhooks/overview) carries the finished render to you, so
    polling `GET /api/v1/jobs/{job_id}` is the fallback rather than the
    expected path.
  </Accordion>

  <Accordion title="Does a failed render cost credits?">
    No. A render that never produced an image is refunded to the balance it
    was drawn from.
  </Accordion>

  <Accordion title="How do I keep a retry from rendering twice?">
    Send an `Idempotency-Key` on the upload. Reusing the same key with a
    different body answers `409` rather than creating a second template.
  </Accordion>
</AccordionGroup>
