ワンクリックで
asc-team-key-create
// Create a new App Store Connect Team API Key with Admin permissions, download the one-time .p8 private key, and store it in ~/.blitz. Use when the user needs a new ASC API key for CLI auth, CI/CD, or external tooling.
// Create a new App Store Connect Team API Key with Admin permissions, download the one-time .p8 private key, and store it in ~/.blitz. Use when the user needs a new ASC API key for CLI auth, CI/CD, or external tooling.
| name | asc-team-key-create |
| description | Create a new App Store Connect Team API Key with Admin permissions, download the one-time .p8 private key, and store it in ~/.blitz. Use when the user needs a new ASC API key for CLI auth, CI/CD, or external tooling. |
Use this skill to create a new App Store Connect API Key with Admin permissions via Apple's iris API, download the one-time .p8 private key, and save it to ~/.blitz.
asc auth login, CI/CD pipelines, or external tooling~/.blitz/asc-agent/web-session.json. If no session exists or it has expired (401), call the asc_web_auth MCP tool first — this opens the Apple ID login window in Blitz and captures the session automatically.Before anything else, check if a web session file already exists:
test -f ~/.blitz/asc-agent/web-session.json && echo "SESSION_EXISTS" || echo "NO_SESSION"
NO_SESSION: call the asc_web_auth MCP tool first to open the Apple ID login window in Blitz. Wait for it to complete before proceeding.SESSION_EXISTS: proceed to the next step.Ask the user what they want to name the key (the nickname field in ASC). This is a required input — do not guess or use a default.
Use the following self-contained script. Replace KEY_NAME with the user's chosen name. Do not print or log cookies — they contain sensitive session tokens.
python3 -c "
import json, urllib.request, base64, os, sys, time
KEY_NAME = 'KEY_NAME_HERE'
# Read web session file (silent — never print these)
session_path = os.path.expanduser('~/.blitz/asc-agent/web-session.json')
if not os.path.isfile(session_path):
print('ERROR: No web session found. Call asc_web_auth MCP tool first.')
sys.exit(1)
with open(session_path) as f:
raw = f.read()
store = json.loads(raw)
session = store['sessions'][store['last_key']]
cookie_str = '; '.join(
f'{c[\"name\"]}={c[\"value\"]}'
for cl in session['cookies'].values() for c in cl
if c.get('name') and c.get('value')
)
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'Origin': 'https://appstoreconnect.apple.com',
'Referer': 'https://appstoreconnect.apple.com/',
'Cookie': cookie_str
}
# Step 1: Create the API key
create_body = json.dumps({
'data': {
'type': 'apiKeys',
'attributes': {
'nickname': KEY_NAME,
'roles': ['ADMIN'],
'allAppsVisible': True,
'keyType': 'PUBLIC_API'
}
}
}).encode()
req = urllib.request.Request(
'https://appstoreconnect.apple.com/iris/v1/apiKeys',
data=create_body, method='POST', headers=headers)
try:
resp = urllib.request.urlopen(req)
create_data = json.loads(resp.read().decode())
except urllib.error.HTTPError as e:
body = e.read().decode()
if e.code == 401:
print('ERROR: Session expired. Call asc_web_auth MCP tool to re-authenticate.')
elif e.code == 409:
print(f'ERROR: A key with this name may already exist. Details: {body[:300]}')
else:
print(f'ERROR creating key: HTTP {e.code} — {body[:300]}')
sys.exit(1)
key_id = create_data['data']['id']
can_download = create_data['data']['attributes'].get('canDownload', False)
print(f'Created API key \"{KEY_NAME}\" — Key ID: {key_id}')
if not can_download:
print('ERROR: Key created but canDownload is false. Cannot retrieve private key.')
sys.exit(1)
# Step 2: Download the one-time private key
time.sleep(0.5)
dl_headers = dict(headers)
dl_headers.pop('Content-Type', None)
req = urllib.request.Request(
f'https://appstoreconnect.apple.com/iris/v1/apiKeys/{key_id}?fields%5BapiKeys%5D=privateKey',
method='GET', headers=dl_headers)
try:
resp = urllib.request.urlopen(req)
dl_data = json.loads(resp.read().decode())
except urllib.error.HTTPError as e:
print(f'ERROR downloading key: HTTP {e.code} — {e.read().decode()[:300]}')
sys.exit(1)
pk_b64 = dl_data['data']['attributes'].get('privateKey')
if not pk_b64:
print('ERROR: No privateKey in response. The key may have already been downloaded.')
sys.exit(1)
private_key_pem = base64.b64decode(pk_b64).decode()
# Step 3: Get the issuer ID from the provider relationship
time.sleep(0.35)
req = urllib.request.Request(
f'https://appstoreconnect.apple.com/iris/v1/apiKeys/{key_id}?include=provider',
method='GET', headers=dl_headers)
try:
resp = urllib.request.urlopen(req)
provider_data = json.loads(resp.read().decode())
issuer_id = None
for inc in provider_data.get('included', []):
if inc['type'] == 'contentProviders':
issuer_id = inc['id']
break
if not issuer_id:
issuer_id = provider_data['data']['relationships']['provider']['data']['id']
except Exception:
issuer_id = 'UNKNOWN'
# Step 4: Save .p8 file to ~/.blitz
blitz_dir = os.path.expanduser('~/.blitz')
os.makedirs(blitz_dir, exist_ok=True)
p8_path = os.path.join(blitz_dir, f'AuthKey_{key_id}.p8')
with open(p8_path, 'w') as f:
f.write(private_key_pem)
os.chmod(p8_path, 0o600)
print(f'Private key saved to: {p8_path}')
print(f'Issuer ID: {issuer_id}')
print(f'Key ID: {key_id}')
print()
print('To use with asc CLI:')
print(f' asc auth login --key-id {key_id} --issuer-id {issuer_id} --private-key-path {p8_path}')
print()
print('WARNING: This .p8 file can only be downloaded ONCE. Keep it safe.')
"
After the script succeeds, call the asc_set_credentials MCP tool to pre-fill the Blitz credential form:
asc_set_credentials(issuerId: "<issuer_id>", privateKeyPath: "~/.blitz/AuthKey_<key_id>.p8")
keyId is optional here because Blitz can derive it from Apple's default AuthKey_<KEYID>.p8 filename.
This lets the user visually verify the values and confirm in Blitz.
After the script runs, report:
The web session has expired or doesn't exist. Call the asc_web_auth MCP tool — this opens the Apple ID login window in Blitz and refreshes ~/.blitz/asc-agent/web-session.json automatically. Then retry the key creation script.
A key with the same name may already exist, or another conflict occurred. Try a different name.
The key's one-time download window has passed (canDownload flipped to false). This happens if the key was already downloaded. The key must be revoked and a new one created.
asc web auth login.0600 permissions (owner read/write only).canDownload flips to false permanently. The saved .p8 file is the only copy.allAppsVisible: true (access to all apps in the team).PATCH /iris/v1/apiKeys/{keyId} with {"data": {"type": "apiKeys", "id": "KEY_ID", "attributes": {"isActive": false}}}.Create an App Store Connect app via iris API using web session from Blitz
Attach in-app purchases and subscriptions to an app version for App Store review. Use when the user has IAPs or subscriptions in "Ready to Submit" state that need to be included with a first-time version submission. Works for both first-time and subsequent submissions.
Set up App Store privacy nutrition labels (data collection declarations) for an app. Use when the user needs to declare what data their app collects, how it's used, and whether it's linked to the user. Handles both "no data collected" and full data collection declarations.