
Product
Introducing Reports: An Extensible Reporting Framework for Socket Data
Explore exportable charts for vulnerabilities, dependencies, and usage with Reports, Socket’s new extensible reporting framework.
apple-storekit-api
Advanced tools
Apple StoreKit 2 Server API - Verify purchases, manage subscriptions, handle refunds, and process In-App Purchases with TypeScript support
A TypeScript/JavaScript library for Apple StoreKit API integration. Handles In-App Purchases and subscription management using the latest StoreKit 2 API.
npm install apple-storekit-api
.p8 format (file or content)import { AppleStoreKit } from 'apple-storekit-api';
// Example with file path
const configWithPath = {
issuerId: 'YOUR_ISSUER_ID',
keyId: 'YOUR_KEY_ID',
privateKey: '/path/to/private_key.p8',
bundleId: 'com.yourcompany.yourapp',
environment: 'sandbox' // or 'production'
};
// Example with key content
const configWithContent = {
issuerId: 'YOUR_ISSUER_ID',
keyId: 'YOUR_KEY_ID',
privateKey: '-----BEGIN PRIVATE KEY-----\nYOUR_PRIVATE_KEY_CONTENT\n-----END PRIVATE KEY-----',
bundleId: 'com.yourcompany.yourapp',
environment: 'sandbox' // or 'production'
};
// Example with environment variables (recommended for production)
const configWithEnv = {
issuerId: process.env.APPLE_ISSUER_ID!,
keyId: process.env.APPLE_KEY_ID!,
privateKey: process.env.APPLE_PRIVATE_KEY!,
bundleId: process.env.APPLE_BUNDLE_ID!
// environment is optional, will try production first, then sandbox if fails
};
const storeKit = new AppleStoreKit(configWithPath); // or configWithContent or configWithEnv
// Check subscription status
const status = await storeKit.getSubscriptionStatus('original-transaction-id');
// Verify purchase
const purchase = await storeKit.verifyPurchase('transactionId');
// Get transaction history
const history = await storeKit.getTransactionHistory('transactionId');
// Look up order information
const order = await storeKit.lookupOrder('orderId');
// Check refund status
const refund = await storeKit.refundLookup('transactionId');
// Get current environment
const currentEnv = storeKit.getCurrentEnvironment(); // 'production' or 'sandbox'
Go to App Store Connect:
Create API Key:
Generate and Download Key:
.p8 fileGet Issuer ID:
Bundle ID:
com.yourcompany.yourappThe library accepts the private key in two formats:
File Path: Provide the path to your .p8 file
privateKey: '/absolute/path/to/private_key.p8'
// or
privateKey: './relative/path/to/private_key.p8'
Key Content: Provide the private key content directly
privateKey: '-----BEGIN PRIVATE KEY-----\nYOUR_KEY_CONTENT\n-----END PRIVATE KEY-----'
The library supports automatic environment detection:
Auto Detection (recommended for development):
const config = {
// ... other config
// environment not specified
};
Manual Setting:
const config = {
// ... other config
environment: 'production' // or 'sandbox'
};
const status = await storeKit.getSubscriptionStatus('original-transaction-id');
This method returns the current status of a subscription, including:
SubscriptionStatusType
{
ACTIVE = 1, // The auto-renewable subscription is active
EXPIRED = 2, // The auto-renewable subscription is expired
BILLING_RETRY = 3, // The subscription is in a billing retry period
GRACE_PERIOD = 4, // The subscription is in a Billing Grace Period
REVOKED = 5 // The subscription is revoked (refunded or removed from Family Sharing)
}
verifyPurchase(transactionId: string): Verify a specific purchase using StoreKit 2 APIgetTransactionHistory(transactionId: string): Get transaction historylookupOrder(orderId: string): Look up order detailsrefundLookup(transactionId: string): Check refund statussetAppAccountToken(originalTransactionId: string, appAccountToken: string): Set or update app account token for a transactionsendConsumptionInformation(transactionId: string, consumptionRequest: ConsumptionRequest): Send consumption information for refund decisionssendConsumptionInformationV2(transactionId: string, consumptionRequest: ConsumptionRequest): Send consumption information using V2 APIThe ConsumptionRequest interface includes required and optional fields with their corresponding enum values:
{
customerConsented: boolean; // User consent (must be true)
deliveryStatus: DeliveryStatus; // Delivery success status
sampleContentProvided: boolean; // Free sample provided
}
{
consumptionPercentage?: number; // Percentage consumed (0-100000 milliunits)
refundPreference?: RefundPreference; // Your refund preference
accountTenure?: AccountTenure; // Age of customer's account
appAccountToken?: string; // UUID of user account
consumptionStatus?: ConsumptionStatus; // Extent of consumption
lifetimeDollarsPurchased?: LifetimeDollars; // Total purchases (USD)
lifetimeDollarsRefunded?: LifetimeDollars; // Total refunds (USD)
platform?: Platform; // Purchase platform
playTime?: PlayTime; // App usage time
userStatus?: UserStatus; // Customer account status
}
ConsumptionStatus
{
UNDECLARED = 0, // Use to avoid providing information
NOT_CONSUMED = 1, // Not consumed at all
PARTIALLY_CONSUMED = 2, // Partially consumed
FULLY_CONSUMED = 3 // Fully consumed
}
Platform
{
UNDECLARED = 0, // Use to avoid providing information
APPLE = 1, // Apple platform
NON_APPLE = 2 // Non-Apple platform
}
DeliveryStatus
{
DELIVERED = 'DELIVERED', // Delivered and working properly
UNDELIVERED_QUALITY_ISSUE = 'UNDELIVERED_QUALITY_ISSUE', // Not delivered due to quality issue
UNDELIVERED_WRONG_ITEM = 'UNDELIVERED_WRONG_ITEM', // Wrong item delivered
UNDELIVERED_SERVER_OUTAGE = 'UNDELIVERED_SERVER_OUTAGE', // Not delivered due to server outage
UNDELIVERED_OTHER = 'UNDELIVERED_OTHER' // Not delivered for other reasons
}
AccountTenure
{
UNDECLARED = 0, // Use to avoid providing information
DAYS_0_3 = 1, // 0-3 days
DAYS_3_10 = 2, // 3-10 days
DAYS_10_30 = 3, // 10-30 days
DAYS_30_90 = 4, // 30-90 days
DAYS_90_180 = 5, // 90-180 days
DAYS_180_365 = 6, // 180-365 days
DAYS_OVER_365 = 7 // Over 365 days
}
PlayTime
{
UNDECLARED = 0, // Use to avoid providing information
MINUTES_0_5 = 1, // 0-5 minutes
MINUTES_5_60 = 2, // 5-60 minutes
HOURS_1_6 = 3, // 1-6 hours
HOURS_6_24 = 4, // 6-24 hours
DAYS_1_4 = 5, // 1-4 days
DAYS_4_16 = 6, // 4-16 days
DAYS_OVER_16 = 7 // Over 16 days
}
LifetimeDollars (for both purchased and refunded)
{
UNDECLARED = 0, // Use to avoid providing information
USD_0 = 1, // $0
USD_0_01_49_99 = 2, // $0.01-$49.99
USD_50_99_99 = 3, // $50-$99.99
USD_100_499_99 = 4, // $100-$499.99
USD_500_999_99 = 5, // $500-$999.99
USD_1000_1999_99 = 6, // $1000-$1999.99
USD_OVER_2000 = 7 // Over $2000
}
UserStatus
{
UNDECLARED = 0, // Use to avoid providing information
ACTIVE = 1, // Account is active
SUSPENDED = 2, // Account is suspended
TERMINATED = 3, // Account is terminated
LIMITED_ACCESS = 4 // Account has limited access
}
RefundPreference
{
DECLINE = 'DECLINE', // Prefer to decline the refund
GRANT_FULL = 'GRANT_FULL', // Prefer to grant a full refund
GRANT_PRORATED = 'GRANT_PRORATED' // Prefer to grant a prorated refund
}
Example usage:
const consumptionData = {
// Required fields
customerConsented: true, // Make sure you have obtained valid consent
deliveryStatus: DeliveryStatus.DELIVERED,
sampleContentProvided: true,
// Optional fields
consumptionStatus: ConsumptionStatus.FULLY_CONSUMED,
platform: Platform.APPLE,
appAccountToken: 'YOUR_APP_ACCOUNT_TOKEN',
accountTenure: AccountTenure.DAYS_180_365,
playTime: PlayTime.HOURS_1_6,
lifetimeDollarsRefunded: LifetimeDollars.USD_0,
lifetimeDollarsPurchased: LifetimeDollars.USD_50_99_99,
userStatus: UserStatus.ACTIVE,
refundPreference: RefundPreference.GRANT_FULL
};
await storeKit.sendConsumptionInformation('transactionId', consumptionData);
User Consent Required
InvalidCustomerConsentError if customerConsented is not trueResponse to Refund Requests
CONSUMPTION_REQUEST notificationPrivacy Considerations
Best Practices
UNDECLARED (0) for any field where you don't want to provide informationgetCurrentEnvironment(): Get the current environment being usedgetAccountTenure(date: Date): Calculate the account tenure enum value based on account creation datePrivate Key Storage:
.p8 file to version controlconst config = {
issuerId: process.env.APPLE_ISSUER_ID,
keyId: process.env.APPLE_KEY_ID,
privateKey: process.env.APPLE_PRIVATE_KEY,
bundleId: process.env.APPLE_BUNDLE_ID
};
Environment Management:
This library is compatible with:
Sets or updates the app account token for a transaction made outside of your app:
try {
await storeKit.setAppAccountToken(
'original-transaction-id',
'user-account-uuid'
);
console.log('App account token updated successfully');
} catch (error) {
console.error('Failed to update app account token:', error.message);
}
Note: This method is available in App Store Server API 1.16+ and is useful for:
The library includes comprehensive error handling for API responses. All methods throw descriptive errors that include the original Apple StoreKit API error message when available.
try {
const status = await storeKit.getSubscriptionStatus('originalTransactionId');
} catch (error) {
console.error('StoreKit API Error:', error.message);
}
MIT
git checkout -b feature/amazing-feature)git commit -m 'feat: amazing new feature')git push origin feature/amazing-feature)For issues and feature requests, please use the GitHub issue tracker.
FAQs
Apple StoreKit 2 Server API - Verify purchases, manage subscriptions, handle refunds, and process In-App Purchases with TypeScript support
The npm package apple-storekit-api receives a total of 54 weekly downloads. As such, apple-storekit-api popularity was classified as not popular.
We found that apple-storekit-api demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Explore exportable charts for vulnerabilities, dependencies, and usage with Reports, Socket’s new extensible reporting framework.

Product
Socket for Jira lets teams turn alerts into Jira tickets with manual creation, automated ticketing rules, and two-way sync.

Company News
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.