Skip to main content
The official SDKs handle authentication, retries and response parsing for you. Read SDKs before writing HTTP calls by hand.

Base URL

Every request goes to a single host.

Authentication

Every request carries an API key in the x-api-key header. Keys begin with sm_.
Authentication covers where to find your key and how to check it works.

Responses

Response bodies vary by endpoint. Use the response schema and examples in the endpoint reference, and check the documented error fields for that call. 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. Seam checks have a ceiling of their own, 30 new checks per minute per account, and a repeat check of the same image and crop does not count. Usage limits holds the concurrency numbers per plan, the seam check ceiling and the headers that report the 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. Video mockups and seam fixes are always queued and answer with a job_id. 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 maps the older spellings.

Frequently asked

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.
No. A webhook carries the finished render to you, so polling GET /api/v1/jobs/{job_id} is the fallback rather than the expected path.
No. A render that never produced an image is refunded to the balance it was drawn from.
Send an Idempotency-Key with is_async: true. Reuse that key only when retrying the same render; use a new key for a different request. A reused key can return the earlier job_id even if the body changes. Synchronous renders do not replay a previous job through this header.