docs · api
Programmatic renders.
POST your screens, poll the job, download the zip. The API is HTTPS-only, authenticated with an X-API-Key header, and limited to Pro accounts. Free of vendor SDKs — anything that speaks HTTP works.
Quick start
1. Generate a key at /account/keys. Copy the ask_live_… string — you only see it once.
2. POST your PNGs as multipart/form-data:
curl https://api.appscreen.co/v1/render \
-H "X-API-Key: $APPSCREEN_KEY" \
-F 'theme=paper' \
-F 'sizes=["ios-6.9"]' \
-F 'langs=["en"]' \
-F 'captions=[{"texts":{"Headline":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Find people who share your taste."}]}]}}}]' \
-F 'fields=[{"id":"Headline","label":"Headline"}]' \
-F 'screens=@./shot1.png' \
-F 'screens=@./shot2.png'3. Poll the returned jobId until status === "done":
curl https://api.appscreen.co/v1/render/$JOB \ -H "X-API-Key: $APPSCREEN_KEY"
4. GET the downloadUrl within 1 hour of the poll response — it's an HMAC-signed link served by AppScreen directly.
Authentication
Send your key as X-API-Key, or as Authorization: Bearer ask_live_… if your client only supports Bearer. Keys are per-account, never scoped to a single project.
Lost a key? Revoke it from /account/keys and create a new one. Revocation is immediate.
POST /v1/render
multipart/form-data with the following fields:
| screens | file[] | PNG screenshots, max 200 files × 10 MB. |
| theme | string | flat | paper | frame | card | glass | mesh | image |
| sizes | json string | JSON array, e.g. '["ios-6.9","play"]'. Allowed: ios-6.9, ios-6.7, ios-6.5, play. |
| langs | json string | JSON array of locale codes, e.g. '["en","de","tr"]'. Up to 15. |
| captions | json string | Per-screen caption objects. See the captions schema below. |
| fields | json string | Optional caption field defs (id, label). |
| layout | string | default | fastlane | flutter | react-native | capacitor | kmm |
| rounded | boolean | Marketing-asset mode (rounded canvas, alpha). Cannot combine with fastlane layouts. |
Returns 202 Accepted with a job id:
{
"jobId": "8c1c…-uuid",
"status": "queued",
"totalSteps": 4,
"doneSteps": 0,
"pollUrl": "/v1/render/8c1c…"
}GET /v1/render/:jobId
Returns current job state. Poll every 2–5 s until status is done or failed. The signed downloadUrl is regenerated on every successful poll and expires in 1 hour.
{
"jobId": "8c1c…",
"status": "done",
"doneSteps": 4,
"totalSteps": 4,
"downloadUrl": "https://api.appscreen.co/r/abc?exp=…&sig=…",
"error": null
}Idempotency
Pass a Idempotency-Key header (any string up to 200 chars). Retries with the same key within 24h return the original job — safe to retry network failures without re-paying render cost.
Limits & errors
| screens / job | 200 |
| renders / month | 500 (Pro) |
| request rate | 30 / min per key |
| max upload | 200 files × 10 MB |
| job timeout | 20 min (server-side) |
Common error shapes:
| 401 | missing or revoked api key |
| 402 | free plan, monthly cap reached, or size/lang outside Pro tier |
| 413 | captions payload exceeds the per-screen size cap |
| 429 | per-key rate limit; retry after Retry-After seconds |
TypeScript SDK
A minimal TS client lives in the sdk/ directory of the repo. It wraps the multipart upload and polling loop:
import { Appscreen } from "./sdk";
const client = new Appscreen({ apiKey: process.env.APPSCREEN_KEY! });
const job = await client.render({
theme: "paper",
sizes: ["ios-6.9"],
langs: ["en"],
fields: [{ id: "Headline", label: "Headline" }],
captions: [
{ texts: { Headline: docFromText("Find people who share your taste.") } },
],
screens: [
{ name: "shot1.png", data: await readFile("./shot1.png") },
],
});
const done = await client.waitForCompletion(job.jobId);
console.log(done.downloadUrl);