Blog · · Guide

App Store Connect API key: Issuer ID, Key ID and roles

Uploading from the command line, CI, scripts, sales reports and coding agents all start with the same thing: an App Store Connect API key. Here is how to create one, which of its three parts goes where, and which role to give it.

What a key is

An App Store Connect API key has two halves. Apple keeps the public half; you download the private half once, as a file called AuthKey_<Key ID>.p8. With it you sign short-lived tokens (JWTs) that authorize each request to the API. Three values belong together:

Value Looks like Where you find it
Issuer ID 57246542-96fe-1a63-e053-0824d011072a Users and Access › Integrations, near the top of the page, with a Copy button
Key ID 2X9R4HXF34 (10 characters) In the key’s row; hover next to it for Copy Key ID
Private key AuthKey_2X9R4HXF34.p8 The file you downloaded. Apple keeps no copy

These keys work only with the App Store Connect API. The In-App Purchase keys on the same Integrations page are a different kind of key, for the App Store Server API and subscription offers.

Team key or individual key

  • Team keys reach every app in your account, with the roles you choose for the key. You can’t limit a team key to some apps. Only the Account Holder or an Admin can create them.
  • Individual keys carry the access and apps of the person who creates them. Each user can have one active individual key. They can’t use the Provisioning endpoints, Sales and Finance reports or notarytool.

If you want sales or finance reports, or a key that keeps working when someone leaves the team, create a team key.

Before the first key

The first time, the Account Holder has to request access: Users and Access › Integrations › Request Access, accept the terms and submit. Apple reviews these requests case by case. After that, the Account Holder and Admins can create team keys.

Create a team key

  1. In App Store Connect, open Users and Access, then the Integrations tab. App Store Connect API is selected.
  2. Select Team Keys.
  3. Select Generate API Key, or the Add (+) button if you already have one.
  4. Enter a name. It’s only for you, for example the tool or machine that will use it.
  5. Under Access, choose the role (or roles) for the key (see the next section).
  6. Select Generate. The key appears with its Key ID.
  7. Select Download API Key and keep the .p8 file safe. The download link disappears once you’ve used it.

You can’t change a key’s name or roles later. To change them, revoke the key and create a new one.

Which role for which job

A key’s roles are the same roles people have on your team. Give it only what the job needs. This table follows Apple’s role permissions, where “full access” counts and “read-only access” doesn’t:

Job Role that covers it
Upload builds App Manager or Developer (each with access to Certificates, Identifiers & Profiles)
Submit for review, release a version, phased release App Manager
Create, edit and submit in-app purchases App Manager
TestFlight builds and external groups App Manager
Internal TestFlight groups App Manager, Developer or Marketing
Sales and Trends reports Finance, or Sales with access to reports
Payments and Financial Reports Finance
Read customer reviews App Manager, Developer, Marketing or Customer Support
Reply to customer reviews Customer Support

Two patterns cover most setups. A CI machine that uploads, hands builds to external testers and submits needs App Manager. A dashboard or script that reads sales and payments needs Finance. A tool that does both needs both roles. Admin works for everything, which is also why it’s the role to avoid for a key that lives on a build server.

Keep the private key safe

  • Store the .p8 in a password manager or your Keychain, not in a repository. Apple’s guidance is explicit: don’t share keys, store them in a code repository or put them in client-side code.
  • A coding agent that can read your project can read any key file in it. Keep keys outside the folders the agent works in.
  • Command-line tools look for the file in known places. altool, for example, searches ~/.appstoreconnect/private_keys/ (among others) for AuthKey_<Key ID>.p8.

Sign a request

Each request carries Authorization: Bearer <token>, where the token is a JWT signed with ES256:

  • Header: alg = ES256, kid = your Key ID, typ = JWT.
  • Payload: iss = your Issuer ID, iat = now, exp = no more than 20 minutes later, aud = appstoreconnect-v1. An optional scope limits the token to the requests you list.
  • Individual keys use sub = user instead of iss.

With Apple’s CryptoKit, the whole thing fits in a short script. Save it as jwt.swift next to the key file and run swift jwt.swift:

import CryptoKit
import Foundation

let keyID = "2X9R4HXF34"                              // Key ID
let issuerID = "57246542-96fe-1a63-e053-0824d011072a" // Issuer ID
let pem = try String(contentsOfFile: "AuthKey_\(keyID).p8", encoding: .utf8)

func base64URL(_ data: Data) -> String {
    data.base64EncodedString()
        .replacingOccurrences(of: "+", with: "-")
        .replacingOccurrences(of: "/", with: "_")
        .replacingOccurrences(of: "=", with: "")
}

let now = Int(Date().timeIntervalSince1970)
let header = #"{"alg":"ES256","kid":"\#(keyID)","typ":"JWT"}"#
let payload = #"{"iss":"\#(issuerID)","iat":\#(now),"exp":\#(now + 1200),"aud":"appstoreconnect-v1"}"#
let input = base64URL(Data(header.utf8)) + "." + base64URL(Data(payload.utf8))
let key = try P256.Signing.PrivateKey(pemRepresentation: pem)
let signature = try key.signature(for: Data(input.utf8))
print(input + "." + base64URL(signature.rawRepresentation))

Then try it:

curl -H "Authorization: Bearer $(swift jwt.swift)" https://api.appstoreconnect.apple.com/v1/apps

The signature must be the raw 64-byte form (rawRepresentation), not DER. You don’t need a new token for every request: reuse one until it expires. For a one-off request, Apple suggests a lifetime as short as two minutes.

When a request fails

  • 401 Unauthorized. Apple’s status-code table doesn’t list it, but in practice it means the token wasn’t accepted. Check it against Apple’s token rules: the Key ID, Issuer ID and .p8 belong to the same key; exp is no more than 20 minutes after iat (Apple allows longer only for some scoped, read-only requests); your Mac’s clock is right; aud is appstoreconnect-v1; an individual key’s token uses sub instead of iss.
  • 403 Forbidden. Apple’s documentation names a revoked key, a badly formatted token, or an operation the key’s role doesn’t allow. Reading sales reports with an App Manager-only key is a typical case.
  • 429 Too Many Requests. Limits apply per key and per rolling hour. Every response has an X-Rate-Limit header with the limit and what’s left.

Revoke and replace a key

Users and Access › Integrations › Team Keys › Edit, select the key, then Revoke Key. A revoked key can’t be reinstated, and it stays listed under Revoked for 30 days. To rotate a key without downtime, create the new one, move your tools to it, then revoke the old one.

Using the key with SwiftSales

SwiftSales uses your team’s key for both of its halves: the sales and finance reports behind its dashboard, and the App Store Connect work your agent does through its App Store Connect MCP server.

Which key and role

  • A team key. Sales and Finance reports only work with team keys, so an individual key won’t do.
  • Finance + App Manager is the recommended choice. Finance reads the finance reports, so fiscal months show the amounts Apple settled. App Manager lets your agent upload builds, run TestFlight, submit, release and create in-app purchases.
  • Finance alone is enough for the dashboard. When you want your agent to ship as well, add a Release Key: a second team key with App Manager, which you add in SwiftSales on your Mac under Settings › Teams. SwiftSales uses it only for release work.
  • Sales, with access to reports, also reads your sales. Fiscal month amounts are then estimated from the daily reports.

When a key can’t do something, SwiftSales tells you which role to add. Create a Team Key walks through it in the app’s own words.

Where it’s kept

You import the .p8 file once and enter the Issuer ID and your vendor number; SwiftSales fills in the Key ID when the file keeps its original name. The key stays in your Keychain, and with iCloud sync on (part of Lifetime Premium and the free trial) your other iPhone, iPad and Mac can use it too. It goes nowhere else: SwiftSales signs each request on your device and talks to Apple directly, so the key never has to sit in a project folder, and your agent never sees it.

SwiftSales Settings, Teams, Harbor Lane Studio: Key ID, Issuer ID, and a line saying the key reads sales, finance and reviews and can submitSwiftSales Settings, Teams, Harbor Lane Studio: Key ID, Issuer ID, and a line saying the key reads sales, finance and reviews and can submitSwiftSales Settings, Teams, Harbor Lane Studio: Key ID, Issuer ID, and a line saying the key reads sales, finance and reviews and can submitSwiftSales Settings, Teams, Harbor Lane Studio: Key ID, Issuer ID, and a line saying the key reads sales, finance and reviews and can submit
Your team and its key in SwiftSales. Demo data

What you see once it’s connected

SwiftSales downloads your reports straight from Apple. The Overview answers the daily questions on one card each: proceeds, downloads, new paying customers, active subscriptions and MRR for any period, and when Apple pays next. Home Screen and Lock Screen widgets, the Mac menu bar and one notification a day show the latest day. Introducing SwiftSales has the tour.

SwiftSales on a MacBook Air: the Overview with proceeds, downloads, new paying customers, subscriptions and the next paymentSwiftSales on a MacBook Air: the Overview with proceeds, downloads, new paying customers, subscriptions and the next paymentSwiftSales on a MacBook Air: the Overview with proceeds, downloads, new paying customers, subscriptions and the next paymentSwiftSales on a MacBook Air: the Overview with proceeds, downloads, new paying customers, subscriptions and the next payment
The Overview on the Mac. Demo data

What your agent can do with it

Turn on Agent Access in SwiftSales on your Mac, and Claude Code, Codex, Cursor, Claude or Xcode can use the same key through SwiftSales: answer questions about your sales and reviews, upload a build, run TestFlight, fill in your App Store page, submit for review and release. Each agent starts at Read Only, you choose its level and its apps, and submitting and releasing wait for your approval on your Mac. How to publish an iOS app with Claude Code goes through a release step by step, with and without SwiftSales.

SwiftSalesLet your agent ship your app.
  • Your agent ships your appClaude Code, Codex, Cursor, Claude or Xcode uploads the build, runs TestFlight, fills in your App Store page and submits for review, through SwiftSales on your Mac.
  • Your sales at a glanceA dashboard on iPhone, iPad and Mac, Home Screen and Lock Screen widgets, the Mac menu bar and one notification a day.
  • Your key, your approvalYour team's key stays in your Keychain, and your agent never sees it. Submitting and releasing wait for you to approve them on your Mac.
  • Straight from AppleReports come straight from Apple to your devices and your own iCloud; no server of ours sees them. An agent you connect reads only what you allow and sends it to the AI service it uses.

Free download · 7-day free trial · Lifetime Premium US$9.99

One purchase, no subscription. Family Sharing included.