roblox_api/api/inventory/
v1.rs1use crate::{AssetTypeId, Error, Paging, client::Client};
2use serde::{Deserialize, Serialize};
3
4pub const URL: &str = "https://inventory.roblox.com/v1";
5
6#[repr(u8)]
7#[derive(Clone, Debug, Deserialize, Serialize)]
8pub enum ItemType {
9 Asset = 0,
10 Gamepass,
11 Badge,
12 Bundle,
13}
14
15#[derive(Clone, Debug, Deserialize)]
16pub struct AssetInfo {
17 pub id: u64,
18 #[serde(rename = "type")]
19 pub kind: String,
20 pub name: String,
21 #[serde(rename = "instanceId")]
22 pub instance_id: u64,
23}
24
25#[derive(Clone, Debug, Deserialize)]
26pub struct UserOwnedAssets {
27 #[serde(rename = "nextPageCursor")]
28 pub next_cursor: Option<String>,
29 #[serde(rename = "previousPageCursor")]
30 pub previous_cursor: Option<String>,
31 #[serde(rename = "data")]
32 pub assets: Vec<AssetInfo>,
33}
34
35#[derive(Clone, Debug, Deserialize)]
36pub struct CollectibleInfo {
37 #[serde(rename = "assetId")]
38 pub id: u64,
39 #[serde(rename = "originalPrice")]
40 pub original_price: u64,
41 #[serde(rename = "recentAveragePrice")]
42 pub recent_average_price: u64,
43 #[serde(rename = "assetStock")]
44 pub stock: u64,
45 #[serde(rename = "userAssetId")]
46 pub instance_id: u64,
47 pub name: String,
48 #[serde(rename = "buildersClubMembershipType")]
49 pub premium_membership_type: String,
50 #[serde(rename = "isOnHold")]
51 pub on_hold: bool,
52 #[serde(rename = "serialNumber")]
53 pub serial: Option<u64>,
54}
55
56#[derive(Clone, Debug, Deserialize)]
57pub struct UserOwnedCollectibles {
58 #[serde(rename = "nextPageCursor")]
59 pub next_cursor: Option<String>,
60 #[serde(rename = "previousPageCursor")]
61 pub previous_cursor: Option<String>,
62 #[serde(rename = "data")]
63 pub assets: Vec<CollectibleInfo>,
64}
65
66pub async fn can_view_inventory(client: &mut Client, user_id: u64) -> Result<bool, Error> {
67 let result = client
68 .requestor
69 .client
70 .get(format!("{URL}/users/{user_id}/can-view-inventory"))
71 .headers(client.requestor.default_headers.clone())
72 .send()
73 .await;
74
75 #[derive(Clone, Debug, Deserialize)]
76 struct Response {
77 #[serde(rename = "canView")]
78 can_view: bool,
79 }
80
81 let response = client.validate_response(result).await?;
82 Ok(client
83 .requestor
84 .parse_json::<Response>(response)
85 .await?
86 .can_view)
87}
88
89pub async fn user_owned_assets(
90 client: &mut Client,
91 user_id: u64,
92 id: u64,
93 item_type: ItemType,
94 paging: Paging<'_>,
95) -> Result<UserOwnedAssets, Error> {
96 let item_type = item_type as u8;
97
98 let cursor = match paging.cursor {
99 Some(cursor) => format!("&cursor={cursor}"),
100 None => String::new(),
101 };
102
103 let result = client
104 .requestor
105 .client
106 .get(format!(
107 "{URL}/users/{user_id}/items/{item_type}/{id}{cursor}"
108 ))
109 .headers(client.requestor.default_headers.clone())
110 .send()
111 .await;
112
113 let response = client.validate_response(result).await?;
114 client
115 .requestor
116 .parse_json::<UserOwnedAssets>(response)
117 .await
118}
119
120pub async fn user_owned_collectibles(
121 client: &mut Client,
122 user_id: u64,
123 asset_type_id: Option<AssetTypeId>,
124 paging: Paging<'_>,
125) -> Result<UserOwnedCollectibles, Error> {
126 let limit = paging.limit.unwrap_or(10);
127 let sort_order = paging.order.unwrap_or_default().to_string();
128 let cursor = match paging.cursor {
129 Some(cursor) => format!("&cursor={cursor}"),
130 None => String::new(),
131 };
132
133 let asset_type = match asset_type_id {
134 Some(id) => {
135 let id = id as u8;
136 format!("?assetType={id}")
137 }
138 None => String::new(),
139 };
140
141 let result = client
142 .requestor
143 .client
144 .get(format!(
145 "{URL}/users/{user_id}/assets/collectibles{asset_type}&limit={limit}&sortOrder={sort_order}{cursor}"
146 ))
147 .headers(client.requestor.default_headers.clone())
148 .send()
149 .await;
150
151 let response = client.validate_response(result).await?;
152 client
153 .requestor
154 .parse_json::<UserOwnedCollectibles>(response)
155 .await
156}