API reference
Use the Developer API to work with your App profiles and automate listing tasks. Find request fields, response formats and examples for each supported endpoint below.
Base URL: https://api.applistinglab.com/api/v1. Send your API key on every request — see Authentication. The OpenAPI specification is available at https://api.applistinglab.com/api/v1/developer/openapi.json. Existing /api/v1/public/v1 URLs remain compatibility aliases with the same API-key authentication. New integrations should use /api/v1/developer.
List App profiles
Returns the App profiles your account owns, most recently updated first, with their store links. Check this before importing: every successful import creates another profile. A locked profile is over your plan's open-project limit and refuses work with 402 until you delete a project or upgrade.
/developer/apps[
{
"appId": "665f0a2b9c1e4d0012ab34cd",
"name": "Your App",
"category": "Productivity",
"artworkUrl": "https://…/icon.png",
"iosUrl": "https://apps.apple.com/us/app/your-app/id1234567890",
"androidUrl": null,
"locked": false
}
]Create an App profile
Creates an App profile from your app's own details and returns an opaque appId. Send name and description — the main way in, and the only one for an app that is not released yet. For an app already in a store you can add its links to pull in the listing as a convenience; the fields you send always take priority. With name, an unreadable listing simply falls back to your details, and importedFrom lists the stores that were read. A link sent without name must open a published listing, otherwise 422 STORE_LISTING_UNAVAILABLE names the store and nothing is created. A malformed link returns 400 with the field's message.
/developer/apps| Field | Type | Description |
|---|---|---|
name | string | The app's name, max 100 characters. Required unless a store link is sent; always takes priority over the store's name. |
description | string | What the app does and who it is for, in your words. Captions and ASO text are written from it; takes priority over the store description. |
category | string | Store category, e.g. Health & Fitness. |
iosUrl | string | Optional, for an app already on the App Store: a link containing the app id, e.g. https://apps.apple.com/us/app/name/id1234567890. Keep the country path for an app not sold in the US. |
androidUrl | string | Optional, for an app already on Google Play: https://play.google.com/store/apps/details?id=<package>. |
extraContext | string | Optional context for the App profile, max 2000 characters. |
curl -s https://api.applistinglab.com/api/v1/developer/apps \
-H "Authorization: Bearer $APP_LISTING_LAB_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Your App","description":"What your app does and who it is for.","category":"Productivity"}'{
"appId": "665f0a2b9c1e4d0012ab34cd",
"name": "Your App",
"category": "Productivity",
"artworkUrl": "",
"iosUrl": null,
"androidUrl": null,
"importedFrom": []
}Read an App profile
Retrieve the imported profile summary using its appId. The response has the same fields as creation and is limited to your account. Invalid identifiers return 400; unavailable profiles return an error rather than revealing another account's data.
/developer/apps/{id}curl -s "https://api.applistinglab.com/api/v1/developer/apps/$APP_ID" \
-H "Authorization: Bearer $APP_LISTING_LAB_API_KEY"Discover screenshot sizes
Returns the supported device identifiers, store, pixel dimensions and maximum number of screenshots per set. Use these identifiers for the screenshot routes below. These read endpoints require the same generate key scope as App profile creation.
/developer/screenshots/devices| device | store | width × height | maxScreenshots | Orientation |
|---|---|---|---|---|
iphone-69 | apple | 1320 × 2868 | 10 | Portrait |
iphone-67 | apple | 1290 × 2796 | 10 | Portrait |
iphone-65 | apple | 1242 × 2688 | 10 | Portrait |
ipad-pro | apple | 2048 × 2732 | 10 | Portrait |
android-phone | 1080 × 1920 | 8 | Portrait | |
android-tablet | 1280 × 800 | 8 | Landscape | |
iphone-duo-outer | apple | 1398 × 2034 | 10 | Portrait |
iphone-duo-inner | apple | 2007 × 2853 | 10 | Portrait |
android-phone-landscape | 1920 × 1080 | 8 | Landscape | |
android-phone-tall | 1080 × 2160 | 8 | Portrait | |
android-tablet-10-portrait | 1440 × 2560 | 8 | Portrait | |
android-tablet-10-landscape | 2560 × 1440 | 8 | Landscape |
These are supported API export sizes, not a checklist of required store slots. Check the current Apple screenshot specifications and Google Play screenshot requirements before submission.
Duo sizes are PNG export canvases. AppListingLab does not currently map them to an App Store Connect upload slot. Generating a screenshot does not publish it to a store.
{
"device": "iphone-67",
"store": "apple",
"width": 1290,
"height": 2796,
"maxScreenshots": 10
}Owned source screenshots
Upload a sanitized PNG/JPEG/WebP capture with platform and dataUrl, then list opaque source IDs and measured dimensions. Source upload is distinct from paid rendering. See Sources & frame order for limits and Node.js input.
/developer/apps/{id}/screenshots/developer/apps/{id}/screenshotsFeature graphic
Send appId, discovered designId/designVersion, one or two owned Android sourceIds, headline, optional subtitle and altText. A finished job returns kind feature-graphic and one artifact. See Feature graphics for field limits and the 1024 × 500 output format.
/developer/feature-graphicsGoogle Play publishing
Requires a publish-scoped key and an eligible connected App profile. Create an immutable session, stage the complete manifest, start once, then poll the dedicated session and read back text. Publishing & verification documents all required fields, review policy, image slots and recovery.
/developer/publishing/google/sessions/developer/publishing/sessions/{id}/artifacts/developer/publishing/sessions/{id}/icon/developer/publishing/google/apps/{id}/icon/developer/publishing/sessions/{id}/start/developer/publishing/sessions/{id}/developer/publishing/google/apps/{id}/listingSuggest captions
Plans editable screenshot copy for an owned App profile without rendering images. The finished job returns one title/subtitle pair per screenshot to review before rendering.
/developer/screenshots/captions| Field | Type | Description |
|---|---|---|
appIdrequired | string | App id returned by POST /developer/apps. |
devicerequired | string | Target size: iphone-69 | iphone-67 | iphone-65 | ipad-pro | android-phone | android-tablet | iphone-duo-outer | iphone-duo-inner | android-phone-landscape | android-phone-tall | android-tablet-10-portrait | android-tablet-10-landscape. See GET /developer/screenshots/devices. |
countrequired | integer | Screenshots in the set, 1 up to the device's maxScreenshots (10 for Apple, 8 for Google Play). |
captionStyle | string | Writing style, default aso-expert: aso-expert | search-intent | outcome | emoji | direct | friendly | inspire | persuasive. |
captionLength | string | short (default) or long. |
Idempotency-Key | header | Optional but recommended for safe retries. Create and persist a new value once per paid stage, before the first submission. 16–128 characters of letters, digits, '.', '_', ':' or '-'. Reuse it with the unchanged body to recover the original operation without another charge; a different body under the same key returns 409. |
curl -s -X POST "https://api.applistinglab.com/api/v1/developer/screenshots/captions" \
-H "Authorization: Bearer $APP_LISTING_LAB_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $CAPTIONS_KEY" \
-d '{ "appId": "'"$APP_ID"'", "device": "iphone-67", "count": 5 }'{
"jobId": "66a1f0c2b7e4d90012cd5678",
"credits": { "cost": 5, "remaining": 195 }
}Render screenshots
Produces finished store PNGs. Send captions to render your own or reviewed copy and skip AI text planning; omit them to plan and render in one operation.
/developer/screenshots| Field | Type | Description |
|---|---|---|
appIdrequired | string | App id returned by POST /developer/apps. |
devicerequired | string | iphone-69 | iphone-67 | iphone-65 | ipad-pro | android-phone | android-tablet | iphone-duo-outer | iphone-duo-inner | android-phone-landscape | android-phone-tall | android-tablet-10-portrait | android-tablet-10-landscape |
count | integer | Required unless frames supplies the count. When both are sent, the values must match. |
frames | array | Ordered sourceId/title/subtitle bindings. The count is derived from this array. Cannot be combined with captions; see Sources & frame order. |
captions | array | Exactly count entries in display order, each { "title": string ≤ 100, "subtitle"?: string ≤ 160 }. A title must contain visible text; an empty subtitle means none. |
captionStyle | string | Used only when captions are omitted. Same values as for suggestions. |
captionLength | string | Used only when captions are omitted: short or long. |
designId | string | Optional public identifier from GET /developer/screenshots/designs; omitted means automatic recommendation. |
designVersion | integer | Optional opaque positive safe integer returned with designId. Requires designId; pins that current revision. |
Idempotency-Key | header | Optional but recommended for safe retries. Create and persist a new value once per paid stage, before the first submission. 16–128 characters of letters, digits, '.', '_', ':' or '-'. Reuse it with the unchanged body to recover the original operation without another charge; a different body under the same key returns 409. |
curl -s -X POST "https://api.applistinglab.com/api/v1/developer/screenshots" \
-H "Authorization: Bearer $APP_LISTING_LAB_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $RENDER_KEY" \
-d '{
"appId": "'"$APP_ID"'",
"device": "iphone-67",
"count": 2,
"captions": [
{ "title": "Plan meals in minutes", "subtitle": "Weekly menus that fit your diet" },
{ "title": "Shop smarter" }
]
}'Screenshot designs
GET /developer/screenshots/designs returns public IDs/current revisions, names, category/theme/features, supported device/count limits, text fields and illustrative raster previewUrls. It exposes no editor geometry. Always use returned values.
POST /developer/screenshots/prepare accepts the same body as rendering and returns { design, device, count }. It validates the owned profile and stored source compatibility without charging, AI calls, rendering or storage writes. It is optional, reserves nothing and does not verify remote bytes.
An unavailable design/revision returns 422 DESIGN_UNAVAILABLE; an incompatible device/count returns 422 DESIGN_INCOMPATIBLE, before charging. Accepted jobs pin the chosen revision; a retry recovers the original operation.
/developer/screenshots/designs/developer/screenshots/prepareDownload a screenshot
Each finished screenshot carries a downloadUrl pointing here. Download it with your account’s API key and the generate scope before downloadExpiresAt. Downloads have their own per-account rate and concurrency limits.
On the Free plan screenshots download with a “Made with applistinglab.com” mark and the header X-AppListingLab-Watermark: free-plan; paid plans and feature graphics download without the mark. After upgrading, download the screenshot again before its link expires to get an unmarked copy.
/developer/artifacts/{id}/filecurl -s -o screenshot-1.png "$DOWNLOAD_URL" \
-H "Authorization: Bearer $APP_LISTING_LAB_API_KEY"Generate a store listing
Writes the final en-US listing fields for one store from an owned App profile. The listing is also saved to the App profile in Studio.
/developer/aso| Field | Type | Description |
|---|---|---|
appIdrequired | string | Owned App profile identifier. |
storerequired | string | apple or google. |
campaignFocus | string | Optional focus for this listing, up to 1000 characters. |
Idempotency-Key | header | Optional but recommended for safe retries. Create and persist a new value once per paid stage, before the first submission. 16–128 characters of letters, digits, '.', '_', ':' or '-'. Reuse it with the unchanged body to recover the original operation without another charge; a different body under the same key returns 409. |
curl -s -X POST "https://api.applistinglab.com/api/v1/developer/aso" \
-H "Authorization: Bearer $APP_LISTING_LAB_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $ASO_KEY" \
-d '{ "appId": "'"$APP_ID"'", "store": "apple" }'Localize a store listing
Translates a completed en-US listing job into up to ten markets. Each target locale is charged as its own unit.
/developer/aso/localize| Field | Type | Description |
|---|---|---|
jobIdrequired | string | A finished POST /developer/aso job. |
targetLocalesrequired | string[] | 1–10 unique store locales other than en-US, for example de-DE, fr-FR, ja, pt-BR. The full supported list is the targetLocales item enum in this environment’s OpenAPI spec. |
Idempotency-Key | header | Optional but recommended for safe retries. Create and persist a new value once per paid stage, before the first submission. 16–128 characters of letters, digits, '.', '_', ':' or '-'. Reuse it with the unchanged body to recover the original operation without another charge; a different body under the same key returns 409. |
curl -s -X POST "https://api.applistinglab.com/api/v1/developer/aso/localize" \
-H "Authorization: Bearer $APP_LISTING_LAB_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $LOCALIZE_KEY" \
-d '{ "jobId": "'"$ASO_JOB_ID"'", "targetLocales": ["de-DE", "ja"] }'Retrieve an operation
Generation runs asynchronously: a submission answers with a jobId at once, and you poll this route every few seconds until status is done or error. pending covers accepted work that has not started yet, including time spent waiting for capacity; keep polling. Credits are charged when processing starts. Confirmed execution failures are compensated; an uncertain outcome may require support review before another submission.
/developer/jobs/{id}| Field | Type | Description |
|---|---|---|
id | string | The operation identifier. |
status | string | pending, running, done or error. |
result | object | null | The final output when status is done; its kind field names the shape below. |
error | string | null | A safe, human-readable failure message when status is error. |
curl -s "https://api.applistinglab.com/api/v1/developer/jobs/$JOB_ID" \
-H "Authorization: Bearer $APP_LISTING_LAB_API_KEY"{
"id": "66a1f0c2b7e4d90012cd5678",
"status": "done",
"result": {
"kind": "screenshot-captions",
"appId": "665f0a2b9c1e4d0012ab34cd",
"device": "iphone-67",
"count": 2,
"captions": [
{ "title": "Plan meals in minutes", "subtitle": "Weekly menus that fit your diet" },
{ "title": "Shop smarter", "subtitle": "One list for every store" }
]
},
"error": null
}{
"id": "66a1f3e0b7e4d90012cd9abc",
"status": "done",
"result": {
"kind": "screenshot-set",
"device": "iphone-67",
"screenshots": [
{
"artifactId": "66a1f41fb7e4d90012cdaa01",
"index": 0,
"device": "iphone-67",
"width": 1290,
"height": 2796,
"format": "png",
"fileName": "screenshot-1-1290x2796.png",
"downloadExpiresAt": "2026-10-16T12:00:00.000Z",
"downloadUrl": "https://api.applistinglab.com/api/v1/developer/artifacts/66a1f41fb7e4d90012cdaa01/file"
}
]
},
"error": null
}{
"id": "66a1f5d1b7e4d90012cdbb02",
"status": "done",
"result": {
"kind": "aso-listing",
"listingId": "66a1f5e9b7e4d90012cdbb10",
"appId": "665f0a2b9c1e4d0012ab34cd",
"locale": "en-US",
"store": "apple",
"fields": {
"name": "…",
"subtitle": "…",
"promotionalText": "…",
"keywords": "…",
"description": "…"
}
},
"error": null
}For google the fields are title, shortDescription and fullDescription. A localization finishes as aso-localization with sourceJobId and a listings array of listings in the same shape, one per target locale.
Refusals worth handling
402: the account cannot pay for the request, counting work it already has waiting. Nothing is charged.409: the same Idempotency-Key with a different body, or an original submission still being confirmed. For an in-progress submission, retry with the original key and body. For a body mismatch, restore the original body to recover it, or use a new key only if you intend a new paid operation.429: a per-account or per-key limit, including the number of waiting operations and hourly/daily generation allowances. HonourRetry-After.503: generation is paused or its queue is full. No credits are charged; retry afterRetry-After.
https://api.applistinglab.com/api/v1/developer/openapi.json. Use the specification to check required fields and response formats when building your integration.