The App Store Connect API in 2026: A Step-by-Step Guide to Keys, JWT Tokens, and Rate Limits
The App Store Connect API is the REST layer behind the App Store Connect web interface: Apple's own summary is that it "enables the automation of actions you take in App Store Connect," and it explicitly warns that what you change through it is production data. That single sentence is the reason this guide exists — a working key and a valid token are enough to invite users, change bundle IDs, upload builds, edit App Store metadata, and download sales reports, all without a browser. This 2026 guide covers the access request only the Account Holder can file, team versus individual keys, the ES256 JWT that authorises every call, the rolling-hour rate limit and HTTP 429, error reading, paging, asset uploads, and key revocation.
The one-line version: the Account Holder requests API access once; an Admin generates a role-scoped team key (or each user generates a single individual key); your code signs a short-lived ES256 JWT whose kid is the key ID and whose aud is appstoreconnect-v1; every response carries an X-Rate-Limit header, and crossing the hourly limit returns 429 RATE_LIMIT_EXCEEDED.
Step 1 — Know what the API actually reaches
Before requesting anything, map the surface you intend to automate, because the key's role determines what is reachable. Apple documents resources for In-App Purchases and auto-renewable subscriptions, TestFlight beta builds, testers and groups, Xcode Cloud data and workflows, Users and Access, Provisioning (bundle IDs, capabilities, certificates, devices, profiles), App Metadata and submissions, App Clip experiences, Reporting (sales and financial reports), Power and Performance Metrics, and customer reviews with their responses. Two structural facts matter: the resources return consistent JSON with relationship links for navigating between them, and if your account is in the Apple Developer Enterprise Program, Apple points you at the Enterprise Program API instead of this one. Do not build against the wrong API and discover it during a release.
Step 2 — The access request only the Account Holder can make
API access is not switched on by default and it is not a per-key toggle. The Account Holder signs in, opens Users and Access > Integrations (the page opens with App Store Connect API selected), clicks Request Access, agrees to the terms and submits. Apple then reviews the request and approves it "on a case-by-case basis" — which means the correct sequence is to file this before you promise anyone an automation date, not on the day of the release. Once approved, the same page holds the issuer ID and the key list.
Step 3 — Choose team keys or individual keys, correctly
Apple defines two key types and they are not interchangeable:
- Team keys — generated by the Account Holder or an Admin, applied across all apps in the account, and their access is set by the role you pick. You cannot limit a team key to specific apps: "team API keys are applied across all apps, so app access can't be limited for an API key."
- Individual keys — generated by a user in their profile, carrying that user's apps and role. Roles that may create one are Account Holder, Admin, App Manager, Customer Support, Developer and Marketing, and each user can hold only one active key at a time. Apple's documentation adds two hard limits worth designing around: individual keys cannot use the provisioning endpoints or
notaryTool.
Two operational rules follow. A key's name and access level cannot be edited after generation — to change either, revoke the key and generate a new one. And the private half is downloadable exactly once: if your pipeline loses it, the fix is a new key, not a re-download. Keep a server-side secret store and treat the .p8 file exactly like a database password.
Step 4 — Build the ES256 token Apple actually accepts
Every request needs a JWT signed with the private key you downloaded. Apple's token documentation fixes the header fields: alg must be ES256, kid is your private key ID (for example 2X9R4HXF34), and typ is JWT. For a team key the payload carries iss (the issuer ID, for example 57246542-96fe-1a63-e053-0824d011072a), iat and exp in UNIX epoch time, and aud set to appstoreconnect-v1. The expiry rule is the one that bites in production: tokens that expire more than 20 minutes into the future are not valid except for the resources Apple lists as exempt. Mint short tokens, reuse them inside the window, and never cache one past it. If you have several team keys, the kid must belong to the same private key that signs the token — a mismatched pair fails authentication, not authorisation.
Individual keys use a slightly different payload: no iss, and instead a sub claim whose value is user. If you write one token builder for both key types, make that difference explicit in code rather than inferred at runtime.
Step 5 — Scope the token instead of hoping it is not leaked
Apple supports an optional scope claim: a list of the requests this token is allowed to make, where each entry is an HTTP method plus URL path plus optional query string — for example GET /v1/apps/123 or GET /v1/apps?filter[platform]=IOS. A token presented with a scope that does not cover the request is rejected. The reasoning Apple gives is worth quoting back to whoever argues that scope is overhead: if you unintentionally share a token with an unauthorised party, a limited scope reduces what that party can do with it. Automation that only reads sales reports should carry a read-only scope, not the full authority of the key's role.
Step 6 — Respect the rolling hour, and handle 429 as a state, not an error
Rate limits in this API are per key, and they are not documented as a single fixed number. Every response carries an X-Rate-Limit header containing user-hour-lim (requests allowed per hour for that key) and user-hour-rem (requests remaining); Apple's own example shows a limit of 3500 requests per hour with 500 remaining, and states that actual limits can vary. The window is a rolling hour: at any moment the remaining figure is your limit minus everything you sent in the previous 60 minutes. Exceed it and the API answers HTTP 429 with the RATE_LIMIT_EXCEEDED error code. Two consequences for design: read user-hour-rem and throttle pre-emptively when it is low, and treat a 429 as "log it and queue the job for later" rather than as a fatal error — a nightly export that fails loudly on a 429 will fail every night it drifts near the ceiling.
Step 7 — Read failures from the status code, then the error object
Per Apple's error guidance, a status code in the 200 range means success and the body holds the data; a 400- or 500-range code means the request failed and the body holds the details. The error object also carries a code for programmatic handling, and in many cases a source object that points at exactly what was wrong in your request — a JSON pointer into the payload, or the query parameter that produced the error. Read the source before rewriting the request; the difference between "my JSON is malformed at this path" and "my role cannot do this" is the difference between a five-minute fix and a support ticket.
Step 8 — Page large result sets instead of guessing a bigger limit
Responses for collections include paging information and related links — a pagination object plus the response links that carry you forward. Write the loop that follows those links until the cursor is exhausted; do not assume a single call returns every build, tester, or App Store version, and do not hard-code a page size you believe is "big enough". A report that silently truncates is worse than a slow one.
Step 9 — Upload assets in the order Apple requires
Binary assets — screenshots, app previews, attachments for App Review, routing app coverage files — follow a four-step flow: make an asset reservation (asset type, filename, size in bytes), upload the bytes using the operations returned in that response, commit the upload, then verify that App Store Connect processed the asset. A successful reservation returns a reservation ID, a set of upload operations, the file attributes, and a delivery state of AWAITING_UPLOAD. Large files come back as multiple operations that tell you the offset and length of each part — the API deliberately splits them so a flaky connection does not cost you the whole file. Note also that the app screenshot, app preview and in-app event screenshot resources are deprecated: manage screenshots, previews and in-app event media through the App Asset Library and placements instead. And do not leave a reservation half-finished; Apple states you have limited time to complete the upload after reserving.
Step 10 — Rotate and revoke like the key is a credential
The Account Holder or an Admin can revoke team keys and any team member's individual keys; users can revoke their own. Revocation is immediate and permanent — a revoked key cannot be reinstated — which makes revocation the correct emergency action, not a last resort. Revoked keys stay visible on the API Keys page under a Revoked heading for 30 days, which is long enough to answer "which key was that?" after an incident but not long enough to serve as your audit trail, so log key IDs alongside your automation runs. Finally, if a person should never obtain API access at all, an Admin can remove the Generate Individual API Keys permission from that user in People — the control exists, so use it rather than relying on policy.
The checklist
- Account Holder has filed the access request and it is approved.
- Key type chosen deliberately: team key for account-wide automation, individual key for one user's scope.
- Private key stored once, in a secret manager, with a documented owner.
- Token builder:
ES256,kidmatching the signing key,aud=appstoreconnect-v1,expinside 20 minutes,scopeas narrow as the job allows. - Client reads
X-Rate-Limit, backs off before the limit, queues on 429. - Collection calls follow paging links; nothing assumes a complete first page.
- Asset uploads reservation, parts, commit, verification-state checked.
- Revoked keys logged with the reason and the date; 30-day visibility not treated as an audit log.
Apple maintains a release-notes changelog for the API. Apple adds fields and resources over time, so re-read it before you treat your integration as finished.
Sources
- Apple Developer — App Store Connect API overview: developer.apple.com/documentation/appstoreconnectapi
- Apple Developer — App Store Connect API (help, access request and keys): developer.apple.com/help/app-store-connect/get-started/app-store-connect-api
- Apple Developer — Creating API keys: creating-api-keys-for-app-store-connect-api
- Apple Developer — Generating tokens for API requests: generating-tokens-for-api-requests
- Apple Developer — Identifying rate limits: identifying-rate-limits
- Apple Developer — Interpreting and handling errors: interpreting-and-handling-errors
- Apple Developer — Large data sets (paging): large-data-sets
- Apple Developer — Uploading assets: uploading-assets-to-app-store-connect
- Apple Developer — Revoking API keys: revoking-api-keys
- Apple Developer — App Store Connect API release notes: app-store-connect-api-release-notes
Running developer accounts at scale? We handle the operational side.
We received your message and will reply within 24 hours.
Or email expert@kapps.store← Back to edit