Asc api app store submit
Skill bokuwalily/claude-code-skills/skills/asc-api-app-store-submit
iOSアプリをApp Store Connectへ「審査提出・状態確認・著作権/価格/メタの編集」する時。Appleログインや2FA無しで、保管済みのASC APIキー(JWT認証)を使って無人で操作する。eas submit後に審査まで通したい時、提出が止まった時、提出状態を確認したい時に発火。From its SKILL.md
npx -y skills add bokuwalily/claude-code-skills --skill asc-api-app-store-submitAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
17.5 KB, ~5.9k tokens by cl100k_base, as published. Nobody here has run it
Procedure
App Store Connectには「人がWeb画面で操作」と「ASC APIキー(JWT)でプログラム操作」の2経路がある。後者は 2FA不要・無人 で、ビルド/メタ/価格/審査提出まで叩ける。鍵がこのMacに保管済み=Claudeが自分で審査提出できる。
認証情報(このMacに保管済み・アカウント横断)
~/.appstoreconnect/keys.json… key_id / issuer_id / key_path / team を持つ(ここを読む。値をハードコードしない)~/.appstoreconnect/private_keys/AuthKey_*.p8… 唯一の秘密(chmod 600・dir 700・gitリポ外)- 1本でアカウント内の全アプリに有効(shukatsu/konomi/postwing/dayleaf 等)
再利用ヘルパー ~/.appstoreconnect/asc.py
python3 ~/.appstoreconnect/asc.py apps # 全アプリ(id/bundleId/名前)
python3 ~/.appstoreconnect/asc.py status <app_id> # version state/copyright/review/build
python3 ~/.appstoreconnect/asc.py set-copyright <app_id> "2026 Lily"
python3 ~/.appstoreconnect/asc.py submit <app_id> # 編集中バージョンを審査提出
python3 ~/.appstoreconnect/asc.py add-tester <app_id> # TestFlightテスター追加(既定=本人iCloud)
keys.jsonを読んでJWTを生成し直叩きする。statusで appStoreState と reviewSubmission.state を確認できる。
フルパイプライン(新規/更新アプリを審査まで)
- ビルド:
eas build --local -p ios --profile production(無料署名。credentials.json+リポのAppStore profile。skill [expo-free-local-ios-testflight]) - バイナリ上传:
eas submit -p ios --path build/<app>.ipa --non-interactive(EASサーバ保管のASCキーで2FA無し) - メタ/スクショ:
fastlane deliver(Deliverfile・fastlane/metadata+fastlane/screenshots)。スクショは 1320x2868(6.9") 必須・6.5"も入れると無難 - 価格: 未設定だと提出が止まる → Apple公式API
POST /v1/appPriceSchedules(USA/USD/free等)。fastlaneの旧price_tier経路は壊れてて使えない - 公開フィールドの本人性: copyright等は本名でなく「Lily」に(公開ポリシー)。
asc.py set-copyright - 審査提出:
asc.py submit <app_id>かfastlane deliver submit_build - TestFlightテスター追加(新規アプリは既定で必須):
asc.py add-tester <app_id>。既定で本人 iCloud[email protected]を内部グループ(Beta審査不要=本人が即インストール可)へ追加。内部グループが無ければPOST /v1/betaGroups(isInternalGroup:trueはAPIで設定可)で自動作成。今まで手動で全アプリに入れていた手間を自動化。冪等(filter[apps]で既存検出してskip)。別のテスターはadd-tester <id> <email>。- ⚠️唯一通る経路 =
POST /v1/betaTesters(attributes.email +relationships.betaGroupsで内部グループ指定)。POST /v1/betaGroups/{gid}/relationships/betaTestersに既存テスターidを直リンクすると 409 STATE_ERROR "Tester(s) cannot be assigned"(グローバルなbetaTester記録は外部用の名寄せで内部グループに付かない)。外部グループはビルドのBeta審査承認が無いとテスター追加不可で即時用途に使えない。createパスはemailで内部適格な記録に名寄せして付く。既に所属なら createパスも 409 を返す→filter[apps]で実在を再確認して成否を判定する。
- ⚠️唯一通る経路 =
Pitfalls
- 本名漏れ: App Storeのcopyright欄は公開。
fastlane/metadata/copyright.txtがデフォルト本名になりがち → 「2026 Lily」に。提出済みでもWAITING_FOR_REVIEW中はAPIでPATCH可(In Reviewでロック)。 - PII:
fastlane/Deliverfileに Apple ID メールが入る →.gitignore必須(リポ外)。.p8も当然gitignore。 - 価格未設定で提出停止: fastlane price_tierは死んでる。公式API
appPriceSchedules直叩きで解決。 - JWT: ES256・
iss=issuer_id・aud="appstoreconnect-v1"・exp 20分以内。cryptographyでECDSA署名→r||s(各32byte)にrawエンコード(DERのままはNG)。 - キーの場所: Downloads等の揮発場所に置かない。
~/.appstoreconnect/(700)に集約済。新しい鍵を貰ったら keys.json を更新するだけ。 - eas submit のキーはEASサーバ保管(別ID)。
asc.pyのキー(ローカル)とは別物だが両方同アカウント。 - ITMS-90111 (beta macOSビルドが真因・2026-06-26 ねむログ/Konomiで確定): 提出が
ITMS-90111「Unsupported SDK or Xcode version - use latest RC」で却下され version が直後にINVALID_BINARY転落する時、エラー文言はミスリードで真因は beta macOS でビルドした事。アーカイブのBuildMachineOSBuildにbeta値(例26A5368g=macOS27beta)が埋まり、Apple検証が拒否。最新安定版Xcodeでも落ちる(=ツールチェーンが原因に見えるが違う)。ニュース/フォーラムが無い=Apple全体障害でなく自分の環境を疑え。回避: アーカイブの.app/Info.plist(と全PlugIns/*.appex/Info.plist)のBuildMachineOSBuildを安定版macOSビルド番号(例25F80=macOS26.5.1、都度確認)にPlistBuddy -c "Set"で書換え→xcodebuild -exportArchive(再署名がパッチ済plistに乗る)→ IPAで値とcodesign --verify --deep --strictを検証→ altool upload。提出後 3-4分 WAITING_FOR_REVIEW 維持=成功(失敗は1-2分でINVALID_BINARY)。詳細=memoryreference_itms90111_beta_macos。なお Expo/RN は Xcode beta でnode_modules/*/.DerivedDataが汚染され安定版でもビルド不能になる→該当.DerivedDataを rm して再ビルド。 - 価格(無料)スケジュールPOSTの正解形(2026-06-22 つづけで確定):
POST /v1/appPriceSchedules、data.relationships={app, baseTerritory(territories/USA・必須), manualPrices→[{type:"appPrices",id:"${p}"}]}、included=[{type:"appPrices",id:"${p}","attributes":{},relationships:{appPricePoint:{data:{type:"appPricePoints",id:<free>}}}}]。⚠️includedのappPriceに"attributes":{}(空オブジェクト)が無い/startDate:nullだと422 invalid value at data.included。manualPricesにappPricePoints型を直入れすると409。価格ポイント=/v1/apps/{id}/appPricePoints?filter[territory]=USAでcustomerPrice=="0.0"(そのトークンidの直GETは404でも提出には有効)。
Verification
python3 ~/.appstoreconnect/asc.py status <app_id>でappStoreState=WAITING_FOR_REVIEWと狙いの copyright を確認- PATCH/submitは戻りHTTP<400かつ再GETで反映を確認(推測で「提出済み」と言わない)
- 実績: 2026-06-19 konomi(6780963389) build13 を本パイプラインで審査提出・copyrightを本名→「2026 Lily」にPATCH(200)・
WAITING_FOR_REVIEWをAPIで裏取り済 - 実績: 2026-06-21 5本(就活/PostWing/Konomi/30H/Dayleaf)を最新UIスクショ+掲載文込みで一括審査提出。下記の罠を全部踏んで突破。
5本同時提出で踏んだ罠 (2026-06-21・再発防止)
- 審査待ちの差し替え: WAITING_FOR_REVIEW のまま新ビルドは載せられない。先に
asc.py reject <id>(保留submission取消)→make-versionで新版→attach→submit。- ⚠️**
attach-build <app_id> <ARG>の ARG は build番号でなく marketing version("1.0.0")**(2026-06-22 Akari build4で確定)。内部の_build_for_versionは preReleaseVersion.version(=CFBundleShortVersionString)でマッチし、同 marketing の最新VALID buildを選ぶ。build番号(4)を渡すとno VALID build for version 4で永遠に空振り。正しい差し替え全手順:reject <id>→attach-build <id> 1.0.0→submit <id>→statusで attached build番号と WAITING_FOR_REVIEW を裏取り。 - 同 version で build番号だけ上げる更新(build3→4)は
make-version不要(既存編集中versionにattachするだけ)。CURRENT_PROJECT_VERSION を project.yml で上げxcodegen generate(pbxprojに焼く)→archive→export→altool→VALID待ち→上記差し替え。
- ⚠️**
- 公開中(READY_FOR_SALE)の更新: ASCの現行versionより上の番号必須。configが古い値でもASC側が先行している(例: 就活configは1.0.5だがASC公開は1.2)→必ず
asc.py statusで現行を見てから上の番号に。 - Expo prebuildのバージョン焼き込み: app.config の version bump 前 に
expo prebuildするとios/に旧版が焼かれ、altoolがCFBundleShortVersionString must be higher / train closed (90062/90186)で蹴る。直し=/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString X" ios/<App>/Info.plist+CFBundleVersionも。bumpは prebuild より前に。 - dual-cert+capability署名(EAS無料クラウド枠切れ時):
eas build --localは EAS管理プロファイルがローカル鍵の無いcertを指してprofile doesn't include signing certificateで死ぬ。回避=ネイティブ流の fastlane ローカル署名。Expoの prebuiltios/<App>.xcworkspace(scheme=app/PostWing等) に対し最小Fastfile:get_certificates(development:false)+get_provisioning_profile(force:true)+build_app(... xcargs: "... PROVISIONING_PROFILE_SPECIFIER='#{lane_context[SharedValues::SIGH_NAME]}'")。xcargs に PROVISIONING_PROFILE_SPECIFIER を入れ忘れると archive でrequires a provisioning profile with Push/Sign In with Appleになる(Bundle IDにcapabilityはあるのにprofile未指定で自動署名が外す)。 - fastlane deliver の api_key:
--api_key_pathの JSON はkey(=.p8本体テキスト) が必須。key_filepathだけだとmissing field(s): key。一時JSONを{"key_id","issuer_id","key":<p8文字列>,"in_house":false}で作る(600・使い終わったら消す)。 - deliver スクショ:
sync_screenshots:trueはFASTLANE_ENABLE_BETA_DELIVER_SYNC_SCREENSHOTS要求で止まる→overwrite_screenshots:trueのみ(syncは付けない)。初版は release_notes がスキップされる(whatsNew 409=初回は不要)。更新版はasc.py whatsnew可。 - altool 空パス:
-f "$IPA"の変数が空だとFile does not exist at path: .で ExitFailure 31。必ず絶対パスで渡す。fastlane build_appの出力は プロジェクト直下<scheme>.ipa。 - 提出409 (localization invalid): 追加ロケール(ko/en-US)に サポートURL or スクショが無い と
appStoreVersionLocalizations ... not in valid state。直し=各ロケールに supportUrl をPATCH+スクショを全ロケールへ配置して deliver。スクショ assetDeliveryState は全COMPLETEを確認してから submit(アップロード途中で submit すると appScreenshots invalid)。 - 検証:
GET /v1/builds?filter[app]=<id>&fields[builds]=version,processingStateでVALIDを待ってから attach。
追補: 新規ネイティブiOSアプリを“箱作成〜審査提出”まで無人で出す (2026-06-22 Auralyで全実証)
新規アプリは APIキーだけでは作れない/落とし穴が多い。実証済みの順序:
- 箱(App record)作成:
POST /v1/appsはAPIキーで 403 (CREATE不可)。正解=fastlane produce。Fastfileでapp_store_connect_api_key(asc_key) →produce(app_identifier:, app_name:, language:"Japanese", sku:, team_id:, skip_devcenter:true)。Appfileにapple_idを置く。spaceshipセッションが無効でも APIキーにフォールバックしてパスワード/2FA無しで作成できる。 - 署名/archive/altoolアップロード/VALID待ちは本文どおり。
- スクショは deliver、ただしスクショ単独で:
fastlane deliver --skip_binary_upload true --skip_metadata true --skip_screenshots false。⚠️metadataを同時にやるとreview_attachment_fileで クラッシュ(No data)。- 🛑deliver後・submit前に必ず
python3 ~/.appstoreconnect/asc.py dedup <app_id> --applyを実行する(必須・任意ではない)。overwrite_screenshots:true(syncなし)はリトライ時に既存を消さず追記するため、deliverが2回走ると各スクショが連続2枚に二重化する(同 checksum+fileName)。ストアで「同じ写真が2枚ずつ並ぶ」醜い表示になる。dedupは同一 checksum+fileName の2枚目以降をDELETE /v1/appScreenshots/{id}で間引く(編集中versionのみ可)。--apply無しはdry-run。2026-06-22に6アプリ(つづけ/就活トラッカー/PostWing/Dayleaf/30H/Konomi)で全滅し一括修正した再発防止。 - 公開中(READY_FOR_SALE)アプリの修正は新version作成→継承スクショをdedup→新ビルド添付→submit。⚠️公開中versionは
DELETEが 409(STATE_ERROR)。審査中(WAITING_FOR_REVIEW)はasc.py rejectで DEVELOPER_REJECTED にしてから dedup→submit。
- 🛑deliver後・submit前に必ず
- メタ/著作権/ビルド添付/価格/年齢/審査連絡先は
asc.pyのcall()をimportして直叩き:- localization PATCH、version PATCH(copyright + relationships.build)。
- 無料価格:
GET /v1/apps/{id}/appPricePoints?filter[territory]=USAで customerPrice "0.0" の point →POST /v1/appPriceSchedules(included appPrice id${price-0}が free point を指す)。 - 年齢4+:
PATCH /v1/ageRatingDeclarations/{id}。⚠️型混在。enum"NONE"= violence*/sexual*/contests/gunsOrOtherWeapons/alcohol/gamblingSimulated/horror/mature/medical/profanity。BOOLEAN(false)= advertising/messagingAndChat/gambling/lootBox/unrestrictedWebAccess/healthOrWellnessTopics/parentalControls/userGeneratedContent/ageAssurance。kidsAgeBand=null。 - 審査連絡先:
POST /v1/appStoreReviewDetails。contactPhone必須(+国番号形式 例+81 90 7170 0135)。demoAccountRequired:false。 PATCH /v1/apps/{id}contentRightsDeclaration:"DOES_NOT_USE_THIRD_PARTY_CONTENT"。
- App Privacy(必須): ⚠️
appDataUsages系エンドポイントは このAPIキーで全404(アプリrelationshipsにも無い)。正解=fastlane upload_app_privacy_details_to_app_storeをレーン内でasc_keyの後に呼ぶ(api_key引数は無いがlane contextのトークンをspaceshipが拾う)。json=[{"data_protections":["DATA_NOT_COLLECTED"]}]。 - iPad要件: device family
"1,2"だと提出時にSCREENSHOT_REQUIRED.APP_IPAD_PRO_3GEN_129。iPhoneアプリはTARGETED_DEVICE_FAMILY:"1"にして回避→build番号上げて再ビルド/再アップロード。 - 提出:
asc.py submit <id>。409時はmeta.associatedErrorsに不足項目が全列挙される(screenshot/reviewDetail/appDataUsages 等)→それを全部潰してから再提出。 - アプリ名衝突: ja主言語名は作成時に空きなら通るが、en-USローカライズ追加で同名が他アプリと衝突しうる→ v1は ja単独掲載で出し、en-USは承認後に別名で追加。
追補2 (2026-06-22 Hibiで確定・produce 500と提出必須項目)
fastlane produceが「Server error got 500」で死ぬ最大要因 = bundleIdが事前に存在しない。skip_devcenter:trueを付けると produce は App ID(devcenter)作成をスキップし bundleId 既存前提で app record だけ作る→bundleId が無いと名前と無関係に 500(名前を変えても直らず名前衝突と誤診しやすい)。→ 必ず先にsetup_signing.py(POST /v1/bundleIds で bundleId 作成)を実行してから produce。順序: setup_signing → produce → archive → upload。- submit が 409 になる隠れ必須2点(
meta.associatedErrorsはtruncateされるので直接dumpして全文読む):- primaryCategory 未設定 =
appInfosの relationship(Deliverfileのprimary_categoryだけでは付かない)。PATCH /v1/appInfos/{appInfoId}でrelationships.primaryCategory.data={type:"appCategories",id:"LIFESTYLE"}(+secondaryCategory)。appInfoId=GET /v1/apps/{id}/appInfos。 - APP_PRICING_REQUIRED = 新規アプリにASCが自動生成する空のappPriceScheduleは無効。
POST /v1/appPriceSchedulesで USA free point を明示作成し直す(included appPrice に"attributes":{}必須・既存あっても再POSTで201上書き)。
- primaryCategory 未設定 =
- 年齢宣言の必須属性(欠けると REQUIRED 409 が連鎖): ENUM"NONE"= violence*/sexual*/profanity*/mature*/horror*/medical*/alcohol*/gamblingSimulated/contests/gunsOrOtherWeapons。BOOL(false)= gambling/unrestrictedWebAccess/advertising/messagingAndChat/lootBox/healthOrWellnessTopics/parentalControls/userGeneratedContent/ageAssurance。kidsAgeBand=null。
seventeenPlusは存在しない(入れると UNKNOWN 409)。 - deliver スクショ二重UP: deliver は1回目「missing on App Store Connect」→自動リトライで各fileNameが2枚に重複(6枚=3種×2)。submit前に重複削除必須=
DELETE /v1/appScreenshots/{id}(各fileNameの2枚目以降)。WAITING_FOR_REVIEW中は409で削除不可→asc.py reject <id>(version→DEVELOPER_REJECTED)→各setをfileNameでグルーピングし1枚残して削除→asc.py submitで再提出。
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.