app-store-server-api
A Node.js client for the App Store Server API.
Features
- Transaction history, subscription status and order lookup endpoints
- Notification test and history endpoints
- Typed responses (i.e. you get auto-complete for the fields in the response)
- Manages authentication tokens for you
- Helpers to decode JWS items
- Performs certificate validation against Apple's CA.
- Types and helpers for App Store Server Notifications V2
Requirements
Node.js 15.6.0 or newer
Installation
npm install app-store-server-api
Usage
Prerequisites
To get started, you must obtain the following:
A note on the issuer ID:
Apple's documentation currently has incorrect instructions on how to obtain this.
To get your issuer ID, you must create an API key for App Store Connect (not the App Store Server API). Only after creating your first API key will the issuer ID appear.
Create a client
const { AppStoreServerAPI, Environment, decodeRenewalInfo, decodeTransaction, decodeTransactions } = require("app-store-server-api")
import { AppStoreServerAPI, Environment, decodeRenewalInfo, decodeTransaction, decodeTransactions } from "app-store-server-api"
const KEY =
`-----BEGIN PRIVATE KEY-----
MHcCAQEEIPWH5lyoG7Wbzv71ntF6jNvFwwJLKYmPWN/KBD4qJfMcoAoGCCqGSM49
AwEHoUQDQgAEMOlUa/hmyAPU/RUBds6xzDO8QNrTFhFwzm8E4wxDnSAx8R9WOMnD
cVGdtnbLFIdLk8g4S7oAfV/gGILKuc+Vqw==
-----END PRIVATE KEY-----`
const KEY_ID = "ABCD123456"
const ISSUER_ID = "91fa5999-7b54-4363-a2a8-265363fa6cbe"
const APP_BUNDLE_ID = "com.yourcompany.app"
const api = new AppStoreServerAPI(
KEY, KEY_ID, ISSUER_ID, APP_BUNDLE_ID, Environment.Production
)
History
const response = await api.getTransactionHistory(originalTransactionId)
const transactions = await decodeTransactions(response.signedTransactions)
for (let transaction of transactions) {
}
if (response.hasMore) {
const nextResponse = await api.getTransactionHistory(originalTransactionId, { revision: response.revision })
}
The library supports the filter and sort options introduced at WWDC 2022.
See Get Transaction History for a list of available options.
import { ProductTypeParameter, SortParameter } from "app-store-server-api"
const response = await api.getTransactionHistory(originalTransactionId, {
productType: ProductTypeParameter.AutoRenewable,
sort: SortParameter.Descending,
})
Subscription status
const response = await api.getSubscriptionStatuses(originalTransactionId)
const item = response.data[0].lastTransactions.find(item => item.originalTransactionId === originalTransactionId)
const transactionInfo = await decodeTransaction(item.signedTransactionInfo)
const renewalInfo = await decodeRenewalInfo(item.signedRenewalInfo)
Order lookup
import { OrderLookupStatus } from "app-store-server-api"
const response = await api.lookupOrder(orderId)
if (response.status === OrderLookupStatus.Valid) {
const transactions = await decodeTransactions(response.signedTransactions)
}
Request test notification
const response = await api.requestTestNotification()
Get test notification status
const response = await api.getTestNotificationStatus("ae0e2185-a3c6-47e4-b41a-6ef4bc86314e_1656062546521")
Notification history
const response = await api.getNotificationHistory({
startDate: 1654466400000,
endDate: new Date().getTime()
})
if (response.hasMore) {
}
Decoding server notifications
The App Store Server API and App Store Server Notifications (version 2) are closely related and use some of the same types and encoding formats. This library includes a function to help you decode notifications (which will also verify their signature).
import { decodeNotificationPayload, isDecodedNotificationDataPayload, isDecodedNotificationSummaryPayload } from "app-store-server-api"
const payload = await decodeNotificationPayload(signedPayload)
if (payload.data.bundleId === APP_BUNDLE_ID) {
}
if (isDecodedNotificationDataPayload(payload)) {
}
if (isdecodedNotificationSummaryPayload(payload)) {
}
Verifying transactions signed by Xcode
When using StoreKit testing in Xcode, transactions will be signed by a local certificate authority (CA) instead of Apple's.
To verify these you must export the root certificate generated by Xcode and obtain its SHA256 fingerprint.
This can be passed in to the various decoding functions:
import { decodeTransactions, APPLE_ROOT_CA_G3_FINGERPRINT } from "app-store-server-api"
const LOCAL_ROOT_FINGERPRINT = "AA:BB:CC:DD:..."
const fingerprint = (process.env.NODE_ENV === "production") ? APPLE_ROOT_CA_G3_FINGERPRINT : LOCAL_ROOT_FINGERPRINT
const transactions = await decodeTransactions(response.signedTransactions, fingerprint)
Resources
WWDC videos:
License
MIT