1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// Code generated by @uarp/codegen from spec/openapi.json. DO NOT EDIT.
//!
//! Usage tracking, quota management, and Stripe webhooks
#![allow(unused_imports, clippy::too_many_arguments)]
use reqwest::Method;
use serde::{Deserialize, Serialize};
use crate::client::{Client, Request, NO_BODY, NO_QUERY};
use crate::error::Result;
use crate::generated::models;
use crate::multipart::{field_text, FilePart};
use crate::util::encode_path;
/// Query and header parameters for `getUsage`.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct GetUsageParams {
/// Billing period in YYYY-MM format. Defaults to current month.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub period: Option<String>,
}
/// Query and header parameters for `getUsageTimeseries`.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct GetUsageTimeseriesParams {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metric: Option<models::GetUsageTimeseriesMetric>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub days: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub agent_id: Option<String>,
}
/// Query and header parameters for `handleStripeWebhook`.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct HandleStripeWebhookParams {
/// Stripe webhook signature in `t=\<timestamp\>,v1=\<sig\>` format. Required; missing or
/// invalid signatures are rejected with 400.
#[serde(skip)]
pub stripe_signature: String,
}
/// Usage tracking, quota management, and Stripe webhooks
#[derive(Debug, Clone)]
pub struct BillingApi {
pub(crate) client: Client,
}
impl Client {
/// Usage tracking, quota management, and Stripe webhooks
pub fn billing(&self) -> BillingApi {
BillingApi { client: self.clone() }
}
}
impl BillingApi {
/// Check tenant quota status
///
/// `GET /api/v1/usage/quota`
///
/// Required scopes: `billing:read`.
pub async fn check_quota(&self) -> Result<serde_json::Value> {
self.client
.request_json(Request {
method: Method::GET,
path: "/api/v1/usage/quota".to_string(),
query: NO_QUERY,
body: NO_BODY,
headers: Vec::new(),
idempotent: false,
})
.await
}
/// Create a Stripe Customer Portal session URL
///
/// Returns a Stripe-hosted URL where the customer can manage subscriptions and payment methods.
/// `return_url` must be same-origin as the request; defaults to `\<origin\>/admin/billing`.
///
/// `POST /api/v1/billing/portal-session`
///
/// Required scopes: `billing:write`.
pub async fn create_billing_portal_session(&self, body: &models::CreateBillingPortalSessionRequest) -> Result<models::CreateBillingPortalSessionResponse> {
self.client
.request_json(Request {
method: Method::POST,
path: "/api/v1/billing/portal-session".to_string(),
query: NO_QUERY,
body: Some(body),
headers: Vec::new(),
idempotent: true,
})
.await
}
/// Create Stripe checkout session
///
/// `POST /api/v1/billing/checkout-session`
///
/// Required scopes: `billing:read`.
pub async fn create_checkout_session(&self, body: &models::CreateCheckoutSessionRequest) -> Result<models::CreateCheckoutSessionResponse> {
self.client
.request_json(Request {
method: Method::POST,
path: "/api/v1/billing/checkout-session".to_string(),
query: NO_QUERY,
body: Some(body),
headers: Vec::new(),
idempotent: true,
})
.await
}
/// Get current tenant usage
///
/// `GET /api/v1/usage`
///
/// Required scopes: `billing:read`.
pub async fn get_usage(&self, params: &GetUsageParams) -> Result<serde_json::Value> {
self.client
.request_json(Request {
method: Method::GET,
path: "/api/v1/usage".to_string(),
query: Some(params),
body: NO_BODY,
headers: Vec::new(),
idempotent: false,
})
.await
}
/// Get usage analytics over time
///
/// `GET /api/v1/usage/timeseries`
///
/// Required scopes: `billing:read`.
pub async fn get_usage_timeseries(&self, params: &GetUsageTimeseriesParams) -> Result<models::GetUsageTimeseriesResponse> {
self.client
.request_json(Request {
method: Method::GET,
path: "/api/v1/usage/timeseries".to_string(),
query: Some(params),
body: NO_BODY,
headers: Vec::new(),
idempotent: false,
})
.await
}
/// Handle Stripe webhook events
///
/// Processes incoming Stripe events (invoice.paid, invoice.payment_failed,
/// customer.subscription.deleted). Bypasses normal auth — `Stripe-Signature` header is
/// HMAC-verified against the webhook signing secret.
///
/// `POST /api/v1/webhooks/stripe`
pub async fn handle_stripe_webhook(&self, body: &models::HandleStripeWebhookRequest, params: &HandleStripeWebhookParams) -> Result<serde_json::Value> {
let mut headers: Vec<(&'static str, String)> = Vec::new();
headers.push(("Stripe-Signature", params.stripe_signature.clone()));
self.client
.request_json(Request {
method: Method::POST,
path: "/api/v1/webhooks/stripe".to_string(),
query: NO_QUERY,
body: Some(body),
headers,
idempotent: true,
})
.await
}
/// List available billing plans
///
/// `GET /api/v1/billing/plans`
///
/// Required scopes: `billing:read`.
pub async fn list_billing_plans(&self) -> Result<models::ListBillingPlansResponse> {
self.client
.request_json(Request {
method: Method::GET,
path: "/api/v1/billing/plans".to_string(),
query: NO_QUERY,
body: NO_BODY,
headers: Vec::new(),
idempotent: false,
})
.await
}
}