Home / skills/app-store-connect-read-with-a-box-api-key/SKILL.md
App Store Connect read with a box API key
name: App Store Connect read with a box API key description: >- Use when you need App Store Connect sales numbers or app/version review states read-only from the cloud computer (no Mac): builds a short-lived JWT from a locally stored API key and calls the official API. Never writes.
App Store Connect read with a box API key
Read-only. Never create versions, edit metadata, change prices, or submit through this recipe. Those are approval-gated writes.
Inputs (from the calling routine or memory, never from this skill)
- The key ID and issuer ID.
- The vendor number (needed for sales reports only).
- The app IDs to check.
- The key file, stored at a path following
~/.appstoreconnect/private_keys/AuthKey_<KEY_ID>.p8. The file must be mode 600, inside a 700 directory. - A local helper script, if one exists (for example
~/.appstoreconnect/bin/<name>.py). Prefer it over writing new code.
Secrets
- Never print, cat, copy, upload, or paste the .p8 contents or a minted token into chat, files, logs, or tool arguments. Load the key inside the script.
- Never commit the key, or a script with a key embedded, to a repo.
Auth
Sign an ES256 JWT:
- header
{"alg":"ES256","kid":"<KEY_ID>","typ":"JWT"} - claims
{"iss":"<ISSUER_ID>","iat":now,"exp":now+<=1200,"aud":"appstoreconnect-v1"}
Send it as Authorization: Bearer <token>. Python needs pyjwt and cryptography; keep them in a venv beside the scripts.
Sales (daily or weekly)
GET https://api.appstoreconnect.apple.com/v1/salesReportswith these query parameters:filter[frequency]=DAILY|WEEKLYfilter[reportType]=SALESfilter[reportSubType]=SUMMARYfilter[vendorNumber]=<VENDOR>filter[reportDate]=YYYY-MM-DD(weekly reports use the week-ending Sunday)filter[version]=1_1- header
Accept: application/a-gzip
- Gunzip the response. It's a TSV; sum units and developer proceeds per SKU or app title.
- HTTP 404 means no sales for that date, or the report isn't published yet. Apple publishes daily reports the next day, Pacific time. Say which, based on the time.
- Promo-code redemptions show a separate product type. Don't count them as sales.
App and version states
GET /v1/apps/<APP_ID>/appStoreVersions?limit=5&fields[appStoreVersions]=versionString,appStoreState,platform,createdDate- Report
versionString,appStoreState(orappVersionState), and the platform for the newest versions. Compare against the last-known state file and report only deltas.
What a narrow-role key can't read
A key with only a Sales/Finance role returns 403 on in-app purchases, TestFlight, and some app resources. Report "not readable with this key" rather than calling it an outage, and name the role that would be needed. Creating a broader key needs the user's approval.
Output
One line per app: version, state, and change since last time. Sales: units and proceeds for the date, or "no sales" / "report not ready". Add the evidence (HTTP status, report date). Never invent states or numbers.