◉ANTIGRAVITY LABJP
Articles/App Development
▣ App Development/2026-04-15Advanced

Antigravity × App Store Connect API: Complete Automation Guide for Revenue, ASO & Reviews

A hands-on guide to automating App Store Connect with Antigravity. From JWT authentication to sales report fetching, review sentiment analysis, ASO tracking, and a daily Slack dashboard — everything indie developers need to reclaim development time.

App Store Connect APIiOS27ASOreview analysisautomation95Antigravity386Swift8monetization31

✦ Premium Article

Every indie developer knows the routine: open App Store Connect in the morning, check yesterday's sales, skim new reviews, wonder why that keyword ranking dropped. Multiply that by the number of apps you run, and suddenly a significant chunk of your working day disappears into a dashboard that never changes itself.

App Store Connect API has existed since 2018, yet many indie developers never get past the initial JWT authentication hurdle. The official documentation is comprehensive but scattered, and the authentication mechanism — signing tokens with an EC private key — feels unfamiliar compared to standard OAuth flows. This guide uses Antigravity as your AI coding partner to cut through that friction, walking you through authentication, sales automation, review monitoring, and a morning dashboard that runs without you.

What the App Store Connect API Can Actually Do

Before diving into code, it helps to understand the API's scope. The three areas most valuable to indie developers are:

Sales and Trends Reports: Daily, weekly, and monthly revenue broken down by country, product type, and app. Unlike the App Store Connect dashboard (limited to 365 days), the API gives you your entire sales history in a structured format suitable for long-term trend analysis.

Customer Reviews: Fetch all reviews, filter by rating or territory, and post responses — all programmatically. The key operational use case is detecting low-rated reviews within hours rather than stumbling on them the next day.

App Analytics: Impression counts, page view rates, conversion funnels, and source attribution (search vs. browse vs. referral). This data underlies any serious ASO effort.

With these three pillars automated, you essentially have a personal business intelligence layer running in the background at zero marginal cost.

JWT Authentication: Getting Past the First Wall

App Store Connect uses JWT signed with an EC private key (ES256 algorithm). Unlike bearer tokens you'd get from an OAuth exchange, you generate these locally every time — or more practically, every 20 minutes, since that's Apple's maximum token validity.

Generating Your API Key

Log into App Store Connect, navigate to Users and Access → Integrations → App Store Connect API, and create a new API key. For a read-heavy setup covering sales and reviews, select the "Sales and Trends" and "Customer Support" roles. Write down the following before leaving the page:

  • Issuer ID: A UUID like XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
  • Key ID: A 10-character alphanumeric string
  • .p8 private key file: Download it immediately — it cannot be re-downloaded

Store the .p8 file in a password manager or encrypted vault. If it's compromised, revoke it from App Store Connect immediately and generate a new one.

Implementing the Auth Class

Use this Antigravity prompt to scaffold the authentication layer:

Implement a TypeScript class that generates App Store Connect API JWT tokens.
Requirements:
- Accept issuer_id, key_id, and path to a .p8 private key file
- Sign using ES256 algorithm
- Set token expiry to 20 minutes (Apple's maximum)
- Cache and auto-refresh the token (refresh 2 minutes before expiry)
- Include proper error handling with descriptive messages

The resulting implementation should look like this:

import * as jwt from 'jsonwebtoken';
import * as fs from 'fs';
 
class AppStoreConnectAuth {
  private readonly issuerId: string;
  private readonly keyId: string;
  private readonly privateKey: string;
  private cachedToken: string | null = null;
  private tokenExpiry: number = 0;
 
  constructor(issuerId: string, keyId: string, privateKeyPath: string) {
    this.issuerId = issuerId;
    this.keyId = keyId;
    // Normalize line endings — critical if the key was ever opened on Windows
    this.privateKey = fs.readFileSync(privateKeyPath, 'utf8').replace(/\r\n/g, '\n');
  }
 
  generateToken(): string {
    const now = Math.floor(Date.now() / 1000);
 
    // Return cached token if still valid (with 2-minute buffer)
    if (this.cachedToken && this.tokenExpiry > now + 120) {
      return this.cachedToken;
    }
 
    const payload = {
      iss: this.issuerId,
      iat: now,
      exp: now + 1200, // 20 minutes
      aud: 'appstoreconnect-v1',
    };
 
    try {
      this.cachedToken = jwt.sign(payload, this.privateKey, {
        algorithm: 'ES256',
        header: { alg: 'ES256', kid: this.keyId, typ: 'JWT' },
      });
      this.tokenExpiry = now + 1200;
      return this.cachedToken;
    } catch (error) {
      // Most common cause: malformed private key (missing PEM headers or bad line endings)
      throw new Error(
        `JWT generation failed: ${error instanceof Error ? error.message : String(error)}. ` +
        `Verify the .p8 file includes BEGIN/END PRIVATE KEY headers.`
      );
    }
  }
 
  getAuthHeader(): { Authorization: string } {
    return { Authorization: `Bearer ${this.generateToken()}` };
  }
}
 
// Environment variables (store in .env or CI secrets — never commit)
// ASC_ISSUER_ID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
// ASC_KEY_ID=XXXXXXXXXX
// ASC_VENDOR_NUMBER=XXXXXXXX  (found in Payments and Financial Reports)
// APP_ID=XXXXXXXXXX           (the Apple ID number of your app, not the bundle ID)

Common Mistake 1: Line Ending Corruption

If you open the .p8 file on Windows, copy-paste its contents into a text field, or let your IDE auto-convert line endings, the jsonwebtoken library will throw a PEM_read_bio error. Always read the file directly with fs.readFileSync and apply .replace(/\r\n/g, '\n') as a safeguard.

Common Mistake 2: Wrong aud Claim

The aud field must be the string "appstoreconnect-v1" — not an array, not capitalized differently. Any deviation results in a 401 with an unhelpful "FORBIDDEN" message.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Implement App Store Connect API JWT authentication with ES256 and get a reusable token class that handles auto-renewal
✦Fetch sales, reviews, and ASO metrics in parallel and ship a morning revenue summary to Slack within the GitHub Actions free tier
✦Go from instant negative-review detection to semi-automated replies — the automation patterns indie developers actually need in production
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

▣ App Dev2026-09-19
I Asked for the Whole Quote PDF Tool at Once, Then Split It Into Four Requests
How I moved my client quote paperwork from copy-and-edit to a small PDF tool built with Antigravity, why the first single-shot request had to be thrown away, and the four smaller requests that replaced it, with working code.
▣ App Dev2026-05-25
One Month Splitting Antigravity's Inline Edit and Agent Mode Across Four Wallpaper Apps
A month of notes from running Antigravity's Inline Edit and Agent Mode across four production wallpaper apps — with real counts, the decision rule I wrote into AGENTS.md, a one-pass dSYM fix, and how credit cost factors in.
▣ App Dev2026-05-06
Running a Solo AI Studio with Antigravity × Google AI — Automating Every Stage of App Development as One Developer
How to combine Antigravity 2.0 and Antigravity CLI with Stitch and Veo 3 into a pipeline that takes an app from design through implementation, testing, asset generation, and App Store submission, driven by one developer. Covers where to delegate to agents and the operational pitfalls.