Skip to main content

smbcloud_ascapi_pricing/
lib.rs

1//! App Store Connect's
2//! [pricing](https://developer.apple.com/documentation/appstoreconnectapi/app-pricing)
3//! resources: an app's price schedule, and the per-territory prices and
4//! price points that hang off it.
5//!
6//! Everything here is an extension trait on
7//! [`Client`](smbcloud_ascapi_core::Client), because that type belongs to
8//! the core crate and Rust only allows inherent impls in the crate that
9//! defines a type. Import [`prelude`] to get all of them at once.
10//!
11//! # Why this crate exists separately from `aso`
12//!
13//! Reading a price is the one App Metadata question that cannot be
14//! answered by fetching a resource and reading its attributes. An
15//! `appPrices` row carries no money at all — only `manual`, `startDate`
16//! and `endDate`, plus relationships to an `appPricePoint` (which holds
17//! `customerPrice` and `proceeds`) and a `territory` (which holds
18//! `currency`). Three resources have to be joined before a price is
19//! legible, and the join only works if the request asks for
20//! `include=appPricePoint,territory` up front.
21//!
22//! That join is this crate's whole reason for being: callers get
23//! [`app_price::TerritoryPrice`], one flat row per territory with the
24//! money already attached, instead of a JSON:API document they have to
25//! reassemble.
26//!
27//! ```no_run
28//! use smbcloud_ascapi_core::{ApiKey, Client};
29//! use smbcloud_ascapi_pricing::app_price::PriceKind;
30//! use smbcloud_ascapi_pricing::prelude::*;
31//!
32//! # async fn example() -> smbcloud_ascapi_core::Result<()> {
33//! let api_key = ApiKey::from_p8_file("L84N624YQH", "b4e8d369-…", "AuthKey.p8")?;
34//! let client = Client::new(api_key);
35//!
36//! // What the developer actually set, in the base territory.
37//! let manual = client
38//!     .list_app_prices("6751143237", PriceKind::Manual, None)
39//!     .await?;
40//!
41//! // What Apple converted that into for one storefront.
42//! let indonesia = client
43//!     .list_app_prices("6751143237", PriceKind::Automatic, Some("IDN"))
44//!     .await?;
45//! # Ok(())
46//! # }
47//! ```
48//!
49//! # A note on the opaque ids
50//!
51//! `appPrices` and `appPricePoints` ids are base64 of a small JSON object
52//! (`{"s":appId,"t":territory,"p":pricePointId,…}`), so it is tempting to
53//! decode one and skip the `include=` round trip. Don't. Apple documents
54//! these ids as opaque, the shape has no compatibility guarantee, and the
55//! decoded `p` is an internal price-point identifier rather than an
56//! amount — the money still has to come from `appPricePoints`. This crate
57//! always joins through `include=`.
58
59pub mod app_price;
60pub mod app_price_schedule;
61
62/// Every extension trait in this crate, for one glob import.
63pub mod prelude {
64    pub use crate::app_price::AppPricesApi;
65    pub use crate::app_price_schedule::AppPriceSchedulesApi;
66}