Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import fetch from 'node-fetch';
import { CheckTestNotificationResponse, CheckTestNotificationResponseValidator } from './models/CheckTestNotificationResponse';
import { ConsumptionRequest } from './models/ConsumptionRequest';
import { ConsumptionRequestV1 } from './models/ConsumptionRequestV1';
import { UpdateAppAccountTokenRequest } from './models/UpdateAppAccountTokenRequest'
import { DefaultConfigurationRequest } from './models/DefaultConfigurationRequest';
import { Environment } from './models/Environment';
Expand All @@ -27,16 +28,19 @@ export { SignedDataVerifier, VerificationException, VerificationStatus } from '.
export { ReceiptUtility } from './receipt_utility'
export { AccountTenure } from "./models/AccountTenure"
export { AlternateProduct } from './models/AlternateProduct'
export { AppData } from './models/AppData'
export { AppTransactionInfoResponse } from './models/AppTransactionInfoResponse';
export { AutoRenewStatus } from './models/AutoRenewStatus'
export { CheckTestNotificationResponse } from './models/CheckTestNotificationResponse'
export { ConsumptionRequest } from './models/ConsumptionRequest'
export { ConsumptionRequestV1 } from './models/ConsumptionRequestV1'
export { UpdateAppAccountTokenRequest } from './models/UpdateAppAccountTokenRequest'
export { ConsumptionStatus } from './models/ConsumptionStatus'
export { Data } from './models/Data'
export { DecodedRealtimeRequestBody } from './models/DecodedRealtimeRequestBody'
export { DefaultConfigurationRequest } from './models/DefaultConfigurationRequest'
export { DeliveryStatus } from './models/DeliveryStatus'
export { DeliveryStatusV1 } from './models/DeliveryStatusV1'
export { Environment } from './models/Environment'
export { ExpirationIntent } from './models/ExpirationIntent'
export { ExtendReasonCode } from './models/ExtendReasonCode'
Expand Down Expand Up @@ -78,8 +82,11 @@ export { PurchasePlatform } from './models/PurchasePlatform'
export { RealtimeRequestBody } from './models/RealtimeRequestBody'
export { RealtimeResponseBody } from './models/RealtimeResponseBody'
export { RefundHistoryResponse } from './models/RefundHistoryResponse'
export { RefundPreference } from './models/RefundPreference'
export { RefundPreferenceV1 } from './models/RefundPreferenceV1'
export { ResponseBodyV2 } from './models/ResponseBodyV2'
export { ResponseBodyV2DecodedPayload } from './models/ResponseBodyV2DecodedPayload'
export { RevocationType } from './models/RevocationType'
export { RevocationReason } from './models/RevocationReason'
export { SendTestNotificationResponse } from './models/SendTestNotificationResponse'
export { Status } from './models/Status'
Expand Down Expand Up @@ -396,15 +403,28 @@ export class AppStoreServerAPIClient {
/**
* Send consumption information about a consumable in-app purchase to the App Store after your server receives a consumption request notification.
*
* @param transactionId The transaction identifier for which youre providing consumption information. You receive this identifier in the CONSUMPTION_REQUEST notification the App Store sends to your server.
* @param transactionId The transaction identifier for which you're providing consumption information. You receive this identifier in the CONSUMPTION_REQUEST notification the App Store sends to your server.
* @param consumptionRequest The request body containing consumption information.
* @throws APIException If a response was returned indicating the request could not be processed
* {@link https://developer.apple.com/documentation/appstoreserverapi/send_consumption_information Send Consumption Information}
* @deprecated Use {@link sendConsumptionInformation} instead
* {@link https://developer.apple.com/documentation/appstoreserverapi/send-consumption-information-v1 Send Consumption Information}
*/
public async sendConsumptionData(transactionId: string, consumptionRequest: ConsumptionRequest): Promise<void> {
public async sendConsumptionData(transactionId: string, consumptionRequest: ConsumptionRequestV1): Promise<void> {
await this.makeRequest("/inApps/v1/transactions/consumption/" + transactionId, "PUT", {}, consumptionRequest, null, 'application/json');
}

/**
* Send consumption information about an In-App Purchase to the App Store after your server receives a consumption request notification.
*
* @param transactionId The transaction identifier for which you're providing consumption information. You receive this identifier in the CONSUMPTION_REQUEST notification the App Store sends to your server's App Store Server Notifications V2 endpoint.
* @param consumptionRequest The request body containing consumption information.
* @throws APIException If a response was returned indicating the request could not be processed
* {@link https://developer.apple.com/documentation/appstoreserverapi/send-consumption-information Send Consumption Information}
*/
public async sendConsumptionInformation(transactionId: string, consumptionRequest: ConsumptionRequest): Promise<void> {
await this.makeRequest("/inApps/v2/transactions/consumption/" + transactionId, "PUT", {}, consumptionRequest, null, 'application/json');
}

/**
* Sets the app account token value for a purchase the customer makes outside your app, or updates its value in an existing transaction.
*
Expand Down
4 changes: 4 additions & 0 deletions jws_verification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ export class SignedDataVerifier {
} else {
environment = Environment.PRODUCTION
}
} else if (decodedJWT.appData) {
appAppleId = decodedJWT.appData.appAppleId
bundleId = decodedJWT.appData.bundleId
environment = decodedJWT.appData.environment
}
this.verifyNotification(bundleId, appAppleId, environment)
return decodedJWT
Expand Down
60 changes: 60 additions & 0 deletions models/AppData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (c) 2025 Apple Inc. Licensed under MIT License.

import { Environment, EnvironmentValidator } from "./Environment"
import { Validator } from "./Validator"

/**
* The object that contains the app metadata and signed app transaction information.
*
* {@link https://developer.apple.com/documentation/appstoreservernotifications/appdata AppData}
*/
export interface AppData {

/**
* The unique identifier of the app that the notification applies to.
*
* {@link https://developer.apple.com/documentation/appstoreservernotifications/appappleid appAppleId}
**/
appAppleId?: number

/**
* The bundle identifier of the app.
*
* {@link https://developer.apple.com/documentation/appstoreservernotifications/bundleid bundleId}
**/
bundleId?: string

/**
* The server environment that the notification applies to, either sandbox or production.
*
* {@link https://developer.apple.com/documentation/appstoreservernotifications/environment environment}
**/
environment?: Environment | string

/**
* App transaction information signed by the App Store, in JSON Web Signature (JWS) format.
*
* {@link https://developer.apple.com/documentation/appstoreservernotifications/jwsapptransaction signedAppTransactionInfo}
**/
signedAppTransactionInfo?: string
}


export class AppDataValidator implements Validator<AppData> {
static readonly environmentValidator = new EnvironmentValidator()
validate(obj: any): obj is AppData {
if ((typeof obj['appAppleId'] !== 'undefined') && !(typeof obj['appAppleId'] === "number")) {
return false
}
if ((typeof obj['bundleId'] !== 'undefined') && !(typeof obj['bundleId'] === "string" || obj['bundleId'] instanceof String)) {
return false
}
if ((typeof obj['environment'] !== 'undefined') && !(AppDataValidator.environmentValidator.validate(obj['environment']))) {
return false
}
if ((typeof obj['signedAppTransactionInfo'] !== 'undefined') && !(typeof obj['signedAppTransactionInfo'] === "string" || obj['signedAppTransactionInfo'] instanceof String)) {
return false
}
return true
}
}
90 changes: 17 additions & 73 deletions models/ConsumptionRequest.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
// Copyright (c) 2023 Apple Inc. Licensed under MIT License.
// Copyright (c) 2025 Apple Inc. Licensed under MIT License.

import { AccountTenure } from "./AccountTenure"
import { ConsumptionStatus } from "./ConsumptionStatus"
import { DeliveryStatus } from "./DeliveryStatus"
import { LifetimeDollarsPurchased } from "./LifetimeDollarsPurchased"
import { LifetimeDollarsRefunded } from "./LifetimeDollarsRefunded"
import { Platform } from "./Platform"
import { PlayTime } from "./PlayTime"
import { RefundPreference } from "./RefundPreference"
import { UserStatus } from "./UserStatus"

/**
* The request body containing consumption information.
* The request body that contains consumption information for an In-App Purchase.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/consumptionrequest ConsumptionRequest}
*/
Expand All @@ -22,82 +15,33 @@ export interface ConsumptionRequest {
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/customerconsented customerConsented}
**/
customerConsented?: boolean

/**
* A value that indicates the extent to which the customer consumed the in-app purchase.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/consumptionstatus consumptionStatus}
**/
consumptionStatus?: ConsumptionStatus | number

customerConsented: boolean

/**
* A value that indicates the platform on which the customer consumed the in-app purchase.
* An integer that indicates the percentage, in milliunits, of the In-App Purchase the customer consumed.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/platform platform}
* {@link https://developer.apple.com/documentation/appstoreserverapi/consumptionpercentage consumptionPercentage}
**/
platform?: Platform | number

/**
* A Boolean value that indicates whether you provided, prior to its purchase, a free sample or trial of the content, or information about its functionality.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/samplecontentprovided sampleContentProvided}
**/
sampleContentProvided?: boolean

consumptionPercentage?: number

/**
* A value that indicates whether the app successfully delivered an in-app purchase that works properly.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/deliverystatus deliveryStatus}
**/
deliveryStatus?: DeliveryStatus | number

/**
* The UUID that an app optionally generates to map a customer’s in-app purchase with its resulting App Store transaction.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/appaccounttoken appAccountToken}
**/
appAccountToken?: string

/**
* The age of the customer’s account.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/accounttenure accountTenure}
**/
accountTenure?: AccountTenure | number

/**
* A value that indicates the amount of time that the customer used the app.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/consumptionrequest ConsumptionRequest}
**/
playTime?: PlayTime | number

/**
* A value that indicates the total amount, in USD, of refunds the customer has received, in your app, across all platforms.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/lifetimedollarsrefunded lifetimeDollarsRefunded}
**/
lifetimeDollarsRefunded?: LifetimeDollarsRefunded | number

/**
* A value that indicates the total amount, in USD, of in-app purchases the customer has made in your app, across all platforms.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/lifetimedollarspurchased lifetimeDollarsPurchased}
**/
lifetimeDollarsPurchased?: LifetimeDollarsPurchased | number

deliveryStatus: DeliveryStatus | string

/**
* The status of the customer’s account.
* A value that indicates your preferred outcome for the refund request.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/userstatus userStatus}
* {@link https://developer.apple.com/documentation/appstoreserverapi/refundpreference refundPreference}
**/
userStatus?: UserStatus | number
refundPreference?: RefundPreference | string

/**
* A value that indicates your preference, based on your operational logic, as to whether Apple should grant the refund.
* A Boolean value that indicates whether you provided, prior to its purchase, a free sample or trial of the content, or information about its functionality.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/refundpreference refundPreference}
* {@link https://developer.apple.com/documentation/appstoreserverapi/samplecontentprovided sampleContentProvided}
**/
refundPreference?: RefundPreference | number
}
sampleContentProvided: boolean
}
104 changes: 104 additions & 0 deletions models/ConsumptionRequestV1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright (c) 2023 Apple Inc. Licensed under MIT License.

import { AccountTenure } from "./AccountTenure"
import { ConsumptionStatus } from "./ConsumptionStatus"
import { DeliveryStatusV1 } from "./DeliveryStatusV1"
import { LifetimeDollarsPurchased } from "./LifetimeDollarsPurchased"
import { LifetimeDollarsRefunded } from "./LifetimeDollarsRefunded"
import { Platform } from "./Platform"
import { PlayTime } from "./PlayTime"
import { RefundPreferenceV1 } from "./RefundPreferenceV1"
import { UserStatus } from "./UserStatus"

/**
* The request body containing consumption information.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/consumptionrequestv1 ConsumptionRequestV1}
* @deprecated Use {@link ConsumptionRequest} instead.
*/
export interface ConsumptionRequestV1 {

/**
* A Boolean value that indicates whether the customer consented to provide consumption data to the App Store.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/customerconsented customerConsented}
**/
customerConsented?: boolean

/**
* A value that indicates the extent to which the customer consumed the in-app purchase.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/consumptionstatus consumptionStatus}
**/
consumptionStatus?: ConsumptionStatus | number

/**
* A value that indicates the platform on which the customer consumed the in-app purchase.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/platform platform}
**/
platform?: Platform | number

/**
* A Boolean value that indicates whether you provided, prior to its purchase, a free sample or trial of the content, or information about its functionality.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/samplecontentprovided sampleContentProvided}
**/
sampleContentProvided?: boolean

/**
* A value that indicates whether the app successfully delivered an in-app purchase that works properly.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/deliverystatus deliveryStatus}
**/
deliveryStatus?: DeliveryStatusV1 | number

/**
* The UUID that an app optionally generates to map a customer’s in-app purchase with its resulting App Store transaction.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/appaccounttoken appAccountToken}
**/
appAccountToken?: string

/**
* The age of the customer’s account.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/accounttenure accountTenure}
**/
accountTenure?: AccountTenure | number

/**
* A value that indicates the amount of time that the customer used the app.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/consumptionrequest ConsumptionRequest}
**/
playTime?: PlayTime | number

/**
* A value that indicates the total amount, in USD, of refunds the customer has received, in your app, across all platforms.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/lifetimedollarsrefunded lifetimeDollarsRefunded}
**/
lifetimeDollarsRefunded?: LifetimeDollarsRefunded | number

/**
* A value that indicates the total amount, in USD, of in-app purchases the customer has made in your app, across all platforms.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/lifetimedollarspurchased lifetimeDollarsPurchased}
**/
lifetimeDollarsPurchased?: LifetimeDollarsPurchased | number

/**
* The status of the customer’s account.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/userstatus userStatus}
**/
userStatus?: UserStatus | number

/**
* A value that indicates your preference, based on your operational logic, as to whether Apple should grant the refund.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/refundpreference refundPreference}
**/
refundPreference?: RefundPreferenceV1 | number
}
20 changes: 10 additions & 10 deletions models/DeliveryStatus.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
// Copyright (c) 2023 Apple Inc. Licensed under MIT License.
// Copyright (c) 2025 Apple Inc. Licensed under MIT License.

import { NumberValidator } from "./Validator";
import { StringValidator } from "./Validator";

/**
* A value that indicates whether the app successfully delivered an in-app purchase that works properly.
* A value that indicates whether the app successfully delivered an In-App Purchase that works properly.
*
* {@link https://developer.apple.com/documentation/appstoreserverapi/deliverystatus deliveryStatus}
*/
export enum DeliveryStatus {
DELIVERED_AND_WORKING_PROPERLY = 0,
DID_NOT_DELIVER_DUE_TO_QUALITY_ISSUE = 1,
DELIVERED_WRONG_ITEM = 2,
DID_NOT_DELIVER_DUE_TO_SERVER_OUTAGE = 3,
DID_NOT_DELIVER_DUE_TO_IN_GAME_CURRENCY_CHANGE = 4,
DID_NOT_DELIVER_FOR_OTHER_REASON = 5,
DELIVERED = "DELIVERED",
UNDELIVERED_QUALITY_ISSUE = "UNDELIVERED_QUALITY_ISSUE",
UNDELIVERED_WRONG_ITEM = "UNDELIVERED_WRONG_ITEM",
UNDELIVERED_SERVER_OUTAGE = "UNDELIVERED_SERVER_OUTAGE",
UNDELIVERED_OTHER = "UNDELIVERED_OTHER",
}

export class DeliveryStatusValidator extends NumberValidator {}

export class DeliveryStatusValidator extends StringValidator {}
Loading