Skip to content
 
 

Repository files navigation

npm

@egodigital/appstore-connect

A simplfied library for Node.js 10+ for accessing Apple's App Store Connect API, written in TypeScript.

The module is quite new, so issues and pull requests are very welcome :-)

Install

Execute the following command from your project folder, where your package.json file is stored:

npm install --save @egodigital/appstore-connect

Usage

Get app downloads

import * as fs from 'fs';
import { Client as AppStoreConnectClient, DownloadSalesReportFrequency } from '@egodigital/appstore-connect';

const PRIVATE_KEY = fs.readFileSync(
    '/path/to/your/p8/file'  // downloaded from https://appstoreconnect.apple.com/access/api
);

const CLIENT = AppStoreConnectClient.create({
    apiKey: '<YOUR-API-KEY>',  // s. https://appstoreconnect.apple.com/access/api
    issuerId: '<YOUR-ISSUER-ID>',  // s. https://appstoreconnect.apple.com/access/api
    privateKey: PRIVATE_KEY,
});

const SUMMARY = await CLIENT.getAppDownloads({
    frequency: DownloadSalesReportFrequency.Weekly,
    vendorId: '<YOUR-VENDOR-ID>',  // s. https://appstoreconnect.apple.com/itc/payments_and_financial_reports
});

console.log(
    SUMMARY
);

Wait for build processing to complete

import * as fs from 'fs';
import {BuildPlatformType, BuildProcessingState, ClientOptions, Client} from '@egodigital/appstore-connect';

const privateKey = fs.readFileSync(
    '/path/to/your/p8/file'  // downloaded from https://appstoreconnect.apple.com/access/api
);

const clientOptions: ClientOptions = {
    apiKey: "<YOUR-API-KEY>",
    issuerId: "<YOUR-ISSUER-ID>",
    privateKey
}

const client = Client.create(clientOptions);

const run = async () => {
    const appId = 1543000000;
    const marketingVersion = "1.0.25";
    const buildNumber = 1;
    try {
        await client.waitForBuildProcessingToComplete(appId, BuildPlatformType.IOS, marketingVersion, buildNumber, {
            pollIntervalInSeconds: 10,
            
            // If build status is not valid wait 8 minutes
            // Useful if calling this script directly after ipa was uploaded in order to not use up daily rate limit
            initialDelayInSeconds: 60 * 8,
            maxTries: 3,
            onPollCallback: (state: BuildProcessingState, tries: number) => {
                console.log(`Waiting for build processing to complete. Got status: ${state}. Tries: ${tries}`);
            }
        });

        console.log("I'm done!");
        process.exit(0);
    }catch (e){
        console.log("I failed");
        console.log(e.message);
        process.exit(1);
    }
}

run().then().catch((e: Error) => {
    console.error(`Error: ${e.message}`);
    console.debug(`Stack: ${e.stack}`);
    process.exit(1);
});

Create a version to be released

import * as fs from 'fs';
import {Client, ClientOptions, PlatformType} from '@egodigital/appstore-connect';

const privateKey = fs.readFileSync(
    '/path/to/your/p8/file'  // downloaded from https://appstoreconnect.apple.com/access/api
);

const clientOptions: ClientOptions = {
    apiKey: "<YOUR-API-KEY>",
    issuerId: "<YOUR-ISSUER-ID>",
    privateKey
}

const client = Client.create(clientOptions);

const run = async () => {
    const appId = 1543000000;
    const appStoreVersion = "1.0.25";
    await client.createVersion(appId, appStoreVersion, PlatformType.IOS, {
        copyright: "John Doe, Inc",
    });
}

run().then().catch((e: Error) => {
    console.error(`Error: ${e.message}`);
    console.debug(`Stack: ${e.stack}`);
    process.exit(1);
});

Ensure an app store version to be released exists

import * as fs from 'fs';
import {Client, ClientOptions, PlatformType} from '@egodigital/appstore-connect';

const privateKey = fs.readFileSync(
    '/path/to/your/p8/file'  // downloaded from https://appstoreconnect.apple.com/access/api
);

const clientOptions: ClientOptions = {
    apiKey: "<YOUR-API-KEY>",
    issuerId: "<YOUR-ISSUER-ID>",
    privateKey
}

const client = Client.create(clientOptions);

const run = async () => {
    const appId = 1543000000;
    const appStoreVersion = "1.0.25";
    await client.ensureVersionExists(appId, appStoreVersion, PlatformType.IOS, {
        createOptions: {
            copyright: "John Doe, Inc",
        },
        
        // Updates any unreleased version to have the provided version
        // This is useful in case you want to change the version you are planning to release since apple 
        // does not allow you to have multiple unreleased (pending) versions
        // Only the version number will be updated. None of the create options will be used to update the existing version.
        updateVersionStringIfUnreleasedVersionExists: true
    });
}

run().then().catch((e: Error) => {
    console.error(`Error: ${e.message}`);
    console.debug(`Stack: ${e.stack}`);
    process.exit(1);
});

Attach a build to a version

import * as fs from 'fs';
import {Client, ClientOptions, PlatformType} from '@egodigital/appstore-connect';

const privateKey = fs.readFileSync(
    '/path/to/your/p8/file'  // downloaded from https://appstoreconnect.apple.com/access/api
);

const clientOptions: ClientOptions = {
    apiKey: "<YOUR-API-KEY>",
    issuerId: "<YOUR-ISSUER-ID>",
    privateKey
}

const client = Client.create(clientOptions);

const run = async () => {
    const appId = 1543000000;
    const appStoreVersion = "1.0.25";
    const buildId =  "7935ef82-4acf-11eb-b378-0242ac130002";
    await client.attachBuildIdToVersion(appId,  appStoreVersion, PlatformType.IOS, buildId)
}

run().then().catch((e: Error) => {
    console.error(`Error: ${e.message}`);
    console.debug(`Stack: ${e.stack}`);
    process.exit(1);
});

Attach a build to a version by version Id

import * as fs from 'fs';
import {Client, ClientOptions, PlatformType} from '@egodigital/appstore-connect';

const privateKey = fs.readFileSync(
    '/path/to/your/p8/file'  // downloaded from https://appstoreconnect.apple.com/access/api
);

const clientOptions: ClientOptions = {
    apiKey: "<YOUR-API-KEY>",
    issuerId: "<YOUR-ISSUER-ID>",
    privateKey
}

const client = Client.create(clientOptions);

const run = async () => {
    const appId = 1543000000;
    
    // Not the same as the build pre-release version. Also referred to as the version string
    const appStoreVersion = "1.0.25";
    
    // Also referred to as pre-release version
    const buildMarketingVersion = "1.0.25";
    
    // Also referred to as the build version
    const buildNumber = 2;
    
    const versionId = await client.getVersionId(appId, appStoreVersion, PlatformType.IOS);
    const buildId = await client.getBuildId(appId,  buildMarketingVersion, PlatformType.IOS, buildNumber);
    await client.attachBuildIdToVersionByVersionId(versionId, buildId);
}

run().then().catch((e: Error) => {
    console.error(`Error: ${e.message}`);
    console.debug(`Stack: ${e.stack}`);
    process.exit(1);
});

Attach a build to an external testing group

import * as fs from 'fs';
import {Client, ClientOptions, PlatformType} from '@egodigital/appstore-connect';

const privateKey = fs.readFileSync(
    '/path/to/your/p8/file'  // downloaded from https://appstoreconnect.apple.com/access/api
);

const clientOptions: ClientOptions = {
    apiKey: "<YOUR-API-KEY>",
    issuerId: "<YOUR-ISSUER-ID>",
    privateKey
}

const client = Client.create(clientOptions);

const run = async () => {
    const appId = 1543000000;
    const version = "1.0.25";
    const buildNumber = 2;
    const groupId = "917ed9fe-4ada-11eb-b378-0242ac130002";
    
    await client.addBuildToExternalGroupByGroupId(appId, version, PlatformType.IOS, buildNumber, groupId, {
        notifyBetaTestersThereIsANewBuild: true
    });
}

run().then().catch((e: Error) => {
    console.error(`Error: ${e.message}`);
    console.debug(`Stack: ${e.stack}`);
    process.exit(1);
});

Submit a version for review

import * as fs from 'fs';
import {Client, ClientOptions, PlatformType} from '@egodigital/appstore-connect';

const privateKey = fs.readFileSync(
    '/path/to/your/p8/file'  // downloaded from https://appstoreconnect.apple.com/access/api
);

const clientOptions: ClientOptions = {
    apiKey: "<YOUR-API-KEY>",
    issuerId: "<YOUR-ISSUER-ID>",
    privateKey
}

const client = Client.create(clientOptions);

const run = async () => {
    const appId = 1543000000;
    const version = "1.0.25";
    
    await client.submitForReview(appId, version, PlatformType.IOS);
}

run().then().catch((e: Error) => {
    console.error(`Error: ${e.message}`);
    console.debug(`Stack: ${e.stack}`);
    process.exit(1);
});

Submit a version for review with options

import * as fs from 'fs';
import {Client, ClientOptions, PlatformType, SubmitForReviewOptions, ReleaseType} from '@egodigital/appstore-connect';

const privateKey = fs.readFileSync(
    '/path/to/your/p8/file'  // downloaded from https://appstoreconnect.apple.com/access/api
);

const clientOptions: ClientOptions = {
    apiKey:   "<YOUR-API-KEY>",
    issuerId: "<YOUR-ISSUER-ID>",
    privateKey
}

const client = Client.create(clientOptions);

const run = async () => {
    const appId   = 1543000000;
    const version = "1.0.25";

    const options: SubmitForReviewOptions = {
        autoCreateVersion:      true,
        autoreleaseOnApproval:  true,
        autoAttachBuildId:      "7935ef82-4acf-11eb-b378-0242ac130002",
        releaseNotes:           {
            lang: 'en-CA',
            text: 'Awesome new features. P.S. We love Canada!'
        },
        reviewDetailAttributes: {
            contactEmail:        'imaspy@gmail.com',
            contactFirstName:    'Jason',
            contactLastName:     'Bourne',
            contactPhone:        '786-255-5555',
            demoAccountName:     'mrusername',
            demoAccountPassword: 'hello world',
            demoAccountRequired: true,
            notes:               'Shake the screen to start the demo mode'
        },
        versionAttributes:      {
            copyright:           'Spy Corp',
            earliestReleaseDate: '2020-12-31T17:35:28.603Z',
            releaseType:         ReleaseType.SCHEDULED,
            usesIdfa:            false,
            versionString:       version,
            downloadable:        true
        },
        localizations:          [
            {
                lang:       'en-US',
                attributes: {
                    description:     'The best app of all time',
                    keywords:        'best,app,ever',
                    marketingUrl:    'https://spygear.com/app',
                    promotionalText: 'Spy on anyone with one simple app',
                    supportUrl:      'https://spygear.com/support',
                    whatsNew:        'Awesome new features for US users'
                }
            }
        ]
    }

    await client.submitForReview(appId, version, PlatformType.IOS, options);
}

run().then().catch((e: Error) => {
    console.error(`Error: ${e.message}`);
    console.debug(`Stack: ${e.stack}`);
    process.exit(1);
});

Documentation

Additional API documentation can be found here.

About

API client for Apple App Store Connect API.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages