{"id":18154250,"url":"https://github.com/agisboye/app-store-server-api","last_synced_at":"2025-12-27T00:16:40.203Z","repository":{"id":37099025,"uuid":"436765408","full_name":"agisboye/app-store-server-api","owner":"agisboye","description":"A Node.js client for the App Store Server API","archived":false,"fork":false,"pushed_at":"2025-10-29T20:39:12.000Z","size":151,"stargazers_count":243,"open_issues_count":2,"forks_count":37,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-10-29T21:51:36.354Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/agisboye.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-09T21:24:06.000Z","updated_at":"2025-10-29T20:39:13.000Z","dependencies_parsed_at":"2024-02-02T13:58:53.195Z","dependency_job_id":"3765951a-dc85-4d8e-b791-13fa489e3185","html_url":"https://github.com/agisboye/app-store-server-api","commit_stats":{"total_commits":51,"total_committers":5,"mean_commits":10.2,"dds":0.07843137254901966,"last_synced_commit":"01629ae3b4106c265beadca25723ee142c692ee3"},"previous_names":[],"tags_count":38,"template":false,"template_full_name":null,"purl":"pkg:github/agisboye/app-store-server-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agisboye%2Fapp-store-server-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agisboye%2Fapp-store-server-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agisboye%2Fapp-store-server-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agisboye%2Fapp-store-server-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agisboye","download_url":"https://codeload.github.com/agisboye/app-store-server-api/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agisboye%2Fapp-store-server-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28065965,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-26T02:00:06.189Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-02T04:00:38.015Z","updated_at":"2025-12-27T00:16:40.186Z","avatar_url":"https://github.com/agisboye.png","language":"TypeScript","readme":"# app-store-server-api\nA Node.js client for the [App Store Server API](https://developer.apple.com/documentation/appstoreserverapi).\n\n## Features\n- Transaction history, subscription status and order lookup endpoints\n- Notification test and history endpoints\n- Typed responses (i.e. you get auto-complete for the fields in the response)\n- Manages authentication tokens for you\n- Helpers to decode JWS items\n- Performs certificate validation against Apple's CA.\n- Types and helpers for [App Store Server Notifications V2](https://developer.apple.com/documentation/appstoreservernotifications)\n\n## Requirements\nNode.js 18.12.0 or newer\n\n## Installation\n```bash\nnpm install app-store-server-api\n```\n\n## Usage\n### Prerequisites\nTo get started, you must obtain the following:\n- An [API key](https://developer.apple.com/documentation/appstoreserverapi/creating_api_keys_to_use_with_the_app_store_server_api)\n- The ID of the key\n- Your [issuer ID](https://developer.apple.com/documentation/appstoreserverapi/generating_tokens_for_api_requests)\n\nA note on the issuer ID:\nApple's documentation currently has incorrect instructions on how to obtain this.\nTo get your issuer ID, you must [create an API key for App Store Connect](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api) (not the App Store Server API). Only after creating your first API key will the issuer ID appear.\n\n### Create a client\n```javascript\nconst { AppStoreServerAPI, Environment, decodeRenewalInfo, decodeTransaction, decodeTransactions } = require(\"app-store-server-api\")\n// or\nimport { AppStoreServerAPI, Environment, decodeRenewalInfo, decodeTransaction, decodeTransactions } from \"app-store-server-api\"\n\nconst KEY = \n`-----BEGIN PRIVATE KEY-----\nMHcCAQEEIPWH5lyoG7Wbzv71ntF6jNvFwwJLKYmPWN/KBD4qJfMcoAoGCCqGSM49\nAwEHoUQDQgAEMOlUa/hmyAPU/RUBds6xzDO8QNrTFhFwzm8E4wxDnSAx8R9WOMnD\ncVGdtnbLFIdLk8g4S7oAfV/gGILKuc+Vqw==\n-----END PRIVATE KEY-----`\n\nconst KEY_ID = \"ABCD123456\"\nconst ISSUER_ID = \"91fa5999-7b54-4363-a2a8-265363fa6cbe\"\nconst APP_BUNDLE_ID = \"com.yourcompany.app\"\n\nconst api = new AppStoreServerAPI(\n  KEY, KEY_ID, ISSUER_ID, APP_BUNDLE_ID, Environment.Production\n)\n```\n\n### History\n```javascript\nconst response = await api.getTransactionHistory(originalTransactionId)\n\n// Decoding not only reveals the contents of the transactions but also verifies that they were signed by Apple.\nconst transactions = await decodeTransactions(response.signedTransactions)\n\nfor (let transaction of transactions) {\n  // Do something with your transactions...\n}\n\n// The response contains at most 20 entries. You can check to see if there are more.\nif (response.hasMore) {\n  const nextResponse = await api.getTransactionHistory(originalTransactionId, { revision: response.revision })\n  // ...\n}\n```\n\nThe library supports the filter and sort options introduced at WWDC 2022.\nSee [Get Transaction History](https://developer.apple.com/documentation/appstoreserverapi/get_transaction_history) for a list of available options.\n```javascript\n// Import parameter types\nimport { ProductTypeParameter, SortParameter } from \"app-store-server-api\"\n\nconst response = await api.getTransactionHistory(originalTransactionId, {\n  productType: ProductTypeParameter.AutoRenewable,\n  sort: SortParameter.Descending,\n})\n```\n\n\n### Subscription status\n```javascript\nconst response = await api.getSubscriptionStatuses(originalTransactionId)\n\n// Find the transaction you're looking for\nconst item = response.data[0].lastTransactions.find(item =\u003e item.originalTransactionId === originalTransactionId)\n\nconst transactionInfo = await decodeTransaction(item.signedTransactionInfo)\nconst renewalInfo = await decodeRenewalInfo(item.signedRenewalInfo)\n```\n\n### Order lookup\n```javascript\n// Import the status type\nimport { OrderLookupStatus } from \"app-store-server-api\"\n\nconst response = await api.lookupOrder(orderId)\n\nif (response.status === OrderLookupStatus.Valid) {\n    const transactions = await decodeTransactions(response.signedTransactions)\n    /// ...\n}\n```\n\n### Request test notification\n```javascript\nconst response = await api.requestTestNotification()\n// response.testNotificationToken identifies the notification that will be sent.\n```\n\n### Get test notification status\n```javascript\nconst response = await api.getTestNotificationStatus(\"ae0e2185-a3c6-47e4-b41a-6ef4bc86314e_1656062546521\")\n```\n\n### Notification history\n```javascript\n// Start and end date are required. \n// The earliest supported start date is June 6th (the start of WWDC 2022).\nconst response = await api.getNotificationHistory({\n  startDate: 1654466400000, // June 6th 2022\n  endDate: new Date().getTime()\n})\n\n// Check if there are more items.\nif (response.hasMore) {\n  // Use history.paginationToken to fetch additional items.\n}\n```\n\n### Decoding server notifications\nThe 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).\n\n```javascript\nimport { decodeNotificationPayload, isDecodedNotificationDataPayload, isDecodedNotificationSummaryPayload } from \"app-store-server-api\"\n\n// signedPayload is the body sent by Apple\nconst payload = await decodeNotificationPayload(signedPayload)\n\n// You might want to check that the bundle ID matches that of your app\nif (payload.data.bundleId === APP_BUNDLE_ID) {\n  // Handle the notification...\n}\n\n// Notifications can contain either a data field or a summary field but never both.\n// Use the provided type guards to determine which is present.\nif (isDecodedNotificationDataPayload(payload)) {\n  // payload is of type DecodedNotificationDataPayload\n}\n\nif (isDecodedNotificationSummaryPayload(payload)) {\n  // payload is of type DecodedNotificationSummaryPayload\n}\n```\n\n### Verifying transactions signed by Xcode\nWhen using [StoreKit testing in Xcode](https://developer.apple.com/documentation/xcode/setting-up-storekit-testing-in-xcode), transactions will be signed by a local certificate authority (CA) instead of Apple's.\nTo verify these you must [export the root certificate generated by Xcode](https://developer.apple.com/documentation/xcode/setting-up-storekit-testing-in-xcode#Prepare-to-validate-receipts-in-the-test-environment) and obtain its SHA256 fingerprint.\nThis can be passed in to the various decoding functions:\n```javascript\nimport { decodeTransactions, APPLE_ROOT_CA_G3_FINGERPRINT } from \"app-store-server-api\"\n\nconst LOCAL_ROOT_FINGERPRINT = \"AA:BB:CC:DD:...\"\nconst fingerprint = (process.env.NODE_ENV === \"production\") ? APPLE_ROOT_CA_G3_FINGERPRINT : LOCAL_ROOT_FINGERPRINT\nconst transactions = await decodeTransactions(response.signedTransactions, fingerprint)\n```\n\n## Resources\n- [App Store Server API changelog](https://developer.apple.com/documentation/appstoreserverapi/app_store_server_api_changelog)\n- [App Store Server Notifications changelog](https://developer.apple.com/documentation/appstoreservernotifications/app_store_server_notifications_changelog/)\n- [Apple App Store Server Node.js Library](https://github.com/apple/app-store-server-library-node)\n\nWWDC videos:\n- [Manage in-app purchases on your server](https://developer.apple.com/videos/play/wwdc2021/10174/)\n- [Meet StoreKit 2](https://developer.apple.com/videos/play/wwdc2021/10114/)\n- [Support customers and handle refunds](https://developer.apple.com/videos/play/wwdc2021/10175/)\n- [What's new with in-app purchase](https://developer.apple.com/videos/play/wwdc2022/10007/)\n- [What's new in App Store server APIs](https://developer.apple.com/videos/play/wwdc2023/10141/)\n\n## License\nMIT\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagisboye%2Fapp-store-server-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagisboye%2Fapp-store-server-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagisboye%2Fapp-store-server-api/lists"}