Skip to content

Commit 0457d71

Browse files
authored
feat: Add support for App Store Server API v1.15 (#63)
1 parent e72a9a5 commit 0457d71

10 files changed

+128
-4
lines changed

assets/appTransaction.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,7 @@
99
"originalApplicationVersion": "1.1.2",
1010
"deviceVerification": "device_verification_value",
1111
"deviceVerificationNonce": "48ccfa42-7431-4f22-9908-7e88983e105a",
12-
"preorderDate": 1698148700000
12+
"preorderDate": 1698148700000,
13+
"appTransactionId": "71134",
14+
"originalPlatform": "iOS"
1315
}

assets/signedRenewalInfo.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,8 @@
1919
"eligibleWinBackOfferIds": [
2020
"eligible1",
2121
"eligible2"
22-
]
22+
],
23+
"appTransactionId": "71134",
24+
"offerPeriod": "P1Y",
25+
"appAccountToken": "7e3fb20b-4cdb-47cc-936d-99d65f608138"
2326
}

assets/signedTransaction.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,7 @@
2424
"storefrontId":"143441",
2525
"price": 10990,
2626
"currency": "USD",
27-
"offerDiscountType": "PAY_AS_YOU_GO"
27+
"offerDiscountType": "PAY_AS_YOU_GO",
28+
"appTransactionId": "71134",
29+
"offerPeriod": "P1Y"
2830
}

src/primitives/app_transaction.rs

+13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::primitives::environment::Environment;
2+
use crate::primitives::purchase_platform::PurchasePlatform;
23
use chrono::{DateTime, Utc};
34
use serde::{Deserialize, Serialize};
45
use serde_with::formats::Flexible;
@@ -68,6 +69,18 @@ pub struct AppTransaction {
6869
#[serde(rename = "preorderDate")]
6970
#[serde_as(as = "Option<TimestampMilliSeconds<String, Flexible>>")]
7071
pub preorder_date: Option<DateTime<Utc>>,
72+
73+
/// The unique identifier of the app download transaction.
74+
///
75+
/// [appTransactionId](https://developer.apple.com/documentation/storekit/apptransaction/apptransactionid)
76+
#[serde(rename = "appTransactionId")]
77+
pub app_transaction_id: Option<String>,
78+
79+
/// The platform on which the customer originally purchased the app.
80+
///
81+
/// [original_platform](https://developer.apple.com/documentation/storekit/apptransaction/originalplatform)
82+
#[serde(rename = "originalPlatform")]
83+
pub original_platform: Option<PurchasePlatform>,
7184
}
7285

7386
impl AppTransaction {

src/primitives/error_payload.rs

+5
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,11 @@ pub enum APIError {
167167
/// [InvalidTransactionTypeNotSupportedError](https://developer.apple.com/documentation/appstoreserverapi/invalidtransactiontypenotsupportederror)
168168
InvalidTransactionTypeNotSupported = 4000047,
169169

170+
/// An error that indicates the endpoint doesn't support an app transaction ID.
171+
///
172+
/// [AppTransactionIdNotSupportedError](https://developer.apple.com/documentation/appstoreserverapi/apptransactionidnotsupportederror)
173+
AppTransactionIdNotSupportedError = 4000048,
174+
170175
/// An error that indicates the subscription doesn't qualify for a renewal-date extension due to its subscription state.
171176
/// [Documentation](https://developer.apple.com/documentation/appstoreserverapi/subscriptionextensionineligibleerror)
172177
SubscriptionExtensionIneligible = 4030004,

src/primitives/jws_renewal_info_decoded_payload.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use chrono::{DateTime, Utc};
77
use serde::{Deserialize, Serialize};
88
use serde_with::formats::Flexible;
99
use serde_with::TimestampMilliSeconds;
10+
use uuid::Uuid;
1011
use crate::primitives::offer_discount_type::OfferDiscountType;
1112

1213
/// A decoded payload containing subscription renewal information for an auto-renewable subscription.
@@ -124,5 +125,23 @@ pub struct JWSRenewalInfoDecodedPayload {
124125
///
125126
///[eligibleWinBackOfferIds](https://developer.apple.com/documentation/appstoreserverapi/eligiblewinbackofferids)
126127
#[serde(rename = "eligibleWinBackOfferIds")]
127-
pub eligible_win_back_offer_ids: Option<Vec<String>>
128+
pub eligible_win_back_offer_ids: Option<Vec<String>>,
129+
130+
/// The UUID that an app optionally generates to map a customer’s in-app purchase with its resulting App Store transaction.
131+
///
132+
/// [appAccountToken](https://developer.apple.com/documentation/appstoreserverapi/appAccountToken)
133+
#[serde(rename = "appAccountToken")]
134+
pub app_account_token: Option<Uuid>,
135+
136+
/// The unique identifier of the app download transaction.
137+
///
138+
/// [appTransactionId](https://developer.apple.com/documentation/appstoreserverapi/appTransactionId)
139+
#[serde(rename = "appTransactionId")]
140+
pub app_transaction_id: Option<String>,
141+
142+
/// The duration of the offer.
143+
///
144+
/// [offerPeriod](https://developer.apple.com/documentation/appstoreserverapi/offerPeriod)
145+
#[serde(rename = "offerPeriod")]
146+
pub offer_period: Option<String>,
128147
}

src/primitives/jws_transaction_decoded_payload.rs

+12
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,16 @@ pub struct JWSTransactionDecodedPayload {
172172
/// [offerDiscountType](https://developer.apple.com/documentation/appstoreserverapi/offerdiscounttype)
173173
#[serde(rename = "offerDiscountType")]
174174
pub offer_discount_type: Option<OfferDiscountType>,
175+
176+
/// The unique identifier of the app download transaction.
177+
///
178+
/// [appTransactionId](https://developer.apple.com/documentation/appstoreserverapi/appTransactionId)
179+
#[serde(rename = "appTransactionId")]
180+
pub app_transaction_id: Option<String>,
181+
182+
/// The duration of the offer.
183+
///
184+
/// [offerPeriod](https://developer.apple.com/documentation/appstoreserverapi/offerPeriod)
185+
#[serde(rename = "offerPeriod")]
186+
pub offer_period: Option<String>,
175187
}

src/primitives/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,4 @@ pub mod user_status;
5454
pub mod external_purchase_token;
5555
pub mod consumption_request_reason;
5656
pub mod refund_preference;
57+
pub mod purchase_platform;

src/primitives/purchase_platform.rs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use serde::{Deserialize, Serialize};
2+
3+
/// Values that represent Apple platforms.
4+
///
5+
/// [PurchasePlatform](https://developer.apple.com/documentation/storekit/appstore/platform)
6+
#[derive(Debug, Clone, Deserialize, Serialize, Hash, PartialEq, Eq)]
7+
pub enum PurchasePlatform {
8+
#[serde(rename = "iOS")]
9+
IOS,
10+
#[serde(rename = "macOS")]
11+
MacOs,
12+
#[serde(rename = "tvOS")]
13+
TvOs,
14+
#[serde(rename = "visionOS")]
15+
VisionOs,
16+
#[serde(rename = "watchOS")]
17+
WatchOs,
18+
}

src/signed_data_verifier.rs

+49
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ mod tests {
311311
use crate::primitives::offer_type::OfferType;
312312
use crate::primitives::price_increase_status::PriceIncreaseStatus;
313313
use crate::primitives::product_type::ProductType;
314+
use crate::primitives::purchase_platform::PurchasePlatform;
314315
use crate::primitives::revocation_reason::RevocationReason;
315316
use crate::primitives::status::Status;
316317
use crate::primitives::subtype::Subtype;
@@ -595,6 +596,19 @@ mod tests {
595596
.expect("Expect preorder_date")
596597
.timestamp()
597598
);
599+
assert_eq!(
600+
"71134",
601+
app_transaction
602+
.app_transaction_id
603+
.expect("Expect app_transaction_id")
604+
.to_string()
605+
);
606+
assert_eq!(
607+
PurchasePlatform::IOS,
608+
app_transaction
609+
.original_platform
610+
.expect("Expect original_platform")
611+
);
598612
}
599613
Err(err) => panic!("Failed to verify and decode app transaction: {:?}", err),
600614
}
@@ -753,6 +767,20 @@ mod tests {
753767
.offer_discount_type
754768
.expect("Expect offer_discount_type")
755769
);
770+
assert_eq!(
771+
"71134",
772+
transaction
773+
.app_transaction_id
774+
.expect("Expect app_transaction_id")
775+
.to_string()
776+
);
777+
assert_eq!(
778+
"P1Y",
779+
transaction
780+
.offer_period
781+
.expect("Expect offer_period")
782+
.to_string()
783+
);
756784
}
757785
Err(err) => panic!("Failed to verify and decode signed transaction: {:?}", err),
758786
}
@@ -849,6 +877,27 @@ mod tests {
849877
.expect("Expect renewal_date")
850878
.timestamp()
851879
);
880+
assert_eq!(
881+
"71134",
882+
renewal_info
883+
.app_transaction_id
884+
.expect("Expect app_transaction_id")
885+
.to_string()
886+
);
887+
assert_eq!(
888+
"P1Y",
889+
renewal_info
890+
.offer_period
891+
.expect("Expect offer_period")
892+
.to_string()
893+
);
894+
assert_eq!(
895+
"7e3fb20b-4cdb-47cc-936d-99d65f608138",
896+
renewal_info
897+
.app_account_token
898+
.expect("Expect app_account_token")
899+
.to_string()
900+
);
852901
}
853902
Err(err) => panic!("Failed to verify and decode renewal info: {:?}", err),
854903
}

0 commit comments

Comments
 (0)