Skip to main content

quantum_sdk/
credits.rs

1//! Credits — purchase credit packs, check balance, view tiers, and apply for dev program.
2//!
3//! Some endpoints (packs, tiers) do not require authentication and can be
4//! called without an API key.
5
6use serde::{Deserialize, Serialize};
7
8use crate::client::Client;
9use crate::error::Result;
10
11/// A credit pack available for purchase.
12#[derive(Debug, Clone, Deserialize)]
13pub struct CreditPack {
14    /// Unique pack identifier.
15    pub id: String,
16
17    /// Display label (e.g. "$5 Starter").
18    #[serde(default)]
19    pub label: String,
20
21    /// Price in USD.
22    #[serde(default)]
23    pub amount_usd: f64,
24
25    /// Number of credit ticks included.
26    #[serde(default)]
27    pub ticks: i64,
28
29    /// Description.
30    #[serde(default)]
31    pub description: Option<String>,
32
33    /// Whether this is the popular/recommended pack.
34    #[serde(default)]
35    pub popular: Option<bool>,
36}
37
38/// Response from listing credit packs.
39#[derive(Debug, Clone, Deserialize)]
40pub struct CreditPacksResponse {
41    /// Available credit packs.
42    pub packs: Vec<CreditPack>,
43}
44
45/// Request to purchase a credit pack.
46#[derive(Debug, Clone, Serialize)]
47pub struct CreditPurchaseRequest {
48    /// The pack ID to purchase.
49    pub pack_id: String,
50
51    /// URL to redirect to after successful payment.
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub success_url: Option<String>,
54
55    /// URL to redirect to if payment is cancelled.
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub cancel_url: Option<String>,
58}
59
60/// Response from purchasing a credit pack.
61#[derive(Debug, Clone, Deserialize)]
62pub struct CreditPurchaseResponse {
63    /// URL to redirect the user to for payment.
64    pub checkout_url: String,
65}
66
67/// Response from checking credit balance.
68#[derive(Debug, Clone, Deserialize)]
69pub struct CreditBalanceResponse {
70    /// Balance in ticks.
71    pub balance_ticks: i64,
72
73    /// Balance in USD.
74    pub balance_usd: f64,
75}
76
77/// A pricing tier.
78#[derive(Debug, Clone, Deserialize)]
79pub struct CreditTier {
80    /// Tier name.
81    #[serde(default)]
82    pub name: Option<String>,
83
84    /// Minimum balance for this tier.
85    #[serde(default)]
86    pub min_balance: i64,
87
88    /// Discount percentage.
89    #[serde(default)]
90    pub discount_percent: f64,
91
92    /// Additional tier data.
93    #[serde(flatten)]
94    pub extra: serde_json::Value,
95}
96
97/// Response from listing credit tiers.
98#[derive(Debug, Clone, Deserialize)]
99pub struct CreditTiersResponse {
100    /// Available tiers.
101    pub tiers: Vec<CreditTier>,
102}
103
104/// Request to apply for the developer program.
105#[derive(Debug, Clone, Serialize)]
106pub struct DevProgramApplyRequest {
107    /// Description of the intended use case.
108    pub use_case: String,
109
110    /// Company name (optional).
111    #[serde(skip_serializing_if = "Option::is_none")]
112    pub company: Option<String>,
113
114    /// Expected monthly spend in USD (optional).
115    #[serde(skip_serializing_if = "Option::is_none")]
116    pub expected_usd: Option<f64>,
117
118    /// Website URL (optional).
119    #[serde(skip_serializing_if = "Option::is_none")]
120    pub website: Option<String>,
121}
122
123/// Response from dev program application.
124#[derive(Debug, Clone, Deserialize)]
125pub struct DevProgramApplyResponse {
126    /// Status of the application (e.g. "submitted", "approved").
127    pub status: String,
128}
129
130impl Client {
131    /// List available credit packs. No authentication required.
132    pub async fn credit_packs(&self) -> Result<CreditPacksResponse> {
133        let (resp, _meta) = self
134            .get_json::<CreditPacksResponse>("/qai/v1/credits/packs")
135            .await?;
136        Ok(resp)
137    }
138
139    /// Purchase a credit pack. Returns a checkout URL for payment.
140    pub async fn credit_purchase(&self, req: &CreditPurchaseRequest) -> Result<CreditPurchaseResponse> {
141        let (resp, _meta) = self
142            .post_json::<CreditPurchaseRequest, CreditPurchaseResponse>(
143                "/qai/v1/credits/purchase",
144                req,
145            )
146            .await?;
147        Ok(resp)
148    }
149
150    /// Get the current credit balance.
151    pub async fn credit_balance(&self) -> Result<CreditBalanceResponse> {
152        let (resp, _meta) = self
153            .get_json::<CreditBalanceResponse>("/qai/v1/credits/balance")
154            .await?;
155        Ok(resp)
156    }
157
158    /// List available credit tiers. No authentication required.
159    pub async fn credit_tiers(&self) -> Result<CreditTiersResponse> {
160        let (resp, _meta) = self
161            .get_json::<CreditTiersResponse>("/qai/v1/credits/tiers")
162            .await?;
163        Ok(resp)
164    }
165
166    /// Apply for the developer program.
167    pub async fn dev_program_apply(&self, req: &DevProgramApplyRequest) -> Result<DevProgramApplyResponse> {
168        let (resp, _meta) = self
169            .post_json::<DevProgramApplyRequest, DevProgramApplyResponse>(
170                "/qai/v1/credits/dev-program",
171                req,
172            )
173            .await?;
174        Ok(resp)
175    }
176}