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

# How to call the API server to server

> Where the key belongs and how a call behaves.

Every SudoMock endpoint is a server endpoint. Calls go to
`https://api.sudomock.com` and carry your key in the `x-api-key` header. Keys
begin with `sm_`.

## The key stays on your side

None of the endpoints are meant to be called from a browser. The key authorises
renders and spends credits, so a key that reaches a page bundle should be
treated as leaked and replaced from the dashboard. Put the call behind your own
route and read the key from your environment.

The one surface a browser touches is the embedded editor, and it does not use
your key either: your server opens a [Studio
session](/docs/api-reference/studio/create-a-new-studio-session) and the browser
receives a short lived token instead.

Issue one key per integration and name it after the thing that holds it, so a
leak costs you that integration rather than the rest of your business.
`GET /api/v1/me` is the cheapest way to prove a key is live, because it returns
the account behind the key, the plan and the credits left.
[Authentication](/docs/authentication) covers issuing and revoking.

## A call returns the image or a job

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

Queue the work whenever nobody is sitting in front of it. A queued render does
not hold a concurrency slot while it waits, which is what makes a large batch
practical: submit the whole set, then follow the jobs.

Artwork goes in as a public image URL or as base64, so a file already sitting
in your own storage needs no upload step first.

## Two ceilings, both answering 429

The sustained rate is 1,000 requests per minute. Separately, a per plan ceiling
counts how many renders run at once. Both answer with `429`, and `error.type`
tells them apart: a rate limit means slow down, a concurrency limit means wait
for work already in flight. Read `Retry-After` rather than guessing a delay.

Do not hardcode the parallel numbers. `GET /api/v1/packages/plans` returns
`max_concurrent_requests` and `max_concurrent_uploads` for the plan you are on.
Size your worker pool from those two fields and a `429` becomes something you
rarely meet. [Rate limits and concurrency
limits](/docs/api-reference/usage-limits) holds the headers that report both ceilings
on every response.

## Retries that do not cost twice

Send an `Idempotency-Key` on an upload. Reusing the same key with a different
body answers `409` rather than creating a second template.

A render that never produced an image is refunded to the balance it was drawn
from, so a failed call does not quietly cost credits. A `5xx` is ours and is
safe to retry with backoff. [Errors](/docs/errors) holds every `error_code` behind
the statuses and a retry loop you can copy.

## Start with an SDK

The official SDKs set the header from an environment variable and handle
retries and response parsing for you, so the parts above become configuration
rather than code you maintain. Read [SDKs](/docs/sdks) before writing HTTP calls by
hand, and [Quickstart](/docs/quickstart) for a first render end to end.


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