Back to Browse

Appstoreconnect MCP Server

Developer ToolsLow Risk10.0MCP RegistryLocal
Free

Server data from the Official MCP Registry

App Store Connect for MCP clients: PPP pricing, subscriptions, TestFlight, reviews, reports & more

About

App Store Connect for MCP clients: PPP pricing, subscriptions, TestFlight, reviews, reports & more

Security Report

10.0
Low Risk10.0Low Risk

Valid MCP server (1 strong, 1 medium validity signals). No known CVEs in dependencies. Package registry verified. Imported from the Official MCP Registry.

4 files analyzed · 1 issue found

Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.

What You'll Need

Set these up before or after installing:

App Store Connect API issuer UUID (Users and Access > Integrations > Keys).Optional

Environment variable: ASC_ISSUER_ID

10-character App Store Connect API key ID.Optional

Environment variable: ASC_KEY_ID

Path to the downloaded .p8 private key file (~ is expanded).Optional

Environment variable: ASC_PRIVATE_KEY_PATH

Optional. Account-level vendor number for the sales/finance report tools.Optional

Environment variable: ASC_VENDOR_NUMBER

How to Install

Add this to your MCP configuration file:

{
  "mcpServers": {
    "io-github-akoskomuves-appstoreconnect-mcp": {
      "env": {
        "ASC_KEY_ID": "your-asc-key-id-here",
        "ASC_ISSUER_ID": "your-asc-issuer-id-here",
        "ASC_VENDOR_NUMBER": "your-asc-vendor-number-here",
        "ASC_PRIVATE_KEY_PATH": "your-asc-private-key-path-here"
      },
      "args": [
        "-y",
        "@akoskomuves/appstoreconnect-mcp"
      ],
      "command": "npx"
    }
  }
}

Documentation

View on GitHub

From the project's GitHub README.

appstoreconnect-mcp

npm CI License: MIT

A Model Context Protocol server for the Apple App Store Connect API. Drives apps, subscriptions, pricing, and more from any MCP-compatible client (Claude Code, Claude Desktop, Cursor, Windsurf).

The first published surface is subscription pricing — including a Purchasing Power Parity rebalance flow that's already been used to schedule 120 production price changes across 65 territories on a real iOS app. New ASC domains (TestFlight, sales, screenshots, IAPs) are designed to plug in one file at a time; see Roadmap.

Install (zero-config)

npx @akoskomuves/appstoreconnect-mcp init

The wizard:

  1. Opens App Store Connect → Keys so you can download a .p8 (skipped if you already have one).
  2. Copies the key to ~/.appstore/ with chmod 600.
  3. Asks for your Issuer ID and (auto-detected) Key ID.
  4. Verifies auth with a real API call before writing anything.
  5. Detects which MCP clients you have installed — Claude Code, Claude Desktop, Cursor, Windsurf — and registers itself in the ones you pick.

When something looks off later, run a read-only diagnostic:

npx @akoskomuves/appstoreconnect-mcp doctor

Manual install

If you'd rather wire it up by hand, add to ~/.claude.json (Claude Code), claude_desktop_config.json (Claude Desktop), or your client's equivalent:

{
  "mcpServers": {
    "appstoreconnect": {
      "command": "npx",
      "args": ["-y", "@akoskomuves/appstoreconnect-mcp"],
      "env": {
        "ASC_ISSUER_ID": "...",
        "ASC_KEY_ID": "...",
        "ASC_PRIVATE_KEY_PATH": "~/.appstore/AuthKey_XXXXXXXXXX.p8"
      }
    }
  }
}

Or via Claude Code's CLI:

claude mcp add appstoreconnect \
  -e ASC_ISSUER_ID=... \
  -e ASC_KEY_ID=... \
  -e ASC_PRIVATE_KEY_PATH=~/.appstore/AuthKey_XXXXXXXXXX.p8 \
  -- npx -y @akoskomuves/appstoreconnect-mcp

Configure

Generate an App Store Connect API key at App Store Connect → Users and Access → Integrations → Keys. Pricing writes need the Admin role; read-only operations work with App Manager.

VariableWhat
ASC_ISSUER_IDIssuer UUID from the Keys page
ASC_KEY_ID10-character Key ID
ASC_PRIVATE_KEY_PATHPath to your downloaded AuthKey_XXXXXXXXXX.p8 file (~ is expanded)

The .p8 file is a private key — never commit it. Recommended: ~/.appstore/AuthKey_XXXXXXXXXX.p8 outside any repo.

Optional: In-App Purchase signing key

Only needed for the asc_sign_* tools (subscription offer redemption signing). Issue a second key at App Store Connect → Users and Access → Integrations → In-App Purchase — this is a separate key from the ASC API key above, generated on a different tab of the same page.

VariableWhat
ASC_IAP_ISSUER_IDIssuer UUID from the In-App Purchase keys tab (different from ASC_ISSUER_ID)
ASC_IAP_KEY_ID10-character Key ID for the IAP key
ASC_IAP_PRIVATE_KEY_PATHPath to the IAP signing .p8 (~ is expanded)

The server starts fine without these — only the asc_sign_* tools refuse with a setup message if they're missing. Set one or two but not all three and the server rejects with a clear error. Run appstoreconnect-mcp doctor to verify the key loads as a valid ES256 PKCS#8.

Optional: vendor number (sales + finance reports)

Only used by asc_get_sales_report / asc_get_finance_report. Your vendor number is account-level, shown at App Store Connect → Payments and Financial Reports next to your team name (a numeric string like 85123456).

VariableWhat
ASC_VENDOR_NUMBERDefault vendor number for sales/finance report downloads

Without it the two report tools still work — they just need vendorNumber passed per call (and their error message tells you where to find it). Note: downloading sales/finance reports requires an API key with the Admin, Finance, or Sales role.

Tools

Apps

  • asc_list_apps — list apps (filter by bundleId)
  • asc_get_app — fetch one app by ID

Subscriptions

  • asc_list_subscription_groups — groups for an app
  • asc_get_subscription_group — fetch one group by ID
  • asc_list_subscriptions — auto-renewable subscriptions in a group
  • asc_get_subscription — fetch one subscription by ID
  • asc_list_subscription_prices — current price schedule per subscription. One row per territory (~175 unfiltered) — pass territoryId to narrow to one market
  • asc_list_subscription_price_points — valid price points for a subscription in a territory. Pass nearAmount to narrow the response to the nearest tiers around a target price.

Subscription products (writes)

Creating the hierarchy itself — the step that used to send you to the App Store Connect web UI. Four names, only two of which customers ever see:

ResourceAttributeWho sees it
SubscriptionGroupreferenceNameinternal only
SubscriptionGroupLocalizationnamecustomer — heading above the plan choices
Subscriptionnameinternal only
SubscriptionLocalizationnamecustomer — the individual plan
  • asc_post_subscription_group — create the container every subscription must live in. A customer can hold only one active subscription per group, so mutually exclusive plans (Monthly vs Yearly) belong in the same group
  • asc_patch_subscription_group — rename (referenceName is the only mutable attribute; groups cannot move between apps)
  • asc_delete_subscription_group — lists the group's subscriptions first and refuses client-side naming the specific products that block the delete, instead of letting Apple return a bare 409
  • asc_post_subscription — create an auto-renewable subscription. productId is permanent: it cannot be changed, and Apple never lets it be reused on the account — not even after the subscription is deleted. subscriptionPeriod is optional at create but required before submission; the new product starts in MISSING_METADATA and the success message lists the remaining steps
  • asc_patch_subscription — name, subscriptionPeriod, familySharable, reviewNote, groupLevel. productId has no codepath here by construction. Nested offer/price arrays are deliberately unsupported — their wire semantic is replace, so a caller passing one offer would silently delete the rest; use the dedicated offer and price tools
  • asc_delete_subscription — pre-checks state and refuses for products under review or ever approved, pointing at asc_post_subscription_availability as the way to stop selling a live product

Subscription group localizations

The customer-facing group heading — what the App Store renders above the plan choices, and what shows in Settings → Subscriptions. A group with no localizations cannot be submitted.

  • asc_list_subscription_group_localizations / asc_get_subscription_group_localization
  • asc_post_subscription_group_localization — name + locale, plus optional customAppName (overrides how the app name reads inside the subscription sheet; usually omit). Wire gotcha handled: the parent relationship key is subscriptionGroup, while Subscription calls the same parent group
  • asc_patch_subscription_group_localization — name / customAppName; locale is the immutable lookup key
  • asc_delete_subscription_group_localization

Subscription pricing (writes)

  • asc_post_subscription_price — set the price for one territory, either the opening price or a scheduled change. Order matters, and both steps are confirmed live: territory availability → undated baseline → dated changes.
    • Omit startDate for a subscription's first price in a territory. The opening row is the undated baseline; a dated first price is a price change with nothing to change from. Apple says so outright — "Invalid startDate. Create a starting price before creating future prices." — and distance doesn't help (1, 8 and 29 days out all 409).
    • Availability must exist first. Without it even a correctly shaped undated POST fails, with a 409 that blames the price point (ENTITY_ERROR.RELATIONSHIP.INVALID → /data/relationships/subscriptionPricePoint/id). The price point is fine; Apple just can't price a territory the product isn't sold in. The tool translates both of these rather than passing the raw 409 through.
    • preserveCurrentPrice defaults to true on a dated change and is omitted on a baseline, where there's no existing cohort to grandfather. The created row reads preserved: false until a newer price supersedes it; that is expected, not a grandfathering failure
  • asc_delete_subscription_price — cancel a pending scheduled change

App pricing (paid non-subscription apps)

  • asc_list_app_prices — current price schedule for an app, splitting manual overrides from auto-derived prices and surfacing the base territory
  • asc_list_app_price_points — valid Apple price tiers for an app in a given territory (~600+ tiers per territory). Pass nearAmount (target price) and optional nearCount (default 10) to narrow the response to the nearest tiers — Apple does not support a near-amount filter server-side, so the full list is still paginated but only the nearest tiers are surfaced.
  • asc_post_app_price_schedule — replace the entire price schedule (whole-schedule replace, NOT a merge — matches Apple's API). Pre-flight refuses unless at least one entry targets the base territory with no startDate, and requires explicit acknowledgeReplacesAll: true. A separate acknowledgeDeletesScheduledIfBaseChanges ack is required when changing the base territory (Apple wipes pending scheduled changes on base-change). Apps have no grandfather mechanism — new schedules activate atomically at each entry's startDate.

In-app purchases (consumables, non-consumables, non-renewing subs)

  • asc_list_iaps — list IAPs for an app (v2 surface only — auto-renewable subscriptions are covered by the Subscriptions tools above). Filterable by inAppPurchaseType and state. If this returns zero rows for an app you know has IAPs, the IAPs may be legacy-only and need to be migrated in the App Store Connect web UI before they appear here.
  • asc_get_iap — fetch a single IAP by ID.
  • asc_list_iap_prices — current price schedule for an IAP (same shape as app prices: manual overrides + auto-derived + base territory).
  • asc_list_iap_price_points — valid Apple price tiers for an IAP in a given territory. Same nearAmount / nearCount narrowing as the app and subscription price-point tools.
  • asc_post_iap_price_schedule — replace the entire IAP price schedule (same whole-schedule replace semantics as asc_post_app_price_schedule: acknowledgeReplacesAll: true, base-territory entry with no startDate, base-change ack required). No grandfather mechanism — same as apps.
  • asc_post_iap — create a consumable, non-consumable or non-renewing-subscription IAP. productId is permanent and never reusable on the account, even after a delete. The new IAP starts in MISSING_METADATA; the success message lists the remaining steps
  • asc_patch_iap — name (internal), reviewNote, familySharable; pass null to clear. productId and inAppPurchaseType are immutable and never sent
  • asc_delete_iap — pre-checks state and refuses for IAPs under review or ever approved, pointing at asc_post_iap_availability to stop selling a live one; force: true skips the check

Version-scoped IAP & subscription content (/v2)

API 4.x adds /v2 copies of the IAP, subscription and group localization endpoints and the two promotional-image endpoints. Same resources and attributes as /v1, but they attach to a version of the product (relationship version) rather than the product itself. /v1 is not deprecated, so the existing localization and image tools stay on it; these are additive. Get the version id from the product's versions list.

  • Localizations: asc_{post,get,patch,delete}_{iap,subscription,subscription_group}_version_localization
  • Images: asc_{upload,post,patch,get,delete}_{iap,subscription}_version_image — the v2 commit takes uploaded only (no sourceFileChecksum)

In-app product versions (IAPs, subscriptions, subscription groups)

Since API 4.4.1 every in-app product has two layers. The product (inAppPurchases, subscriptions, subscriptionGroups) holds identity and commerce: product ID, type, prices, availability, offers. The tools above work on it. Its versions (inAppPurchaseVersions, subscriptionVersions, subscriptionGroupVersions) hold the customer-facing metadata App Review approves: localizations and, for IAPs and subscriptions, images. Each version has a number and a state (PREPARE_FOR_SUBMISSION … APPROVED, then REPLACED_WITH_NEW_VERSION once a newer one is approved). To change approved metadata you create a version, edit it, and submit the version through a review submission. Apple deprecated the product-scoped v1 localization / image endpoints and the standalone IAP / subscription submissions in favour of this model.

  • asc_list_{iap,subscription,subscription_group}_versions — versions of one product, newest first, with state and localization count; filter by state
  • asc_get_*_version — one version with its product, localizations and images included
  • asc_post_*_version — create a new version (relationships-only body). Versions have no PATCH or DELETE, so it refuses while the product already has a PREPARE_FOR_SUBMISSION draft and names it. dryRun prints the body and the existing versions
  • asc_list_*_version_localizations — the version-scoped localizations (these carry no state, unlike the v1 ones)
  • asc_list_{iap,subscription}_version_images / asc_get_{iap,subscription}_version_primary_image — the version's images (to-many) and its to-one image

In-app purchase offer codes

Offer codes for consumables, non-consumables and non-renewing subscriptions (API 4.2). They work like the subscription offer codes, with a campaign → one-time-use batches / custom codes hierarchy, and with simpler campaigns: just a name, customer eligibility (NON_SPENDER, ACTIVE_SPENDER, CHURNED_SPENDER) and a price per territory (IAP price points). Nothing can be deleted; PATCH only flips active.

  • asc_list_iap_offer_codes · asc_get_iap_offer_code · asc_list_iap_offer_code_prices
  • asc_post_iap_offer_code — one POST with every territory price inline. Pre-flights a 10-campaign cap and name uniqueness (both carried over from subscriptions as working assumptions) · asc_patch_iap_offer_code (active)
  • One-time-use batches: asc_list_* / asc_get_* / asc_post_* / asc_patch_iap_offer_code_one_time_use_codes, and asc_export_iap_offer_code_one_time_use_values (CSV of the redeemable strings)
  • Custom codes: asc_list_iap_offer_code_custom_codes · asc_get_* · asc_post_iap_offer_code_custom_code (refuses a string the campaign already has) · asc_patch_*

Subscription introductory offers

Introductory offers target new subscribers — the discounted "first window" before the regular price kicks in.

  • asc_list_subscription_introductory_offers — list intro offers (free trial / pay-as-you-go / pay-up-front) configured for a subscription, across territories. Apple's "all territories" wildcard (a single offer with no territory) surfaces as TERR=(all) in the table. Pass territoryId to narrow to one market — wildcard offers are always kept, since they are live everywhere.
  • asc_get_subscription_introductory_offer — fetch one offer by ID.
  • asc_post_subscription_introductory_offer — create an offer. Three offerModes: FREE_TRIAL (no price; omit pricePointId), PAY_AS_YOU_GO (charge the offer price each period for numberOfPeriods periods), PAY_UP_FRONT (single charge for the whole duration; Apple still requires numberOfPeriods — defaults to 1 when omitted). Pass territoryId to target one market, or omit it for Apple's "all territories" wildcard (uses the literal price point in every market — no auto-FX). Server-side validation refuses PAY_* without pricePointId, PAY_AS_YOU_GO without numberOfPeriods, and endDate ≤ startDate — Apple's error is surfaced inline otherwise.
  • asc_patch_subscription_introductory_offer — narrow update path: only startDate, endDate, and pricePointId can change after creation. To change mode / duration / periods, delete and re-create.
  • asc_delete_subscription_introductory_offer — delete a pending or active offer. Apple refuses to delete one that is currently redeemable; PATCH endDate to today to stop it instead.

Subscription promotional offers

Promotional offers target existing or lapsed subscribers — opposite eligibility from intro offers, set by the resource type itself (no per-offer flag). Apple caps active promo offers at 10 per subscription. After creation, only the per-territory prices can be edited — name, offerCode, offerMode, duration, and numberOfPeriods are immutable.

  • asc_list_subscription_promotional_offers — list promo offers configured for a subscription.
  • asc_get_subscription_promotional_offer — fetch a single offer, including its per-territory prices.
  • asc_list_subscription_promotional_offer_prices — list per-territory price rows attached to an offer (territory + currency + amount + price-point ID).
  • asc_post_subscription_promotional_offer — create an offer (name + offerCode + mode + duration + all per-territory prices) in one atomic POST. Pre-flights Apple's 10-offer cap and offerCode collisions, refusing with a clear remedy message instead of letting Apple 409.
  • asc_patch_subscription_promotional_offer_prices — update the offer's per-territory prices. Apple's wire semantic is replace (the new prices array becomes the post-state, dropping any territory not listed); the tool's mode: 'replace' | 'add' | 'remove' parameter hides the footgun — 'add' reads current prices and merges, 'remove' reads and filters.
  • asc_delete_subscription_promotional_offer — DELETE → 204.

Subscription win-back offers

Win-back offers target lapsed subscribers — customers who previously subscribed and churned — and Apple surfaces them automatically to eligible customers based on the offer's eligibility rules (or through your own StoreKit messaging). This is the third offer type alongside introductory and promotional. Richer than promo offers: they add eligibility targeting, a schedule, priority, and an auto-asset intent. referenceName, offerId, duration, offerMode, periodCount, targetSubscriptionPlanType, and the prices are immutable after creation.

  • asc_list_subscription_win_back_offers — list win-back offers configured for a subscription.
  • asc_get_subscription_win_back_offer — fetch a single offer, including its subscription and per-territory prices.
  • asc_list_subscription_win_back_offer_prices — list per-territory price rows attached to an offer (territory + currency + amount + price-point ID).
  • asc_post_subscription_win_back_offer — create an offer (identity + eligibility rules + schedule + priority + all per-territory prices) in one atomic POST. Eligibility is expressed as customerEligibilityPaidSubscriptionDurationInMonths, customerEligibilityTimeSinceLastSubscribedInMonths (an { minimum, maximum? } range), and an optional customerEligibilityWaitBetweenOffersInMonths. Pre-flights offerId collisions and validates the range + endDate > startDate.
  • asc_patch_subscription_win_back_offer — update the mutable attributes only: eligibility, startDate/endDate, priority, and promotionIntent. To change identity, mode, duration, periods, or prices, delete and re-create.
  • asc_delete_subscription_win_back_offer — DELETE → 204.

App Asset Library (screenshots, previews, event assets)

App Store Connect API 4.5.1 replaced screenshot sets, preview sets and in-app event screenshots / video clips with one App Asset Library per app. You upload an image or video once, then place it: one placement puts one asset on one localization (version, Custom Product Page, experiment treatment or in-app event) in one placementType + device placementGroup slot. The same asset can be placed on many localizations. The library's id is the app id.

  • Reference data: asc_get_asset_library_ref_data — Apple's catalog of device groups (IPHONE_DYNAMIC_ISLAND_LARGE_PROFILE, IPAD_13_PROFILE, IPHONE_DUO_PROFILE, …), max assets per group (e.g. 10 screenshots, 3 previews) and the pixel/format/duration specs each group takes. Narrow it with sections and the filters; the full document is ~130 KB.
  • Library: asc_get_app_asset_library · asc_list_asset_library_{images,videos} (category / state / name / spec filters, placement count per asset) · asc_get_asset_library_{image,video} · asc_list_asset_library_{image,video}_placements (where an asset is shown).
  • Upload: asc_upload_asset_library_{image,video} (composite: reserve → PUT chunks → commit) · raw asc_post_* / asc_patch_* (uploaded, archived, referenceName, video previewFrameTimeCode) · asc_delete_*. The commit is uploaded: true alone — this API takes no checksum.
  • Placements: asc_list_localization_placements (what a localization shows, per group, in store order) · asc_get_asset_library_placement · asc_post_asset_library_placement (image or video × parent localization) · asc_delete_asset_library_placement (the asset stays in the library) · asc_post_asset_library_placement_ordering_request (reorder one group).

Product-page header (the wide image or video at the top of the product page): upload with category: "CREATIVE_ASSETS", then place it with placementType: "PRODUCT_PAGE_HEADER_ASSET", placementGroup: "DEFAULT_PROFILE" on a version, Custom Product Page or experiment-treatment localization. One per localization. Live specs (2026-10-23): PNG 5244x2950 (16:9) or 3840x1646 (21:9), no alpha; or video 3840x1646 (21:9), 30/60 fps, up to 30 s, .mp4/.m4v/.mov. APP_STORE_SEARCH_RESULTS_ASSET works the same way. asc_get_asset_library_ref_data with placementTypes: ["PRODUCT_PAGE_HEADER_ASSET"] shows the current specs.

The old set-based tools (asc_*_app_screenshot*, asc_*_app_preview*, asc_*_app_event_screenshot*, asc_*_app_event_video_clip*, asc_upload_screenshot, asc_upload_app_preview) still work against Apple's deprecated endpoints and now say so in their descriptions.

IAP & subscription review assets

The review screenshot Apple requires before an in-app purchase or subscription can be submitted, plus the optional promotional images — and, since v1.5, the App Review attachments of a version (files for the reviewer, e.g. a demo video). Five resources, each on the same three-step upload flow as app screenshots (reserve → PUT chunks → commit), with a composite asc_upload_* tool that does all three from a local file. Wire gotcha handled for you: the IAP image relates via inAppPurchase while the IAP review screenshot uses inAppPurchaseV2.

  • Images (to-many, per IAP / subscription): asc_list_{iap,subscription}_images · asc_get_* · asc_upload_* (composite) · asc_post_* / asc_patch_* (raw reserve/commit) · asc_delete_*.
  • Review screenshots (to-one, per IAP / subscription): asc_get_{iap,subscription}_review_screenshot (returns the single one, or null) · asc_upload_* · asc_post_* / asc_patch_* · asc_delete_*. Because it's to-one, the upload/reserve tools refuse if one already exists — delete it first.
  • App Review attachments (to-many, per version's review detail): asc_list_review_attachments · asc_get_review_attachment · asc_upload_review_attachment (composite) · asc_post_* / asc_patch_* · asc_delete_*. The parent id is the appStoreReviewDetail id from asc_get_app_store_review_detail.

App Review details, submissions & release

The last manual steps between "metadata is ready" and "build is live":

  • asc_get_app_store_review_detail / asc_post_… / asc_patch_… — the What-to-tell-App-Review card of a version: contact person, demo account (name/password/required), notes. To-one per version; Apple merges on PATCH.
  • asc_post_app_store_version_release_request — ⚠️ release an approved (PENDING_DEVELOPER_RELEASE) version to the public App Store now — the "Release this version" click, automated. Only for manually-released versions; no undo.
  • asc_post_iap_submission / asc_post_subscription_submission / asc_post_subscription_group_submission — submit an IAP / subscription / subscription group's pending metadata changes for review standalone, without a version release. Wire gotcha handled: the IAP one relates via inAppPurchaseV2.
  • asc_get_subscription_grace_period / asc_patch_… — billing grace period per app: optIn / sandboxOptIn, duration (3 / 16 / 28 days), renewalType (all renewals vs paid-to-paid only). Keeps lapsed subscribers entitled while Apple retries payment.

App Clips

An App Clip record appears when a build containing the clip is uploaded; the API cannot create one. Everything below hangs off it.

  • Clips: asc_list_app_clips (per app, bundleId filter) · asc_get_app_clip.
  • Default experience (the card for Safari banners, Messages and the default link; one per version): asc_list_app_clip_default_experiences · asc_get_… · asc_post_… (action, release version, or templateDefaultExperienceId to copy last version's card) · asc_patch_… · asc_delete_….
  • Version link: asc_get_app_store_version_app_clip_default_experience / asc_patch_… (from the version) · asc_get_app_clip_default_experience_release_version / asc_patch_… (from the experience). Apple's API can't unlink, only re-link.
  • Localizations: asc_list_app_clip_default_experience_localizations · asc_get_… · asc_post_… (locale + subtitle) · asc_patch_… · asc_delete_….
  • Header image (one per localization): asc_upload_app_clip_header_image (composite: reserve → PUT chunks → commit with MD5) · asc_get_app_clip_header_image (by image or localization) · raw asc_post_* / asc_patch_* · asc_delete_*.
  • App Review detail: asc_get_app_clip_app_store_review_detail (by detail or experience) · asc_post_… / asc_patch_… (invocation URLs).
  • Advanced experiences (per-URL cards: App Clip Codes, NFC, QR, Maps place cards): asc_list_app_clip_advanced_experiences (status / place status / action filters) · asc_get_… · asc_upload_app_clip_advanced_experience_image first, then asc_post_app_clip_advanced_experience (link, isPoweredBy, default language, header image, localizations inline, optional place) · asc_patch_… (removed: true takes it down; localizations replaces them all) · raw image asc_get_* / asc_post_* / asc_patch_*.
  • TestFlight invocations: asc_get_beta_app_clip_invocation · asc_post_… (build bundle ID, URL, titles inline) · asc_patch_… · asc_delete_… · asc_{post,patch,delete}_beta_app_clip_invocation_localization.

Background Assets (Apple-hosted asset packs)

  • Asset packs: asc_list_background_assets (per app; archived / identifier / locale / platform filters; shows the version live on internal beta, external beta and App Store) · asc_get_background_asset · asc_post_background_asset (assetPackIdentifier, fixed after create) · asc_patch_background_asset (archived only).
  • Versions: asc_list_background_asset_versions (state + per-track release-state filters) · asc_get_background_asset_version · asc_post_background_asset_version (Apple assigns the number) · asc_get_background_asset_version_release (track: internalBeta / externalBeta / appStore).
  • Files: asc_upload_background_asset_file (composite: ASSET archive or MANIFEST → reserve → PUT chunks → commit) · asc_list_background_asset_upload_files · asc_get_… · raw asc_post_* / asc_patch_*. The commit sends sourceFileChecksums.file (MD5 by default, SHA_256 accepted); the singular sourceFileChecksum is deprecated on this resource.

Availabilities (subscriptions, IAPs, plans)

Per-territory availability of in-app products — the sibling of App Availability with one key difference: territory linkage uses bare 3-letter ISO codes (plain territories), not the opaque composites apps use.

  • Subscriptions: asc_get_subscription_availability · asc_list_subscription_available_territories · asc_post_subscription_availability (full replacement — send the complete territory list; ⚠️ removed territories go off sale). Since API 4.4 deprecated SubscriptionAvailability, these read and write the subscription's UPFRONT plan availability instead — live data shows it carries the identical territory set, and every subscription has one. Same names and inputs as before.
  • IAPs: asc_get_iap_availability (reads through the v2 parent path) · asc_list_iap_available_territories · asc_post_iap_availability (same replace semantics).
  • Subscription plans (per plan type: UPFRONT = the standard plan, paid up front each period; MONTHLY = monthly billing with a 12-month commitment): asc_list_subscription_plan_availabilities · asc_list_subscription_plan_available_territories · asc_post_… · asc_patch_… (the one availability resource with a PATCH).

Marketplace webhooks (EU alternative marketplaces)

/v1/marketplaceWebhooks is deprecated. Marketplace notifications are now regular webhooks on the marketplace app, subscribed to the three ALTERNATIVE_DISTRIBUTION_* events. asc_list_marketplace_webhooks / asc_post_… / asc_patch_… / asc_delete_… keep their names and drive /v1/webhooks (create and list take marketplaceAppId); pass legacy: true to list, patch or delete records created on the old team-level endpoint. On an app that is not a marketplace app, Apple rejects these event types with a 409 — the tool says so.

Subscription offer signing (in-app redemption)

The cryptographic signer that makes promo/intro offers redeemable in your iOS app via StoreKit. Uses a separate signing key from the ASC API key — issued at App Store Connect → Users and Access → Integrations → In-App Purchase. See the optional config section for env vars. Built on Apple's official @apple/app-store-server-library.

  • asc_sign_promotional_offer_legacy — legacy ECDSA-concatenated signature used by StoreKit 1's SKPaymentDiscount and the original StoreKit 2 Product.PurchaseOption.promotionalOffer(offerID:keyID:nonce:signature:timestamp:) API. Returns the base64 signature plus the nonce, timestamp, and keyId for the caller to pass to StoreKit. Auto-generates a UUID nonce and current timestamp; both overridable for testing.
  • asc_sign_promotional_offer — JWS v2 format introduced at WWDC 2025 (back-deployed to iOS 15). Use with StoreKit 2's newer promotional-offer purchase options. Returns the JWS compact serialization directly. transactionId (the customer's appTransactionId) is optional but strongly recommended.
  • asc_sign_introductory_offer_eligibility — JWS v2 with aud="introductory-offer-eligibility". Lets you override StoreKit's default introductory-offer eligibility check (e.g. grant a returning customer another trial). New in WWDC 2025.

All signatures are valid for 24 hours from signing time — re-sign per redemption attempt rather than pre-signing and caching.

Age rating

The questionnaire App Review scores an app against — it gates submission, and there was previously no way to set it from here.

  • asc_get_age_rating_declaration — read the answers. Shows only the non-default ones (a typical declaration has 29 attributes, nearly all at NONE/false) plus every override, so the few that actually drive the rating stand out.
  • asc_patch_age_rating_declaration — answer the questionnaire. Content questions take a frequency (NONE / INFREQUENT_OR_MILD / FREQUENT_OR_INTENSE); the rest are booleans, plus the rating overrides and the Kids age band.

Two things about this resource are easy to get wrong, so the tools handle them for you. It hangs off AppInfo, not the version — age rating is per-app metadata like categories, and /v1/appStoreVersions/{id}/ageRatingDeclaration returns 404. And its ID is the AppInfo ID, so passing appId resolves the target automatically (if an app has several AppInfos across notarization tracks, the tool reports the candidates instead of guessing).

Apple merges on write: omitted keys keep their current value, so a partial update is safe — but you can't clear an answer by leaving it out, you have to send the explicit NONE/false. Overrides only ever raise the rating, never lower it.

Build uploads

Upload an .ipa / .pkg through the API instead of Transporter (API 4.1): create a build upload (app + version + build number + platform) → reserve the file → PUT the chunks to Apple storage → commit with the file's checksum. The commit takes sourceFileChecksums: { file: { hash, algorithm } }, a nested object, unlike the flat checksum string screenshots use.

  • asc_upload_build — the whole flow from a local file (MD5 checksum, UTI from the extension, dryRun prints both bodies). Apple then processes the build; follow it with asc_get_build_upload
  • asc_list_build_uploads — an app's uploads, newest first: version, build, platform, state (AWAITING_UPLOAD / PROCESSING / COMPLETE / FAILED, with error and warning counts) and the resulting build. A COMPLETE upload's build id equals its upload id. Slots abandoned mid-upload stay AWAITING_UPLOAD
  • asc_get_build_upload (full error / warning detail) · asc_delete_build_upload (drop a slot; doesn't touch processed builds)
  • Raw steps: asc_post_build_upload · asc_post_build_upload_file · asc_upload_asset_chunk · asc_patch_build_upload_file · asc_list_build_upload_files · asc_get_build_upload_file
  • Build bundles (the app, App Clips and extensions inside a processed build): asc_list_build_bundles · asc_list_build_bundle_file_sizes (download / install size per device) · asc_get_build_bundle_app_clip_domain_status (cache or debug) · asc_list_build_bundle_beta_app_clip_invocations

Xcode Cloud (CI/CD)

The build side of the ship loop: watch runs, read failures, kick builds. Hierarchy: products → workflows → build runs → actions (build/test/archive/analyze) → issues / test results / artifacts. A finished run links the TestFlight builds it produced, handing off to the TestFlight tools.

  • Reads: asc_list_ci_products · asc_list_ci_workflows / asc_get_ci_workflow (compact config summary: flags, start-condition patterns, actions, resolved Xcode/macOS — raw:true for Apple's full ~90k-char document) · asc_list_ci_build_runs (by workflow or product) / asc_get_ci_build_run · asc_list_ci_build_actions · asc_list_ci_issues · asc_list_ci_test_results · asc_list_ci_artifacts / asc_get_ci_artifact (pre-signed, time-limited downloadUrl — fetch it without the ASC bearer) · asc_list_ci_build_run_builds (the TestFlight handoff) · asc_list_ci_environment_versions (Xcode/macOS catalogs).
  • SCM reads: asc_list_scm_providers · asc_list_scm_repositories · asc_list_scm_git_references (branch/tag reference ids — what build-start takes) · asc_list_scm_pull_requests.
  • Triggers: asc_post_ci_build_run (start a build — optional branch/tag override + clean; uses the team's compute hours) · asc_patch_ci_workflow (pause/resume via isEnabled, clean, name, description — start conditions and actions stay Xcode-owned by design).

Featuring nominations

Pitch a release to Apple's editorial team for App Store featuring (Today tab, curated collections). Drafts are private; submission is one-way.

  • asc_list_nominations (filter by app / state / type) · asc_get_nomination · asc_post_nomination (defaults to a reviewable DRAFT — submitted:false) · asc_patch_nomination (edit the draft; submitted:true sends it to Apple — no un-submit, only archived:true) · asc_delete_nomination.
  • The pitch rides in description + notes; publishStartDate/publishEndDate frame the relevance window; supplementalMaterialsUris carry press-kit/TestFlight links; launchInSelectMarketsFirst is the wire key (Markets, not the UI's "storefronts" wording).

Game Center: details, groups, achievements, leaderboards

The core Game Center model on Apple's v2 paths (every /v1 achievement / leaderboard / set CRUD path is deprecated). An app has one Game Center detail; achievements, leaderboards and leaderboard sets belong to that detail, or to a Game Center group when several apps share Game Center data. Each item has versions that go through App Review, and each version has localizations with an image.

  • Detail and groups: asc_get_app_game_center_detail (an app without Game Center returns nothing, not an error) · asc_get_* / asc_post_* / asc_patch_game_center_detail · groups asc_{list,get,post,patch,delete}_game_center_group(s) · asc_list_game_center_group_details · asc_get_game_center_detail_group.
  • Achievements, leaderboards, leaderboard sets: list / get / post / patch / delete for each. Create sends the first version inline. Pass the owner as exactly one of gameCenterDetailId or gameCenterGroupId.
  • Versions → localizations → images: list / get / post per family, localizations with get / post / patch / delete, and a composite image upload (reserve → PUT chunks → uploaded: true) plus raw reserve / commit / delete.
  • Ordering replaces the owner's whole list in the order you give, so the tools refuse a list that adds or drops items. Set membership: add, replace (reorder) or remove leaderboards in a set; member localizations get list / post / patch / delete.
  • Moderation and submissions: asc_list_game_center_leaderboard_score_moderations · asc_patch_game_center_score_moderation (block a score) · asc_list_game_center_blocked_players · asc_patch_game_center_detail_player (block or unblock a player) · asc_post_game_center_leaderboard_entry_submission / asc_post_game_center_player_achievement_submission (server-side score and achievement reports). As of 2026-10-24 Apple answers 404 on the blocked-players and score-moderation reads although they are in the spec.
  • Deletes are pre-checked against version state, with force: true to skip the check.

Game Center: activities, challenges, matchmaking

The player-facing Game Center surfaces. Activities and challenges belong to an app's Game Center detail (pass appId and the tools resolve it) or to a Game Center group shared across apps. Their content lives on versions that ship with App Review: edit a PREPARE_FOR_SUBMISSION version, not the live one.

Documentation truncated — see the full README on GitHub.

Reviews

No reviews yet

Be the first to review this server!