api · for builders

Ship store
screenshots from CI.

One HTTPS endpoint. Multipart upload, JSON status poll, signed zip download. No SDK lock-in. Drop it into a GitHub Action, a Fastlane lane, or a cron — every release ships with fresh, multilingual store assets.

~ ship.sh — appscreencurljspyruby
# 1. POST your screenshots
curl https://api.appscreen.co/v1/render \
  -H "X-API-Key: $APPSCREEN_KEY" \
  -F 'theme=paper' \
  -F 'sizes=["ios-6.9","ios-6.7","pixel-6"]' \
  -F 'langs=["en","de","tr"]' \
  -F 'screens=@./01.png' \
  -F 'screens=@./02.png'
01 post02 queued03 poll04 done05 zip
AUTH
One header, one key
Send X-API-Key. Plaintext shown once at create time, sha256 at rest. Revoke instantly from the dashboard — no token refresh, no OAuth dance.
QUEUE
FIFO queue, no 409s
Hammer the endpoint from a matrix build. Submissions are persisted, the worker pulls them in order. Polling shows progress; the submitter never blocks.
IDEMPOTENCY
Safe retries
Pass Idempotency-Key once and the same job comes back on every retry within 24 hours. Survives flaky CI runners without double-billing render time.
I18N
Up to 15 locales / call
Send per-locale captions in one request and the renderer fans them out across iOS 6.9 / 6.7 / 6.5 / Play. Output zip is fastlane-shaped on demand.
TRANSLATE
Auto-translate, self-hosted
POST /v1/translate to fan source copy into every locale you ship. Backed by our own LibreTranslate instance — no third-party MT, no data hand-off. Pro only.
WEBHOOKS
Render-completed callbacks
Subscribe once. We POST when the zip is ready. Same shape as Stripe events — verifiable HMAC signatures, replayable from the dashboard.
two minutes from key to zip

curl it, or wire a lane.

~ render.sh
# 1. POST your shots
curl https://api.appscreen.co/v1/render \
  -H "X-API-Key: $APPSCREEN_KEY" \
  -F 'theme=paper' \
  -F 'sizes=["ios-6.9"]' \
  -F 'langs=["en","de","tr"]' \
  -F 'screens=@./shot1.png' \
  -F 'screens=@./shot2.png'
# → { "jobId": "…", "status": "queued" }

# 2. Poll until done
curl https://api.appscreen.co/v1/render/$JOB \
  -H "X-API-Key: $APPSCREEN_KEY"
# → { "status": "done", "downloadUrl": "…" }

# 3. Pull the zip
curl -o screens.zip "$DOWNLOAD_URL"
~ Fastfile
# Fastfile
lane :appscreen do
  job = sh(%(
    curl -fsS https://api.appscreen.co/v1/render \
      -H "X-API-Key: $APPSCREEN_KEY" \
      -F 'theme=paper' \
      -F 'sizes=["ios-6.9","ios-6.7"]' \
      -F 'langs=["en","de","tr"]' \
      -F 'screens=@fastlane/screenshots/shot1.png' \
      -F 'screens=@fastlane/screenshots/shot2.png'
  )).strip
  job_id = JSON.parse(job).fetch("jobId")

  loop do
    sleep 5
    res = JSON.parse(sh("curl -fsS https://api.appscreen.co/v1/render/#{job_id} -H 'X-API-Key: $APPSCREEN_KEY'"))
    break if res["status"] == "done"
    UI.user_error!(res["error"]) if res["status"] == "failed"
  end

  sh("curl -fsSL -o fastlane/appscreen.zip '#{res["downloadUrl"]}' && unzip -o fastlane/appscreen.zip -d fastlane/screenshots")
  deliver(skip_metadata: true, skip_app_version_update: true)
end
drop into a fastlane lane

Bundle matches deliver and supply.

Locale and device folders, no reshuffle. Drop the unzipped tree into fastlane/screenshots and your existing lanes ship it.

fastlane/screenshots/
├─en-US/
│ ├─iPhone_6.9/
│ │ ├─01_overview.png
│ │ ├─02_pricing.png
│ │ └─03_share.png
│ ├─iPhone_6.7/
│ └─Pixel_6.5/
├─de-DE/
│ └─
└─tr-TR/
└─
limits
200 screens / job30 requests / minute / key10 MB / file
500 renders / month (Pro)20 min server-side timeout1 hr download URL TTL
Need higher caps, outbound webhooks, or per-render billing?hello@appscreen.co →