Storeboard

Storeboard/Blog/Asset Library API

App Store Connect API: upload and place Asset Library assets

Developers 31 October 2026 · 10 min read

The Asset Library calls in order: GET the app's asset library, POST an image reservation, PUT the bytes, PATCH uploaded true, POST a placement and POST an ordering request

Version 4.5.1 of the App Store Connect API adds the Asset Library. Uploading a screenshot, header or search image is now: GET /v1/apps/{id}/assetLibrary, reserve with POST /v1/appAssetLibraryImages, upload the bytes to the returned uploadOperations, commit with PATCH and uploaded: true, then POST /v1/appAssetLibraryPlacements once per localization. Read sizes and device groups, including iPhone Duo's, from GET /v1/appAssetLibraryRefData. Apple has deprecated the old screenshot and preview set resources.

We built Storeboard's publishing of header and search results images and iPhone Duo screenshots on these endpoints in October 2026, because the older resources can't reach either. This guide is the reference we wanted: every call in order, with request bodies taken from Apple's OpenAPI specification 4.5.1 and Apple's App Asset Library documentation. For what the Asset Library is and how it looks in App Store Connect, start with the Asset Library, explained.

The flow at a glance

Upload once, place many times. Review happens with the surface each placement sits on.

Asset Library endpoints

CallWhat it does
GET /v1/apps/{id}/assetLibraryThe app's one library; keep its id
GET /v1/appAssetLibraryRefDataEvery spec, placement group and limit
GET /v1/appAssetLibraries/{id}/images, /videosList assets; filter by category, state, referenceName, specId, id; up to 200 a page
POST /v1/appAssetLibraryImages, /appAssetLibraryVideosReserve an upload
PATCH /v1/appAssetLibraryImages/{id} (or Videos)Commit (uploaded), rename (referenceName), archive (archived), poster frame (videos: previewFrameTimeCode)
DELETE /v1/appAssetLibraryImages/{id} (or Videos)Delete an asset with no placements
POST /v1/appAssetLibraryPlacementsPut an asset on one localization
GET / DELETE /v1/appAssetLibraryPlacements/{id}Read or remove one placement
GET /v1/appStoreVersionLocalizations/{id}/placementsA localization's placements (also on custom product page, In-App Event and test treatment localizations)
GET /v1/appAssetLibraryImages/{id}/placementsEverywhere one asset is used
POST /v1/appAssetLibraryPlacementOrderingRequestsSet display order in one group

Apple's documentation lists the Account Holder, Admin and App Manager roles for these calls, so generate your API key with one of them.

1. Find the app's asset library

GET /v1/apps/{appId}/assetLibrary

Each app has exactly one library and its id doesn't change, so read it once and keep it. Every asset you upload relates to it.

2. Read the reference data instead of hard-coding sizes

The reference data is one record with six arrays: features (limits per surface), placementProfileGroups (device groups, each with a platform and display class), imageSpecs, videoSpecs, placementTypes (which categories and specs each slot accepts, per group) and displayClasses. Ask for only what you need:

GET /v1/appAssetLibraryRefData?fields[appAssetLibraryRefData]=placementProfileGroups
GET /v1/appAssetLibraryRefData?filter[placementTypes]=APP_SCREENSHOT&filter[placementProfileGroups]={groupId}

Group identifiers are strings Apple can add to without an API change, such as IPHONE_DYNAMIC_ISLAND_LARGE_PROFILE or MAC_PROFILE in Apple's examples. To find iPhone Duo's groups, read placementProfileGroups and keep the ones whose displayClassId is IPHONE_DUO. Then read each group's specs: Storeboard does exactly this rather than guessing the Duo group names, and sends the open (2007 × 2853) or folded (1398 × 2034) export, or their landscape versions, to whichever group accepts that size.

Screenshot and preview specs are exact (minWidth equals maxWidth). The per-group limits live in features[].placementPolicies[].groupLimits[].maxCount; on a version Apple's documentation gives 10 screenshots, 3 app previews and 1 product page header per group.

3. Reserve the upload

POST /v1/appAssetLibraryImages
{
  "data": {
    "type": "appAssetLibraryImages",
    "attributes": {
      "fileName": "header-de-DE.png",
      "fileSize": 4812345,
      "category": "CREATIVE_ASSETS",
      "referenceName": "Header, German, autumn"
    },
    "relationships": {
      "assetLibrary": { "data": { "type": "appAssetLibraries", "id": "{libraryId}" } }
    }
  }
}

4. Upload the bytes and commit

For each upload operation, send bytes offset to offset + length with its method (usually PUT), url and requestHeaders. The URLs are pre-signed: don't send your API token to them. Large files come back as several parts, which can go in parallel. Then commit:

PATCH /v1/appAssetLibraryImages/{imageId}
{
  "data": {
    "type": "appAssetLibraryImages",
    "id": "{imageId}",
    "attributes": { "uploaded": true }
  }
}

There's no sourceFileChecksum any more: Apple checks the bytes against the fileSize you declared, and the commit fails if they differ. The asset moves to UPLOAD_COMPLETE while Apple processes it, then to PREPARE_FOR_SUBMISSION, or to FAILED with the reason in stateDetails. Poll GET /v1/appAssetLibraryImages/{id}. After processing, specId tells you which spec Apple matched your file to; check it's the one you meant, because it decides which groups accept the asset.

Videos

Same three steps with /v1/appAssetLibraryVideos. Two differences: you can send previewFrameTimeCode (Apple's example is "00:00:03:00") to pick the poster frame, now or later with PATCH, and video specs add frame rates, a duration range and whether audio is required. Apple only validates footage after upload, so a clip that's too short fails processing rather than being refused up front. For header and search results videos, Apple's specifications say 5 to 30 seconds at 30 or 60 fps.

5. Place the asset on each localization

A placement links one asset to one localization in one slot. This puts a header image on a version's German localization:

POST /v1/appAssetLibraryPlacements
{
  "data": {
    "type": "appAssetLibraryPlacements",
    "attributes": { "placementType": "PRODUCT_PAGE_HEADER_ASSET" },
    "relationships": {
      "image": { "data": { "type": "appAssetLibraryImages", "id": "{imageId}" } },
      "appStoreVersionLocalization": { "data": { "type": "appStoreVersionLocalizations", "id": "{localizationId}" } }
    }
  }
}

The same asset can back many placements, so a language-neutral image needs uploading only once. Read placements back with GET /v1/appStoreVersionLocalizations/{id}/placements?filter[placementType]=APP_SCREENSHOT&sort=placementGroupPosition&include=image: the sort gives display order, and there's no position attribute to read.

6. Order screenshots in each group

POST /v1/appAssetLibraryPlacementOrderingRequests
{
  "data": {
    "type": "appAssetLibraryPlacementOrderingRequests",
    "attributes": { "placementGroup": "{groupId}" },
    "relationships": {
      "orderedPlacements": { "data": [
        { "type": "appAssetLibraryPlacements", "id": "{first}" },
        { "type": "appAssetLibraryPlacements", "id": "{second}" }
      ] },
      "appStoreVersionLocalization": { "data": { "type": "appStoreVersionLocalizations", "id": "{localizationId}" } }
    }
  }
}

One request per group per localization, on a version, custom product page or test treatment. In-App Event slots hold one asset each, so they aren't ordered.

7. Submit for review

Placements go through App Review with the surface they sit on: submit the version, custom product page, test or In-App Event as usual. For a standalone asset, the 4.5.1 spec lets a reviewSubmissionItems entry relate to an appAssetLibraryImage or appAssetLibraryVideo. Apple's guides don't walk through that yet, and we haven't run it, so test it on one asset first. Apple's documentation doesn't describe an API equivalent of App Store Connect's Publish step for putting an approved asset on a live version.

Rename, archive and delete

Migrating from appScreenshotSets

4.5.1 deprecates App Screenshot Sets, App Screenshots, App Preview Sets, App Previews, App Event Screenshots and App Event Video Clips. Deprecated isn't removed, but those resources have no iPhone Duo display type and can't carry header or search results images. What changes when you move over:

Screenshot sets (deprecated)Asset Library
Create a set per display type, per languageNo sets: a placement carries its type and group
Display type is a fixed listGroups come from reference data at runtime
Commit with an MD5 sourceFileChecksumCommit with uploaded: true only
The same image uploaded once per languageUpload once, place per language
Order by patching the set's relationshipOrder with an ordering request
Deleting a set removes its screenshotsDelete placements first, then the asset

Migrate against a version in Prepare for Submission, since approved surfaces don't take new placements. A half-finished run is safe to resume: uploaded assets just sit unplaced until you place them.

Errors you'll meet

ErrorCause
409 ENTITY_ERROR.ATTRIBUTE.INVALID, "placementType and placementGroup combination is not supported"Type, group and asset category don't agree
409 STATE_ERROR.INVALID_STATE, "Creating a placement is not permitted…"The version or page is already approved
409 STATE_ERROR.INVALID_ASSET_STATE, "Only an approved asset can be archived."Archiving an unapproved asset
409 STATE_ERROR.ASSET_HAS_PLACEMENTSDeleting an asset that's still placed

The fixes, plus the stuck-in-processing and missing-slot cases, are in Asset Library errors and fixes.

Rather not write the upload code?

Storeboard 1.3, coming as an update, designs header, search results and iPhone Duo assets in every language and publishes them to the Asset Library with your own API key. Free to download, with an optional one-time Pro purchase.

Get Storeboard for Mac

FAQ

How do I upload screenshots with the App Store Connect API now?

Read the app's library with GET /v1/apps/{id}/assetLibrary, reserve the file with POST /v1/appAssetLibraryImages and category APP_SCREENSHOTS_AND_PREVIEWS, upload the bytes to the returned upload operations, commit with PATCH and uploaded true, then create a placement with placement type APP_SCREENSHOT, a placement group from the reference data and the version localization.

Are appScreenshotSets deprecated?

Yes. App Store Connect API 4.5.1 deprecates App Screenshot Sets, App Screenshots, App Preview Sets and App Previews, along with App Event Screenshots and App Event Video Clips, in favour of Asset Library images, videos and placements.

How do I upload iPhone Duo screenshots with the API?

Through the Asset Library. Read the reference data, take the placement groups whose display class is IPHONE_DUO, upload the screenshot as an APP_SCREENSHOTS_AND_PREVIEWS image, and place it with type APP_SCREENSHOT in that group. The deprecated screenshot sets have no Duo display type.

Do I still need an MD5 checksum to commit an upload?

No. Asset Library commits take uploaded set to true and nothing else. App Store Connect checks the bytes against the file size you declared when reserving.

Can I replace the image in an existing placement?

No. Placements can't be changed after they're created. Delete the placement, create a new one for the new asset, and reorder the group if position matters.

Keep reading