Skip to content
3,951 linesCodeBlameRaw
1//! The billing service: what agents cost, charged to the workspace they
2//! worked for.
3//!
4//! A workspace buys credit and each agent run deducts what it cost, plus
5//! g1t's margin. With no credit, no agent starts. Money is held in
6//! millionths of a US dollar, so that a run costing a fraction of a cent is
7//! recorded exactly.
8//!
9//! Each `*Args` struct is the argument of the method of the same name,
10//! served at `POST /rpc/<method>`.
11
12use serde::{Deserialize, Serialize};
13
14use crate::repos::RepoPath;
15use crate::{User, Viewer};
16
17/// Millionths of a US dollar in one dollar.
18pub const MICROS_PER_DOLLAR: i64 = 1_000_000;
19
20/// Whether workspaces are charged for agents at all, and with real money.
21/// `status` takes nothing and returns this.
22#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
23pub struct Status {
24 /// False when no payment provider is configured: nothing is charged,
25 /// and who may run agents is decided some other way.
26 pub enabled: bool,
27 /// False while the payment provider is in its test mode, where cards
28 /// are not real.
29 pub live: bool,
30 /// True while g1t is being built out: runs are recorded, with what
31 /// they cost, but nothing is charged and no credit is needed. Not a
32 /// promise that it stays free.
33 #[serde(default)]
34 pub free: bool,
35}
36
37/// `trial`: a workspace's trial credit, so people can try g1t (its agents on
38/// g1t's hosted models among it) without a key or a card of their own. Each
39/// new workspace gets one grant of usage credit (`TRIAL_WORKSPACE_MICROS`),
40/// made when it first uses something, out of a pool for everyone that
41/// resets each calendar month (`TRIAL_MONTHLY_POOL_MICROS`). When this
42/// month's pool is given out, new grants wait for the next month. Returns
43/// `Trial`.
44#[derive(Debug, Serialize, Deserialize)]
45#[serde(rename_all = "camelCase")]
46pub struct TrialArgs {
47 pub workspace: String,
48 /// Workspaces open to hosted models anyway, whose use is not counted
49 /// against the pool.
50 #[serde(default)]
51 pub exempt: Vec<String>,
52}
53
54#[derive(Clone, Debug, Serialize, Deserialize)]
55#[serde(rename_all = "camelCase")]
56pub struct Trial {
57 /// Whether its agents may use g1t's hosted models on the trial now: it
58 /// has credit left, or this month's pool can still grant it some.
59 pub open: bool,
60 /// What the trial has paid for so far, in millionths of a dollar.
61 pub used_micros: i64,
62 /// Its grant, or what it would be granted.
63 pub limit_micros: i64,
64 /// No longer used: the trial does not end on a date. Kept for older
65 /// readers; always null.
66 pub ends_at: Option<String>,
67 /// Why it is closed: `off` (no trials), `used` (this workspace's grant
68 /// is spent) or `pool` (this month's grants are all given out; see
69 /// `waits_until`). `ended` is no longer sent.
70 pub reason: Option<String>,
71 /// Whether the workspace has its grant already.
72 #[serde(default)]
73 pub granted: bool,
74 /// RFC 3339: when a workspace waiting for a grant can get one, the
75 /// first of next month. Only with reason `pool`.
76 #[serde(default)]
77 pub waits_until: Option<String>,
78}
79
80/// A workspace's standing.
81#[derive(Clone, Debug, Serialize, Deserialize)]
82#[serde(rename_all = "camelCase")]
83pub struct Account {
84 pub workspace: String,
85 /// Credit left, in millionths of a dollar. Can dip below zero by the
86 /// cost of the runs that were under way when it ran out.
87 pub balance_micros: i64,
88 pub status: Status,
89 /// What is added to a run's cost, in percent.
90 pub margin_percent: u32,
91 /// The card g1t charges as the workspace nears its limit and when a
92 /// month closes, if one is on file.
93 #[serde(default)]
94 pub card: Option<Card>,
95}
96
97/// A saved card, as far as it is safe to show.
98#[derive(Clone, Debug, Serialize, Deserialize)]
99#[serde(rename_all = "camelCase")]
100pub struct Card {
101 /// `visa`, `mastercard`, ...
102 pub brand: String,
103 pub last4: String,
104 pub exp_month: u32,
105 pub exp_year: u32,
106}
107
108/// `billing_portal`: Stripe's hosted billing page for the workspace, where
109/// an owner adds or replaces the card, sees invoices and receipts, and sets
110/// the billing email and address. g1t never handles card numbers. Owners
111/// only. Returns `Outcome<Checkout>` (its `url`); Stripe sends them back
112/// to `return_url`.
113#[derive(Debug, Serialize, Deserialize)]
114pub struct BillingPortalArgs {
115 pub actor: User,
116 pub workspace: String,
117 pub return_url: String,
118}
119
120/// `admin_billing_link`: for staff to send a customer: their Stripe billing
121/// page. Returns `Outcome<BillingLink>`.
122#[derive(Debug, Serialize, Deserialize)]
123pub struct AdminBillingLinkArgs {
124 pub workspace: String,
125 pub by: String,
126}
127
128#[derive(Clone, Debug, Serialize, Deserialize)]
129#[serde(rename_all = "camelCase")]
130pub struct BillingLink {
131 /// A one-time session on Stripe's billing page, signed in already.
132 pub portal_url: String,
133 /// The billing page's sign-in page, which does not expire: the
134 /// customer signs in with the email Stripe has for them.
135 pub login_url: Option<String>,
136 pub customer_email: Option<String>,
137 pub expires_note: String,
138}
139
140#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
141#[serde(rename_all = "snake_case")]
142pub enum EntryKind {
143 /// Credit bought with a card.
144 TopUp,
145 /// An agent's run, or a paid feature's usage past its allowance.
146 Usage,
147}
148
149/// One line of a workspace's statement.
150#[derive(Clone, Debug, Serialize, Deserialize)]
151#[serde(rename_all = "camelCase")]
152pub struct LedgerEntry {
153 pub id: String,
154 pub kind: EntryKind,
155 /// Positive for credit added, negative for usage.
156 pub amount_micros: i64,
157 pub description: String,
158 /// For usage: the repository and pull request the agent worked on.
159 pub repo: Option<String>,
160 pub number: Option<u32>,
161 /// For usage: `implement`, `review` or `update`.
162 pub task: Option<String>,
163 /// For usage: the model, by its public name.
164 pub model: Option<String>,
165 /// For usage: `g1t` when g1t paid the model provider, `workspace` when
166 /// the workspace's own account did. Runs on the workspace's own
167 /// provider pay only their sandbox time now, so only older entries
168 /// are `workspace`.
169 #[serde(default = "g1t")]
170 pub billed_to: String,
171 /// For a top-up: the username of whoever paid.
172 pub created_by: Option<String>,
173 /// RFC 3339.
174 pub created_at: String,
175 /// The workspace the line belongs to, which tells an enterprise's
176 /// lines apart.
177 #[serde(default, skip_serializing_if = "Option::is_none")]
178 pub workspace: Option<String>,
179 /// For usage: what the g1t plan's monthly included usage paid of it.
180 /// The entry's `amount_micros` is what is left to pay.
181 #[serde(default)]
182 pub credit_micros: i64,
183 /// For usage: what the workspace's trial credit paid of it.
184 #[serde(default)]
185 pub trial_micros: i64,
186 /// For usage: what g1t's open-source pool paid of it.
187 #[serde(default)]
188 pub oss_micros: i64,
189 /// For usage: what g1t covered itself, such as the part of a free
190 /// workspace's last trial run that went past its trial credit.
191 #[serde(default)]
192 pub given_micros: i64,
193 /// For usage: what the account's discount took off its price. The
194 /// price is `-amount_micros` plus this and what paid for it.
195 #[serde(default)]
196 pub discount_micros: i64,
197 /// For a credit from g1t, and for what of one expired or was revoked:
198 /// its kind.
199 #[serde(default, skip_serializing_if = "Option::is_none")]
200 pub credit_kind: Option<CreditKind>,
201}
202
203fn g1t() -> String {
204 "g1t".to_owned()
205}
206
207/// `account` (`Outcome<Account>`) and `ledger` (`Outcome<Vec<LedgerEntry>>`,
208/// newest first). Members of the workspace only.
209#[derive(Debug, Serialize, Deserialize)]
210pub struct AccountArgs {
211 pub workspace: String,
212 pub viewer: Viewer,
213}
214
215/// `checkout`: prepays usage: money paid in advance, drawn down by usage
216/// after the plan's included usage, which raises what can be used before
217/// work stops by the same amount at once. $25 at the least. By card, with
218/// 3-D Secure; from $1,000 also by bank transfer. Owners of the workspace
219/// only. Returns `Outcome<Checkout>`.
220#[derive(Debug, Serialize, Deserialize)]
221#[serde(rename_all = "camelCase")]
222pub struct CheckoutArgs {
223 pub actor: User,
224 pub workspace: String,
225 /// How much to prepay, in cents.
226 pub amount_cents: u32,
227 /// Where the payment page sends the person afterwards. The payment's
228 /// id is appended as `session`.
229 pub return_url: String,
230 /// `card` (the default) or `bank_transfer` (from $1,000): Stripe gives
231 /// the account details, and the money counts once it arrives.
232 #[serde(default)]
233 pub method: Option<String>,
234}
235
236#[derive(Debug, Serialize, Deserialize)]
237pub struct Checkout {
238 /// The payment page to send the person to.
239 pub url: String,
240}
241
242/// `confirm`: credits a payment once the provider says it was made. Safe
243/// to call any number of times. Returns `Outcome<Account>`.
244#[derive(Debug, Serialize, Deserialize)]
245pub struct ConfirmArgs {
246 pub workspace: String,
247 pub viewer: Viewer,
248 /// The payment's id, as returned to `return_url`.
249 pub session: String,
250}
251
252/// `can_start`: whether a workspace may start an agent now, asked before
253/// anything is opened for it. Returns `Outcome<bool>`: a failure, with the
254/// reason to show, when it has no credit.
255#[derive(Debug, Serialize, Deserialize)]
256pub struct CanStartArgs {
257 pub workspace: String,
258}
259
260/// `start_run`: asks whether a workspace may start an agent, and opens the
261/// run it will be charged for. Called by the runner service. Returns
262/// `Outcome<Option<RunTicket>>`: no ticket when billing is off, a failure
263/// when the workspace has no credit.
264#[derive(Debug, Serialize, Deserialize)]
265pub struct StartRunArgs {
266 pub workspace: String,
267 pub repo: RepoPath,
268 pub number: u32,
269 /// `implement`, `review` or `update`.
270 pub task: String,
271 /// The model, by its public name.
272 pub model: String,
273 /// `workspace` when the run uses the workspace's own model provider.
274 /// The runner, which is TypeScript, sends it as `billedTo`.
275 #[serde(default = "g1t", alias = "billedTo")]
276 pub billed_to: String,
277 /// The model session's id. Through g1t's AI Gateway, settling charges
278 /// the run what the gateway priced its requests at; on the workspace's
279 /// own provider, it is what the proxy counts the run's tokens under,
280 /// for the agent rate.
281 #[serde(default)]
282 pub session: Option<String>,
283 /// `small`, `large` or `frontier`: the tier g1t routed the run to.
284 /// None when the workspace's own provider names its model.
285 #[serde(default)]
286 pub tier: Option<String>,
287}
288
289#[derive(Clone, Debug, Serialize, Deserialize)]
290#[serde(rename_all = "camelCase")]
291pub struct RunTicket {
292 pub run_id: String,
293 /// Lets the sandbox, and nothing else, report what this run cost.
294 pub token: String,
295}
296
297/// `finish_run`: what a run cost, as its sandbox reports it. Charged once.
298/// Returns `Outcome<bool>`.
299#[derive(Debug, Serialize, Deserialize)]
300#[serde(rename_all = "camelCase")]
301pub struct FinishRunArgs {
302 pub run_id: String,
303 pub token: String,
304 /// What the model provider charged, in US dollars.
305 pub cost_usd: f64,
306 #[serde(default)]
307 pub turns: u32,
308 /// The tokens the run used, as the harness counted them from the
309 /// provider's answers. On the workspace's own provider, the agent rate
310 /// is charged on no fewer than these. Absent from older sandboxes.
311 #[serde(default)]
312 pub tokens: Option<RunTokens>,
313}
314
315/// The tokens one run used, by kind.
316#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
317#[serde(rename_all = "camelCase")]
318pub struct RunTokens {
319 #[serde(default)]
320 pub input: u64,
321 #[serde(default)]
322 pub output: u64,
323 #[serde(default)]
324 pub cache_read: u64,
325 #[serde(default)]
326 pub cache_write: u64,
327}
328
329impl RunTokens {
330 /// Every token, of every kind: what the agent rate is charged on.
331 pub fn total(&self) -> u64 {
332 self.input.saturating_add(self.output).saturating_add(self.cache_read).saturating_add(self.cache_write)
333 }
334}
335
336
337/// `usage`: what a workspace's agents cost over a period, broken down.
338/// Members only. Returns `Outcome<Usage>`.
339#[derive(Debug, Serialize, Deserialize)]
340pub struct UsageArgs {
341 pub workspace: String,
342 pub viewer: Viewer,
343 /// RFC 3339: the start of the period. The period runs to now.
344 pub since: String,
345}
346
347/// One slice of usage: what it was for, what it cost, how many runs.
348#[derive(Clone, Debug, Serialize, Deserialize)]
349#[serde(rename_all = "camelCase")]
350pub struct UsageSlice {
351 pub key: String,
352 pub micros: i64,
353 pub runs: u32,
354}
355
356/// What a workspace's agents cost over a period.
357#[derive(Clone, Debug, Serialize, Deserialize)]
358#[serde(rename_all = "camelCase")]
359pub struct Usage {
360 pub since: String,
361 /// Charged, including g1t's margin.
362 pub spent_micros: i64,
363 /// What g1t's usage came to at price, less what was charged: the plan's
364 /// included usage, the trial, a pool or a free period paid it. Usage at
365 /// price is `spent_micros` plus this.
366 #[serde(default)]
367 pub covered_micros: i64,
368 /// What the account's discount took off the price. Usage at price is
369 /// `spent_micros` plus `covered_micros` plus this.
370 #[serde(default)]
371 pub discount_micros: i64,
372 /// The account's discount now, in percent; absent without one. With
373 /// one, the slices measure usage at price.
374 #[serde(default)]
375 pub discount_percent: Option<u32>,
376 /// Usage at price: `spent_micros` plus `covered_micros` plus
377 /// `discount_micros`, from the same ledger lines. The one figure every
378 /// page shows as usage (mission control, the agent fleet, Usage and
379 /// Billing), labelled "usage at price".
380 #[serde(default)]
381 pub price_micros: i64,
382 /// What g1t's model provider charged, before the margin.
383 pub cost_micros: i64,
384 /// What runs on the workspace's own provider cost there, as the harness
385 /// estimated it. Not charged by g1t.
386 pub provider_micros: i64,
387 /// What the runs used, at cost: g1t's models and the workspace's own
388 /// provider together, whatever was charged for them.
389 pub used_micros: i64,
390 /// g1t charges nothing for now. The slices then measure usage at cost,
391 /// since every charge is zero.
392 pub free: bool,
393 pub runs: u32,
394 /// Spend per day (`YYYY-MM-DD`) and task, as `day/task` keys.
395 pub by_day: Vec<UsageSlice>,
396 /// Per task: implement, review, revise, update, plan.
397 pub by_task: Vec<UsageSlice>,
398 /// Per repository, `namespace/name`.
399 pub by_repo: Vec<UsageSlice>,
400 /// The pull requests that cost most, as `namespace/name#number`.
401 pub by_pull: Vec<UsageSlice>,
402 /// Per model, by its public name.
403 pub by_model: Vec<UsageSlice>,
404 /// Credit bought in the period.
405 pub added_micros: i64,
406}
407
408/// `record_tokens`: what one model answer used, added to the day's count
409/// for its run. The model proxy sends it after each answer. For usage
410/// views only: runs are still priced from AI Gateway. Returns
411/// `Outcome<bool>`: false when there was nothing to count.
412#[derive(Debug, Serialize, Deserialize)]
413#[serde(rename_all = "camelCase")]
414pub struct RecordTokensArgs {
415 pub workspace: String,
416 /// The model session's id (`ModelSession::id`), one per run.
417 pub session: String,
418 /// The person the run is for, by username. Absent when nobody asked.
419 #[serde(default)]
420 pub person: Option<String>,
421 pub model: String,
422 /// The tier g1t routed the run to: `small`, `large` or `frontier`.
423 #[serde(default)]
424 pub tier: Option<String>,
425 #[serde(default)]
426 pub input: u64,
427 #[serde(default)]
428 pub output: u64,
429 #[serde(default)]
430 pub cache_read: u64,
431 #[serde(default)]
432 pub cache_write: u64,
433}
434
435/// `token_usage`: the model tokens a workspace's runs used, day by day,
436/// for the whole workspace or for one person. Members only; a member may
437/// ask only for themselves, an owner for anyone. Returns
438/// `Outcome<TokenUsage>`.
439#[derive(Debug, Serialize, Deserialize)]
440pub struct TokenUsageArgs {
441 pub workspace: String,
442 pub viewer: Viewer,
443 /// A username: only the runs for them.
444 #[serde(default)]
445 pub person: Option<String>,
446 /// How many days, to today: 42 when absent, 366 at most.
447 #[serde(default)]
448 pub days: Option<u32>,
449}
450
451/// One day's tokens.
452#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
453pub struct DayTokens {
454 /// `YYYY-MM-DD`, UTC.
455 pub day: String,
456 pub tokens: u64,
457}
458
459/// The model tokens runs used over a window of days.
460#[derive(Clone, Debug, Serialize, Deserialize)]
461#[serde(rename_all = "camelCase")]
462pub struct TokenUsage {
463 /// `YYYY-MM-DD`: the first day counted.
464 pub since: String,
465 pub days: u32,
466 /// Null for the whole workspace.
467 pub person: Option<String>,
468 pub total_tokens: u64,
469 pub input_tokens: u64,
470 pub output_tokens: u64,
471 pub cache_read_tokens: u64,
472 pub cache_write_tokens: u64,
473 /// What those runs were charged, as `usage` measures it.
474 pub cost_micros: i64,
475 /// Days in the window with any tokens.
476 pub active_days: u32,
477 /// Every day in the window, oldest first, zeros included.
478 pub by_day: Vec<DayTokens>,
479}
480
481// --- AI Gateway -------------------------------------------------------------
482//
483// A workspace's own model requests, sent with one of its access tokens to
484// the model proxy (`models.g1t.sh/anthropic` in Anthropic's Messages format,
485// `models.g1t.sh/openai/v1` in OpenAI's Chat Completions format). On g1t's
486// models each request
487// is charged to the workspace at the model's price, with the price book's
488// `gateway_models` markup, drawn from AI credit; on the workspace's own
489// provider key it is only counted.
490
491/// A model the AI Gateway offers on g1t's own key, with its price per
492/// million tokens of each kind. `gateway_models` takes nothing and returns
493/// these, in the order they are shown.
494#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
495#[serde(rename_all = "camelCase")]
496pub struct GatewayModel {
497 /// The provider's own id, such as `claude-sonnet-5-5` or
498 /// `@cf/openai/gpt-oss-120b`. A request names it as it is or with its
499 /// provider in front (`anthropic/claude-sonnet-5-5`,
500 /// `workers-ai/@cf/openai/gpt-oss-120b`).
501 pub model: String,
502 /// For people: `Claude Sonnet 5.5`.
503 pub name: String,
504 /// `anthropic` or `workers-ai`.
505 pub provider: String,
506 /// `chat`, or `embeddings` for a model that only embeds text.
507 #[serde(default = "chat")]
508 pub kind: String,
509 pub input_micros: i64,
510 pub output_micros: i64,
511 pub cache_read_micros: i64,
512 /// Cache writes that live five minutes.
513 pub cache_write_micros: i64,
514 /// Cache writes that live an hour.
515 #[serde(default)]
516 pub cache_write_1h_micros: i64,
517 /// A model priced by the prompt's length: a request whose prompt (its
518 /// input, cache read and cache write tokens) is longer than this many
519 /// tokens is charged entirely at the `over_` prices. 0 for one price.
520 #[serde(default)]
521 pub threshold: u64,
522 #[serde(default)]
523 pub over_input_micros: i64,
524 #[serde(default)]
525 pub over_output_micros: i64,
526 #[serde(default)]
527 pub over_cache_read_micros: i64,
528 #[serde(default)]
529 pub over_cache_write_micros: i64,
530 #[serde(default)]
531 pub over_cache_write_1h_micros: i64,
532}
533
534fn chat() -> String {
535 "chat".to_owned()
536}
537
538fn anthropic_format() -> String {
539 "anthropic".to_owned()
540}
541
542/// `gateway_admit`: whether a workspace's next AI Gateway request may go to
543/// g1t's models. Fails with `payment_required` and what to do when it may
544/// not: over its spend limit, out of AI credit, or not on the plan. Returns
545/// `Outcome<bool>`.
546#[derive(Debug, Serialize, Deserialize)]
547pub struct GatewayAdmitArgs {
548 pub workspace: String,
549}
550
551/// `record_gateway`: one AI Gateway request, logged, and charged when it
552/// went to g1t's models and used tokens. The model proxy sends it after
553/// the answer. `id` makes it idempotent: a request recorded twice is
554/// logged and charged once. Returns `Outcome<bool>`: false when it was
555/// already recorded.
556#[derive(Debug, Serialize, Deserialize)]
557#[serde(rename_all = "camelCase")]
558pub struct RecordGatewayArgs {
559 /// `gw_…`, chosen by the proxy.
560 pub id: String,
561 pub workspace: String,
562 /// The access token's id and name.
563 pub token_id: String,
564 #[serde(default)]
565 pub token_name: Option<String>,
566 pub model: String,
567 #[serde(default)]
568 pub input: u64,
569 #[serde(default)]
570 pub output: u64,
571 #[serde(default)]
572 pub cache_read: u64,
573 /// Every cache write, of either lifetime.
574 #[serde(default)]
575 pub cache_write: u64,
576 /// Of `cache_write`, those that live an hour.
577 #[serde(default)]
578 pub cache_write_hour: u64,
579 /// The HTTP status the caller was answered with.
580 pub status: u16,
581 /// On the workspace's own provider key: counted, never charged.
582 #[serde(default)]
583 pub own_key: bool,
584 /// The format the request was sent in: `anthropic` or `openai`.
585 #[serde(default = "anthropic_format")]
586 pub format: String,
587 /// Who served it: on g1t's key the catalogue's provider (`anthropic`,
588 /// `workers-ai`); on the workspace's own, its connection's provider
589 /// (`openai`, `openai_endpoint`…). Empty when it never got that far.
590 #[serde(default)]
591 pub provider: String,
592 /// On the workspace's own provider: the connection's name.
593 #[serde(default)]
594 pub connection: Option<String>,
595 #[serde(default)]
596 pub streamed: bool,
597 #[serde(default)]
598 pub duration_ms: u64,
599 /// What went wrong, for a request that was refused or failed.
600 #[serde(default)]
601 pub error: Option<String>,
602}
603
604/// `gateway_requests`: a workspace's recent AI Gateway requests, newest
605/// first. Members only. Returns `Outcome<GatewayRequests>`.
606#[derive(Debug, Serialize, Deserialize)]
607pub struct GatewayRequestsArgs {
608 pub workspace: String,
609 pub viewer: Viewer,
610 /// How many, 50 when absent, 200 at most.
611 #[serde(default)]
612 pub limit: Option<u32>,
613 /// Only requests older than this one (a request's `id`), for the next page.
614 #[serde(default)]
615 pub before: Option<String>,
616}
617
618/// One AI Gateway request, as its log keeps it.
619#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
620#[serde(rename_all = "camelCase")]
621pub struct GatewayRequest {
622 pub id: String,
623 /// RFC 3339.
624 pub created_at: String,
625 pub model: String,
626 pub token_id: String,
627 pub token_name: Option<String>,
628 pub input: u64,
629 pub output: u64,
630 pub cache_read: u64,
631 pub cache_write: u64,
632 /// Of `cache_write`, those that live an hour.
633 #[serde(default)]
634 pub cache_write_hour: u64,
635 /// What the tokens cost at the model's price.
636 pub cost_micros: i64,
637 /// What the workspace was charged for it, before included usage and
638 /// credit paid for it: 0 on its own key.
639 pub charged_micros: i64,
640 pub status: u16,
641 pub own_key: bool,
642 /// `anthropic` or `openai`: the format it was sent in.
643 #[serde(default = "anthropic_format")]
644 pub format: String,
645 /// Who served it: `anthropic` or `workers-ai` on g1t's key, the
646 /// connection's provider on the workspace's own.
647 #[serde(default)]
648 pub provider: String,
649 /// On the workspace's own provider: the connection's name.
650 #[serde(default)]
651 pub connection: Option<String>,
652 pub streamed: bool,
653 pub duration_ms: u64,
654 pub error: Option<String>,
655}
656
657/// A page of AI Gateway requests.
658#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
659#[serde(rename_all = "camelCase")]
660pub struct GatewayRequests {
661 pub requests: Vec<GatewayRequest>,
662 /// The `before` for the next page, when there is one.
663 pub next: Option<String>,
664 /// How many days requests are kept.
665 pub retention_days: u32,
666}
667
668/// What a workspace pays a monthly price for. There is one plan, `plan`
669/// ("g1t"): a flat price per workspace, never per person, with included
670/// usage each month, more private storage, and deployments. Never free:
671/// `FREE_WHILE_BUILDING` does not cover it.
672///
673/// `deployments` is not sold on its own any more: it comes with the plan.
674/// A service that asks `has_feature` for it is told whether the workspace
675/// has the plan, and a Deployments subscription bought before the change
676/// keeps working until its period ends.
677#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
678#[serde(rename_all = "snake_case")]
679pub enum Feature {
680 /// The g1t plan. Older readers called it `team`.
681 #[serde(alias = "team")]
682 Plan,
683 /// Previews per pull request and production on g1t.page: part of the
684 /// plan.
685 Deployments,
686 /// The Security and quality activation: the security suite's paid
687 /// features on private repositories, for a monthly price per workspace
688 /// from the price book (`security_activation`). Sold on its own; it
689 /// does not need the plan, and the plan does not include it.
690 Security,
691}
692
693impl Feature {
694 /// What is sold: the plan, and the Security and quality activation.
695 pub const ALL: [Feature; 2] = [Feature::Plan, Feature::Security];
696
697 pub fn as_str(self) -> &'static str {
698 match self {
699 Feature::Plan => "plan",
700 Feature::Deployments => "deployments",
701 Feature::Security => "security",
702 }
703 }
704
705 pub fn parse(name: &str) -> Option<Feature> {
706 match name {
707 "plan" | "team" => Some(Feature::Plan),
708 "deployments" => Some(Feature::Deployments),
709 "security" => Some(Feature::Security),
710 _ => None,
711 }
712 }
713
714 pub fn title(self) -> &'static str {
715 match self {
716 Feature::Plan => "g1t",
717 Feature::Deployments => "Deployments",
718 Feature::Security => "Security and quality",
719 }
720 }
721}
722
723/// What deployments cost g1t, in millionths of a dollar: fallbacks for
724/// when billing's price book cannot be read. Nothing here is an allowance:
725/// on the plan every unit is metered from the first, at cost plus the
726/// margin, and drawn from the plan's included usage before anything is
727/// charged. Projects, previews and the apps behind them are not metered at
728/// all: Cloudflare's Workers for Platforms includes far more scripts than
729/// g1t runs, so an app costs g1t only the requests and CPU it answers with.
730pub mod deployment_costs {
731 /// Workers for Platforms: $0.30 per million requests.
732 pub const MICROS_PER_MILLION_REQUESTS: i64 = 300_000;
733 /// $0.02 per million CPU milliseconds.
734 pub const MICROS_PER_MILLION_CPU_MS: i64 = 20_000;
735 /// What one second of a build's sandbox costs g1t (Cloudflare
736 /// Containers, standard-1: half a vCPU, 4 GiB, 8 GB disk), rounded up,
737 /// as the price keeper measured it on 2026-10-05 (14.5). Only a
738 /// fallback: billing charges builds at the price book's `build_second`,
739 /// which the keeper keeps current.
740 pub const MICROS_PER_BUILD_SECOND: i64 = 15;
741 /// What one custom hostname costs g1t a month (Cloudflare for SaaS):
742 /// $0.10.
743 pub const MICROS_PER_DOMAIN_MONTH: i64 = 100_000;
744}
745
746/// `record_sandbox`: how long one sandbox ran for a workspace, reported by
747/// the runner when it stops. Every sandbox g1t starts for a workspace
748/// (agents, reviews, checks, the merge queue, workflow jobs) is metered by
749/// the second, from the first: recorded once per `reference`, with what it
750/// cost g1t, and charged at the price book's `sandbox_second` price unless
751/// `FREE_WHILE_BUILDING`. Deploy builds are charged by the Deployments plan
752/// instead.
753/// Returns `Outcome<bool>`: false if that reference was recorded before.
754#[derive(Debug, Serialize, Deserialize)]
755#[serde(rename_all = "camelCase")]
756pub struct RecordSandboxArgs {
757 pub workspace: String,
758 pub seconds: u32,
759 /// What ran, e.g. `Checks on acme/api#12`.
760 pub description: String,
761 /// `namespace/name`.
762 pub repo: Option<String>,
763 /// Unique to the run.
764 pub reference: String,
765 /// What ran: `agent`, `check`, `workflow` or `queue`. Decides whether
766 /// g1t's open-source pool may pay for it (checks, workflows and the
767 /// merge queue on public repositories). Absent: not the pool.
768 #[serde(default)]
769 pub kind: Option<ComputeKind>,
770 /// The vCPU-seconds the sandbox used, when it can tell. With it, the
771 /// run is priced on its own CPU (`sandbox_base_second` per second plus
772 /// `sandbox_cpu_second` per vCPU-second); without it, at the average
773 /// (`sandbox_second`).
774 #[serde(default, alias = "cpu_seconds")]
775 pub cpu_seconds: Option<f64>,
776 /// The reservation the work started under, settled with this cost.
777 #[serde(default, alias = "reservation_id")]
778 pub reservation_id: Option<String>,
779 /// It ran on one of the workspace's self-hosted runners: recorded as
780 /// self-hosted time, for the minutes, at $0.
781 #[serde(default, alias = "self_hosted")]
782 pub self_hosted: bool,
783 /// The machine it ran on, by label (`g1t-4core`); absent, the standard
784 /// one. A larger machine's memory and disk cost more each second.
785 #[serde(default)]
786 pub instance: Option<String>,
787}
788
789/// How much a workspace has earned g1t's trust with money, which sets how
790/// far its unpaid usage can go before its work stops.
791#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
792#[serde(rename_all = "snake_case")]
793pub enum Trust {
794 /// No live payment yet: only a little past the free allowances.
795 New,
796 /// Has paid g1t real money: the ceiling grows with what it has paid.
797 Paid,
798 /// Has paid steadily for months, with nothing disputed or declined:
799 /// the ceiling follows its monthly spend, up to $10,000, by itself.
800 Established,
801 /// A ceiling g1t set by hand, after talking to the workspace.
802 Reviewed,
803 /// g1t's own workspaces: no ceiling.
804 Internal,
805}
806
807#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
808#[serde(rename_all = "snake_case")]
809pub enum LimitState {
810 Ok,
811 /// Past 80% of the ceiling.
812 Warning,
813 /// At or past it: no new sandboxes, builds or app requests.
814 Stopped,
815}
816
817/// How far a workspace's unpaid usage has gone this month, and where its
818/// work stops: like Fly's or Cloudflare's limits for new accounts, so no
819/// one runs up costs g1t cannot collect. Usage counts at what it cost g1t
820/// or what it is charged, whichever is more, so it counts while g1t is
821/// free too.
822#[derive(Clone, Debug, Serialize, Deserialize)]
823#[serde(rename_all = "camelCase")]
824pub struct Limit {
825 pub workspace: String,
826 /// The account that pays, whose usage and payments the limit counts:
827 /// the workspace's own, or its enterprise's.
828 #[serde(default)]
829 pub account: String,
830 #[serde(default)]
831 pub account_name: String,
832 pub trust: Trust,
833 /// Usage this month (UTC) less what was paid this month.
834 pub exposure_micros: i64,
835 /// Where work stops: the lower of g1t's ceiling and the owner's own
836 /// spend limit. None for g1t's own workspaces.
837 pub ceiling_micros: Option<i64>,
838 /// The ceiling g1t sets from `trust`.
839 pub trust_ceiling_micros: Option<i64>,
840 /// The owner's own monthly limit, if they set one.
841 pub spend_limit_micros: Option<i64>,
842 pub state: LimitState,
843 /// What to tell people when work is stopped or close to it.
844 pub message: Option<String>,
845 /// Charged this month, which the spend limit is measured against.
846 #[serde(default)]
847 pub spent_micros: i64,
848 /// True while the owners have not chosen a spend limit of their own, so
849 /// the automatic one applies: $200, or twice last month's spend.
850 #[serde(default)]
851 pub default_spend_limit: bool,
852 /// The most the owners may set their own limit to: g1t's ceiling. To
853 /// go past it, they contact g1t.
854 #[serde(default)]
855 pub available_micros: Option<i64>,
856 /// How the ceiling grows from here, in a sentence.
857 #[serde(default)]
858 pub growth: Option<String>,
859 /// Money paid in advance and not used yet. It raises what can be used
860 /// before work stops by the same amount, at once.
861 #[serde(default)]
862 pub prepaid_micros: i64,
863 /// The highest ceiling the workspace has ever had. Owners may set their
864 /// spend limit anywhere up to it (plus what is prepaid) without asking.
865 #[serde(default)]
866 pub max_ceiling_micros: Option<i64>,
867 /// The most the owners may raise the limit to themselves, once, with
868 /// `raise_once`: twice the highest ceiling. None once it is used.
869 #[serde(default)]
870 pub raise_once_micros: Option<i64>,
871 /// When the one-time raise was used, RFC 3339.
872 #[serde(default)]
873 pub raised_at: Option<String>,
874 /// True in a paid workspace's first billing cycle, when the ceiling is
875 /// the starting one (`LIMIT_PAID_START_MICROS`).
876 #[serde(default)]
877 pub first_month: bool,
878 /// The budget's alerts, in percent of the spend limit: some of 50, 75,
879 /// 90 and 100. Each is emailed to the owners once a month.
880 #[serde(default)]
881 pub alert_levels: Vec<u32>,
882 /// Whether usage pauses at the spend limit (the default). Off, the
883 /// limit only alerts; g1t's own ceiling still applies.
884 #[serde(default = "yes")]
885 pub pause_at_limit: bool,
886 /// An HTTPS address told of each budget alert with a JSON POST.
887 #[serde(default)]
888 pub budget_webhook: Option<String>,
889}
890
891fn yes() -> bool {
892 true
893}
894
895/// `limit`: a workspace's limit, for its members. Returns `Outcome<Limit>`.
896#[derive(Debug, Serialize, Deserialize)]
897pub struct LimitArgs {
898 pub workspace: String,
899 pub viewer: Viewer,
900}
901
902/// `check_limit`: the same, for the services that enforce it. Returns
903/// `Outcome<Limit>`.
904#[derive(Debug, Serialize, Deserialize)]
905pub struct CheckLimitArgs {
906 pub workspace: String,
907}
908
909/// `note_pending`: usage this month that will be charged later, such as
910/// app traffic past a plan, so the workspace's limit counts it now. Each
911/// report replaces the last for that workspace, source and month. Called
912/// by the service that meters it. Returns `bool`.
913#[derive(Debug, Serialize, Deserialize)]
914#[serde(rename_all = "camelCase")]
915pub struct NotePendingArgs {
916 pub workspace: String,
917 /// `deployments`, `security` (scans), `context` (search embeddings),
918 /// `storage` or `cache` (actions/cache, plan only). Billing charges
919 /// `security`, `context`, `storage` and `cache` itself once the month
920 /// is over; `deployments` charges its own.
921 pub source: String,
922 /// What it cost g1t so far this month, before the margin.
923 pub cost_micros: i64,
924 /// How much of it, for the Billing page: `1.2 million requests and
925 /// 3.4 million CPU ms`, `2 custom domains`.
926 #[serde(default)]
927 pub detail: Option<String>,
928}
929
930/// `usage_meters`: this month's usage for a workspace, one line per kind
931/// of meter, at what it is charged (cost plus the margin, on the account's
932/// terms) before the plan's included usage, the trial or g1t's pools paid
933/// for any of it. Members only. Returns `Outcome<Vec<MeterUsage>>`.
934#[derive(Debug, Serialize, Deserialize)]
935pub struct UsageMetersArgs {
936 pub workspace: String,
937 pub viewer: Viewer,
938}
939
940/// One kind of meter's usage this month.
941#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
942#[serde(rename_all = "camelCase")]
943pub struct MeterUsage {
944 /// `agents` (agent runs, models and sandboxes for checks, workflows
945 /// and the merge queue), `builds`, `requests` (app requests and CPU),
946 /// `domains`, `git_storage` (git operations and private storage) or
947 /// `search_scans` (search embeddings and security scans).
948 pub key: String,
949 pub label: String,
950 /// At price, before what paid for it.
951 pub micros: i64,
952 /// How much, when it is known: `12 runs`, `41 build minutes`.
953 #[serde(default)]
954 pub quantity: Option<String>,
955}
956
957/// `set_spend_limit`: the owner's own monthly ceiling, under g1t's; None
958/// removes it. Owners only. Returns `Outcome<Limit>`.
959#[derive(Debug, Serialize, Deserialize)]
960#[serde(rename_all = "camelCase")]
961pub struct SetSpendLimitArgs {
962 pub actor: User,
963 pub workspace: String,
964 /// A monthly limit, at most what is available; None goes back to the
965 /// default.
966 pub spend_limit_micros: Option<i64>,
967 /// Use everything available, with no limit of their own.
968 #[serde(default)]
969 pub use_full_limit: bool,
970 /// Use the one-time raise: up to twice the highest ceiling the
971 /// workspace has had, without asking. Once per workspace.
972 #[serde(default, alias = "raiseOnce")]
973 pub raise_once: bool,
974}
975
976/// One metered unit: what it costs g1t, and what it is sold at. The price
977/// is always `cost × (100 + markup) / 100`, so it follows the cost.
978#[derive(Clone, Debug, Serialize, Deserialize)]
979#[serde(rename_all = "camelCase")]
980pub struct Price {
981 /// `sandbox_second`, `build_second`, `app_requests`, `app_cpu`, `app_month`.
982 pub meter: String,
983 pub title: String,
984 pub unit: String,
985 /// Millionths of a dollar per unit; may have a fraction.
986 pub cost_micros: f64,
987 pub markup_percent: u32,
988 pub price_micros: f64,
989 /// `list`: Cloudflare's published price. `cloudflare`: what Cloudflare
990 /// actually billed g1t, measured.
991 pub source: String,
992 /// When it was last checked against Cloudflare's bill.
993 pub checked_at: Option<String>,
994 pub updated_at: String,
995}
996
997impl Price {
998 pub fn price_for(cost_micros: f64, markup_percent: u32) -> f64 {
999 cost_micros * f64::from(100 + markup_percent) / 100.0
1000 }
1001}
1002
1003/// A cost that moved.
1004#[derive(Clone, Debug, Serialize, Deserialize)]
1005#[serde(rename_all = "camelCase")]
1006pub struct PriceChange {
1007 pub meter: String,
1008 pub old_cost_micros: f64,
1009 pub new_cost_micros: f64,
1010 pub markup_percent: u32,
1011 /// The markup before, when the change was to the markup rather than
1012 /// to the cost. Absent when the markup stayed `markup_percent`.
1013 #[serde(default, skip_serializing_if = "Option::is_none")]
1014 pub old_markup_percent: Option<u32>,
1015 pub reason: String,
1016 pub created_at: String,
1017 /// When a change still to come takes effect: a rise is announced
1018 /// before it is charged. Absent for changes already made.
1019 #[serde(default, skip_serializing_if = "Option::is_none")]
1020 pub effective_at: Option<String>,
1021}
1022
1023/// `prices`: every metered price and the recent changes. Public. Returns
1024/// `PriceBook`.
1025#[derive(Clone, Debug, Serialize, Deserialize)]
1026#[serde(rename_all = "camelCase")]
1027pub struct PriceBook {
1028 pub prices: Vec<Price>,
1029 pub changes: Vec<PriceChange>,
1030 /// The margin on model usage, which is charged at what AI Gateway
1031 /// priced each request at.
1032 pub model_margin_percent: u32,
1033 /// Every plan, as it is sold now.
1034 #[serde(default)]
1035 pub plans: Vec<Plan>,
1036 /// What is free, and what pays for it.
1037 #[serde(default)]
1038 pub free: Option<FreeTier>,
1039}
1040
1041/// What g1t gives without a plan, each with what pays for it: a capped
1042/// budget, never an open-ended allowance.
1043#[derive(Clone, Debug, Default, Serialize, Deserialize)]
1044#[serde(rename_all = "camelCase")]
1045pub struct FreeTier {
1046 /// Each new workspace's trial credit, once.
1047 pub trial_workspace_micros: i64,
1048 /// Trial grants each month, in all; new trials wait when it is spent.
1049 pub trial_monthly_pool_micros: i64,
1050 /// g1t's open-source pool each month, and any one repository's share.
1051 pub oss_pool_micros: i64,
1052 pub oss_repo_micros: i64,
1053 /// Private repository storage that is free for every workspace. Past
1054 /// it, the plan pays at cost plus the margin; a free workspace's pushes
1055 /// to private repositories stop instead.
1056 pub free_private_storage_bytes: i64,
1057 /// Days of audit log a free workspace keeps.
1058 pub audit_retention_days: u32,
1059 /// Days of audit log the g1t plan keeps, and g1t's own and enterprise
1060 /// workspaces. Longer is by arrangement, set per account in sudo.
1061 #[serde(default)]
1062 pub plan_audit_retention_days: u32,
1063 /// The smallest amount a card is charged when a month closes; less
1064 /// carries over. Charges at a limit always go through.
1065 pub min_charge_micros: i64,
1066 /// Git operations (clones, fetches and pushes through g1t) that are
1067 /// free for every workspace each month. Past it, the plan pays at cost
1068 /// plus the margin and is never slowed; a free workspace is slowed
1069 /// down, never charged.
1070 #[serde(default)]
1071 pub git_operations_included: u64,
1072 /// A new paid workspace's ceiling in its first month.
1073 #[serde(default)]
1074 pub paid_start_ceiling_micros: i64,
1075 /// The most a one-click goodwill credit can cost g1t.
1076 #[serde(default)]
1077 pub overage_forgive_cost_micros: i64,
1078}
1079
1080/// Who pays: a billing account. Every workspace has one; by default its
1081/// own. An enterprise account pays for several workspaces at once, as
1082/// GitHub Enterprise does: one bill, one limit, one set of terms.
1083#[derive(Clone, Debug, Serialize, Deserialize)]
1084#[serde(rename_all = "camelCase")]
1085pub struct BillingAccount {
1086 /// `ws_<slug>` for a workspace's own account; `ent_…` for an enterprise.
1087 pub id: String,
1088 pub kind: AccountKind,
1089 pub name: String,
1090 pub terms: Terms,
1091 /// The workspaces it pays for.
1092 pub workspaces: Vec<String>,
1093 /// Where an enterprise's invoices go.
1094 #[serde(default)]
1095 pub billing_email: Option<String>,
1096 /// An enterprise's invoices, newest first. Empty for a workspace's own.
1097 #[serde(default)]
1098 pub invoices: Vec<EnterpriseInvoice>,
1099 pub created_at: String,
1100 /// What g1t staff set for the account beyond its terms.
1101 #[serde(default)]
1102 pub allowances: Allowances,
1103}
1104
1105/// Set per account by g1t staff in sudo, on top of its terms.
1106#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
1107#[serde(rename_all = "camelCase")]
1108pub struct Allowances {
1109 /// The g1t plan without paying for its monthly price, such as for a
1110 /// partner. Usage is charged as usual. Comped accounts have it anyway.
1111 #[serde(default, alias = "team")]
1112 pub plan: bool,
1113 /// Each of the account's public repositories' monthly cap on g1t's
1114 /// open-source pool, in place of `OSS_REPO_MICROS`. None: the default.
1115 #[serde(default)]
1116 pub oss_repo_micros: Option<i64>,
1117 /// The trial credit each of its workspaces gets, in place of
1118 /// `TRIAL_WORKSPACE_MICROS`, outside the monthly pool. None: the default.
1119 #[serde(default)]
1120 pub trial_micros: Option<i64>,
1121 /// Agents at once, in place of the plan's (2 in the first month or on
1122 /// the trial, then 10). None: the default.
1123 #[serde(default)]
1124 pub max_concurrent_agents: Option<u32>,
1125 /// One run's spend cap, in place of `RUN_CAP_MICROS` and the owners'
1126 /// own. None: theirs, or the default.
1127 #[serde(default)]
1128 pub run_cap_micros: Option<i64>,
1129 /// What the agents on one issue may spend in all, in place of
1130 /// `ISSUE_CAP_MICROS` and the owners' own. None: theirs, or the default.
1131 #[serde(default)]
1132 pub issue_cap_micros: Option<i64>,
1133 /// Days of audit log its workspaces keep, in place of the plan's (7
1134 /// free, 90 on the plan), longer or shorter. None: the plan's.
1135 #[serde(default)]
1136 pub audit_retention_days: Option<u32>,
1137 /// A hold g1t staff put on new compute, with why. None: no hold.
1138 #[serde(default)]
1139 pub hold: Option<String>,
1140}
1141
1142/// `admin_set_allowances`: the plan on or off without charge, overrides of
1143/// the plan's caps, a hold, and the account's share of g1t's pools.
1144/// Recorded with who and why. Returns `Outcome<BillingAccount>`.
1145#[derive(Debug, Serialize, Deserialize)]
1146pub struct AdminSetAllowancesArgs {
1147 pub id: String,
1148 pub allowances: Allowances,
1149 pub note: String,
1150 pub by: String,
1151}
1152
1153// --- Entitlements, and compute started under a reservation -----------------
1154//
1155// Every service that starts compute (sandboxes for agents, checks,
1156// workflows and the merge queue; builds; models; semantic search) asks
1157// billing first:
1158//
1159// 1. `entitlements { workspace }` says what the workspace may do at all:
1160// its plan, whether it may start compute, its caps, and whether compute
1161// is paused.
1162// 2. `reserve { workspace, repo, public, kind, estimate_micros }` holds the
1163// work's estimated cost against what may pay for it, so that starts at
1164// the same moment cannot overshoot the ceiling together. It answers who
1165// pays first, or refuses with a stable code and a message for the owner.
1166// 3. `settle { reservation_id, actual_micros }` releases the hold once the
1167// work is done. The charge itself goes on the ledger the usual way
1168// (`finish_run`, `record_sandbox`, `charge_feature`, `note_pending`).
1169//
1170// A reservation never settled expires after `RESERVATION_HOURS`.
1171
1172/// A reservation that is never settled stops holding after this long.
1173pub const RESERVATION_HOURS: u64 = 3;
1174/// What a ceiling reads as when there is none (g1t's own workspaces): a
1175/// billion dollars, which JavaScript holds exactly.
1176pub const UNLIMITED_MICROS: i64 = 1_000_000_000_000_000;
1177
1178/// What a workspace pays g1t on, as far as compute is concerned.
1179#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1180#[serde(rename_all = "snake_case")]
1181pub enum PlanKind {
1182 /// No plan: the forge is free; compute only from a trial or g1t's
1183 /// open-source pool, after a card check.
1184 Free,
1185 /// The g1t plan, paid for (or given by g1t staff without its price).
1186 Paid,
1187 /// g1t's own workspaces and Flagon's (comped terms): the plan without
1188 /// being charged. Usage is still recorded at what it cost.
1189 Internal,
1190 /// Paid for by an enterprise account, invoiced.
1191 Enterprise,
1192}
1193
1194impl PlanKind {
1195 pub fn as_str(self) -> &'static str {
1196 match self {
1197 PlanKind::Free => "free",
1198 PlanKind::Paid => "paid",
1199 PlanKind::Internal => "internal",
1200 PlanKind::Enterprise => "enterprise",
1201 }
1202 }
1203
1204 /// Whether usage past what is included may be charged (on demand).
1205 pub fn on_demand(self) -> bool {
1206 !matches!(self, PlanKind::Free)
1207 }
1208}
1209
1210/// What compute is for.
1211#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1212#[serde(rename_all = "snake_case")]
1213pub enum ComputeKind {
1214 /// An agent's run: its sandbox and its model.
1215 Agent,
1216 /// Checks on a pull request.
1217 Check,
1218 /// A workflow job.
1219 Workflow,
1220 /// The merge queue's checks.
1221 Queue,
1222 /// A deployment's build.
1223 Deploy,
1224 /// Semantic search: embeddings in the context hub.
1225 Embedding,
1226}
1227
1228impl ComputeKind {
1229 pub fn as_str(self) -> &'static str {
1230 match self {
1231 ComputeKind::Agent => "agent",
1232 ComputeKind::Check => "check",
1233 ComputeKind::Workflow => "workflow",
1234 ComputeKind::Queue => "queue",
1235 ComputeKind::Deploy => "deploy",
1236 ComputeKind::Embedding => "embedding",
1237 }
1238 }
1239
1240 /// Whether g1t's open-source pool may pay for it on a public
1241 /// repository: checks, workflows and the merge queue only.
1242 pub fn open_source_pool(self) -> bool {
1243 matches!(self, ComputeKind::Check | ComputeKind::Workflow | ComputeKind::Queue)
1244 }
1245}
1246
1247/// Who pays first for reserved work. What the first source cannot cover
1248/// falls to the next, in this order.
1249#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1250#[serde(rename_all = "snake_case")]
1251pub enum PaidBy {
1252 /// The plan's included usage this month.
1253 Credit,
1254 /// The workspace's one-time trial credit.
1255 Trial,
1256 /// g1t's open-source pool.
1257 Oss,
1258 /// Charged to the workspace, at cost plus the margin.
1259 OnDemand,
1260}
1261
1262/// `entitlements`: what a workspace may do now, for the services that
1263/// start compute and the pages that show it. Takes `EntitlementsArgs`;
1264/// returns `Entitlements`. No viewer: callers decide who sees it.
1265#[derive(Debug, Serialize, Deserialize)]
1266pub struct EntitlementsArgs {
1267 pub workspace: String,
1268}
1269
1270/// `audit_retention`: how many days of audit log each workspace keeps, for
1271/// the events service's daily purge. Takes `AuditRetentionArgs`; returns
1272/// `Vec<AuditRetention>`, one for each workspace asked about.
1273#[derive(Debug, Serialize, Deserialize)]
1274pub struct AuditRetentionArgs {
1275 pub workspaces: Vec<String>,
1276}
1277
1278#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1279pub struct AuditRetention {
1280 pub workspace: String,
1281 pub days: u32,
1282}
1283
1284#[derive(Clone, Debug, Serialize, Deserialize)]
1285#[serde(rename_all = "camelCase")]
1286pub struct Entitlements {
1287 pub workspace: String,
1288 pub plan: PlanKind,
1289 /// May start sandboxes, models, deployments and semantic search at all:
1290 /// paid, internal and enterprise workspaces, or a free one with trial
1291 /// credit left. A free workspace may still use the open-source pool
1292 /// for checks, workflows and the merge queue on public repositories
1293 /// after a card check; `reserve` decides that per start.
1294 pub compute: bool,
1295 /// The one-time trial credit left; 0 if none was granted or it is used.
1296 pub trial_micros_left: i64,
1297 /// A card check has been done. The trial and the open-source pool need
1298 /// it.
1299 pub trial_verified: bool,
1300 /// A paid workspace still in its first billing cycle.
1301 pub first_month: bool,
1302 /// Agents at once: 2 in the first month or on the trial, 10 after;
1303 /// staff can override it.
1304 pub max_concurrent_agents: u32,
1305 /// The longest one run may take: 60 minutes in the first month or on
1306 /// the trial; otherwise the guardrails' own caps (`MAX_MINUTES`).
1307 pub max_run_minutes: u32,
1308 /// One run's spend cap (`RUN_CAP_MICROS`, $2 by default); staff can
1309 /// override it.
1310 pub run_cap_micros: i64,
1311 /// What agents may spend on one issue in all (`ISSUE_CAP_MICROS`, $10
1312 /// by default); the owners can set it (`set_caps`), and staff override.
1313 pub issue_cap_micros: i64,
1314 /// Where on-demand work stops: g1t's ceiling on usage not yet paid
1315 /// for. `UNLIMITED_MICROS` for g1t's own workspaces; 0 for a free one,
1316 /// which has no on-demand usage.
1317 pub ceiling_micros: i64,
1318 /// Usage not yet paid for this month, with prepayment taken off.
1319 pub exposure_micros: i64,
1320 /// Why new compute is paused, for the owner: the limit is reached, a
1321 /// spend spike is waiting for an owner to confirm it, or g1t staff put
1322 /// a hold on it. None when it is not.
1323 pub paused: Option<String>,
1324 // What the workspace's plan gives it, for its pages.
1325 /// What open reservations hold now.
1326 #[serde(default)]
1327 pub held_micros: i64,
1328 /// Paid in advance and not used yet.
1329 #[serde(default)]
1330 pub prepaid_micros: i64,
1331 /// The plan's included usage each month, and what of it is used.
1332 #[serde(default)]
1333 pub included_micros: i64,
1334 #[serde(default)]
1335 pub included_used_micros: i64,
1336 /// How far back the audit log can be read and exported, and what is
1337 /// kept: the plan's days, or what g1t staff set for the account.
1338 pub audit_retention_days: u32,
1339 /// Whether `audit_retention_days` is what staff set for the account
1340 /// rather than the plan's.
1341 #[serde(default)]
1342 pub audit_retention_custom: bool,
1343 /// Private repository storage that is free for every workspace: past
1344 /// it, the plan pays for it and a free workspace's pushes stop.
1345 pub free_private_storage_bytes: i64,
1346 /// The last daily measure of the workspace's private repositories.
1347 pub private_storage_bytes: i64,
1348 /// On a paid plan (not Free): storage past the free amounts below is
1349 /// charged, so nothing is refused for it.
1350 #[serde(default)]
1351 pub has_plan: bool,
1352 /// Package storage free for every workspace, public and private: past
1353 /// it, the plan pays for it and a free workspace's pushes are refused.
1354 #[serde(default)]
1355 pub package_public_free_bytes: i64,
1356 #[serde(default)]
1357 pub package_private_free_bytes: i64,
1358 /// What g1t's open-source pool paid for the workspace this month.
1359 pub oss_paid_micros: i64,
1360 /// Deploy build time this month, every second of it metered.
1361 #[serde(default)]
1362 pub build_seconds_used: u32,
1363 /// Git operations this month, and how many are free for every
1364 /// workspace (past it: metered on the plan, slowed when free).
1365 #[serde(default)]
1366 pub git_operations: u64,
1367 #[serde(default)]
1368 pub git_operations_included: u64,
1369 /// The smallest amount a card is charged when a month closes.
1370 pub min_charge_micros: i64,
1371 /// A spend spike waiting for an owner, or decided.
1372 #[serde(default)]
1373 pub spike: Option<Spike>,
1374 /// Where usage stands against what is included and the limits, from 50%.
1375 #[serde(default)]
1376 pub alerts: Vec<UsageAlert>,
1377}
1378
1379/// One level reached: 50, 75, 90 or 100 percent of something.
1380#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1381#[serde(rename_all = "camelCase")]
1382pub struct UsageAlert {
1383 /// `included` (the plan's included usage), `spend_limit` (the owners'
1384 /// own limit) or `ceiling` (g1t's, on usage not yet paid for).
1385 pub meter: String,
1386 pub level: u32,
1387 pub used_micros: i64,
1388 pub limit_micros: i64,
1389 pub message: String,
1390}
1391
1392/// An hour's spend well above the workspace's usual pace: new compute
1393/// waits until an owner says to keep going.
1394#[derive(Clone, Debug, Serialize, Deserialize)]
1395#[serde(rename_all = "camelCase")]
1396pub struct Spike {
1397 pub id: String,
1398 /// `open` (waiting for an owner), `continued` (an owner said keep
1399 /// going) or `stopped` (an owner said stop).
1400 pub status: String,
1401 /// The hour's spend when it was found, and the usual hour's.
1402 pub hour_micros: i64,
1403 pub average_micros: i64,
1404 pub detected_at: String,
1405 #[serde(default)]
1406 pub decided_by: Option<String>,
1407 #[serde(default)]
1408 pub decided_at: Option<String>,
1409 /// While continued: until when, unless spend doubles again first.
1410 #[serde(default)]
1411 pub until: Option<String>,
1412}
1413
1414/// `reserve`: holds an estimate of a start's cost before the work starts.
1415/// Returns `Outcome<Reservation>`, or a failure whose code says why not:
1416///
1417/// - `paused`: a spend spike waiting for an owner, or a hold.
1418/// - `limit`: the spend limit or g1t's ceiling would be passed.
1419/// - `not_paid`: no plan, and nothing else pays for this kind of work (or
1420/// no card check yet).
1421/// - `trial_used`: the one-time trial is spent.
1422/// - `oss_pool_empty`: the open-source pool, or the repository's share of
1423/// it, is spent this month.
1424///
1425/// The message says exactly what to do, with the page to do it on (such as
1426/// `/acme/-/billing`).
1427#[derive(Debug, Serialize, Deserialize)]
1428#[serde(rename_all = "camelCase")]
1429pub struct ReserveArgs {
1430 pub workspace: String,
1431 pub repo: RepoPath,
1432 /// Whether the repository is public: the open-source pool pays only for
1433 /// public repositories' checks, workflows and merge queue.
1434 pub public: bool,
1435 pub kind: ComputeKind,
1436 /// The most the work is expected to cost g1t, before the margin, in
1437 /// millionths of a dollar (billing adds the margin, as it does to every
1438 /// charge). For an agent, its model's average plus its sandbox for its
1439 /// whole time cap.
1440 #[serde(alias = "estimate_micros")]
1441 pub estimate_micros: i64,
1442 /// An agent run on g1t's hosted models (not the workspace's own
1443 /// provider). Unsaid, an agent run is taken to be one. g1t's daily
1444 /// spend breaker pauses these when g1t is paying for them.
1445 #[serde(default, alias = "hosted_model")]
1446 pub hosted_model: Option<bool>,
1447}
1448
1449#[derive(Clone, Debug, Serialize, Deserialize)]
1450#[serde(rename_all = "camelCase")]
1451pub struct Reservation {
1452 pub id: String,
1453 pub paid_by: PaidBy,
1454 /// What is held, at cost; less than the estimate when a free
1455 /// workspace's last bit of trial credit is all there is.
1456 #[serde(default)]
1457 pub held_micros: i64,
1458 /// RFC 3339: when the hold lapses if never settled.
1459 #[serde(default)]
1460 pub expires_at: String,
1461}
1462
1463/// `settle`: releases a reservation's hold with what the work cost. The
1464/// charge goes on the ledger the usual way. Safe to repeat. Returns
1465/// `Outcome<bool>`: false if it was settled or had lapsed before.
1466#[derive(Debug, Serialize, Deserialize)]
1467#[serde(rename_all = "camelCase")]
1468pub struct SettleArgs {
1469 #[serde(alias = "reservation_id")]
1470 pub reservation_id: String,
1471 /// What the work cost g1t, before the margin.
1472 #[serde(alias = "actual_micros")]
1473 pub actual_micros: i64,
1474}
1475
1476// --- Card checks, the plan, prepayment -------------------------------------
1477
1478/// `card_check`: starts Stripe's page to save and verify a card: a setup
1479/// with 3-D Secure where the card supports it, which the card's bank sees
1480/// as a $0 or $1 authorization that is never charged. The trial and the
1481/// open-source pool need it, and it is the card the plan uses. Owners only.
1482/// Returns `Outcome<Checkout>`; the page's id comes back to `return_url` as
1483/// `session`, for `confirm_card_check`.
1484#[derive(Debug, Serialize, Deserialize)]
1485#[serde(rename_all = "camelCase")]
1486pub struct CardCheckArgs {
1487 pub actor: User,
1488 pub workspace: String,
1489 #[serde(alias = "return_url")]
1490 pub return_url: String,
1491}
1492
1493/// `confirm_card_check`: records the check once Stripe says the card was
1494/// verified, and grants the trial if the month's pool has room and the card
1495/// has not had one before. Safe to repeat. Returns `Outcome<Entitlements>`.
1496#[derive(Debug, Serialize, Deserialize)]
1497pub struct ConfirmCardCheckArgs {
1498 pub workspace: String,
1499 pub viewer: Viewer,
1500 pub session: String,
1501}
1502
1503// --- Limits: raising them, and spikes ---------------------------------------
1504
1505/// A request to g1t: a higher limit, or help with usage that went past
1506/// what was meant.
1507#[derive(Clone, Debug, Serialize, Deserialize)]
1508#[serde(rename_all = "camelCase")]
1509pub struct LimitRequest {
1510 pub id: String,
1511 pub workspace: String,
1512 /// `limit` (raise my limit) or `overage` (spent more than meant to).
1513 pub kind: String,
1514 /// The limit asked for; for an overage, what they think went wrong.
1515 pub amount_micros: i64,
1516 pub reason: String,
1517 pub expected_monthly_micros: i64,
1518 /// `open`, `approved` or `declined`.
1519 pub status: String,
1520 /// What was approved, which may differ from what was asked.
1521 #[serde(default)]
1522 pub decided_micros: Option<i64>,
1523 #[serde(default)]
1524 pub decided_by: Option<String>,
1525 /// The answer, as the owner sees it.
1526 #[serde(default)]
1527 pub answer: Option<String>,
1528 pub created_by: String,
1529 pub created_at: String,
1530 #[serde(default)]
1531 pub decided_at: Option<String>,
1532}
1533
1534/// `request_limit`: an owner asks g1t for more, or for help with usage past
1535/// what they meant. Answered within one business day, in the app and by
1536/// email. Owners only. Returns `Outcome<LimitRequest>`.
1537#[derive(Debug, Serialize, Deserialize)]
1538#[serde(rename_all = "camelCase")]
1539pub struct RequestLimitArgs {
1540 pub actor: User,
1541 pub workspace: String,
1542 /// `limit` or `overage`.
1543 pub kind: String,
1544 #[serde(alias = "amount_micros")]
1545 pub amount_micros: i64,
1546 pub reason: String,
1547 #[serde(default, alias = "expected_monthly_micros")]
1548 pub expected_monthly_micros: i64,
1549}
1550
1551/// `limit_requests`: a workspace's requests, newest first. Members only.
1552/// Returns `Outcome<Vec<LimitRequest>>`.
1553#[derive(Debug, Serialize, Deserialize)]
1554pub struct LimitRequestsArgs {
1555 pub workspace: String,
1556 pub viewer: Viewer,
1557}
1558
1559/// `confirm_spike`: an owner's answer to a spend spike. Keep going lifts the
1560/// pause for 24 hours, or until the hour's spend doubles again; stop keeps
1561/// new compute paused until an owner says to keep going. Owners only.
1562/// Returns `Outcome<Entitlements>`.
1563#[derive(Debug, Serialize, Deserialize)]
1564#[serde(rename_all = "camelCase")]
1565pub struct ConfirmSpikeArgs {
1566 pub actor: User,
1567 pub workspace: String,
1568 #[serde(alias = "keep_going")]
1569 pub keep_going: bool,
1570}
1571
1572/// `set_caps`: the owners' own caps on agents: one run's spend ($0.10 to
1573/// $100) and what the agents on one issue may spend in all ($1 to $1,000).
1574/// None goes back to the default ($2 and $10). A cap g1t staff set for the
1575/// account wins over both. Owners only. Returns `Outcome<Entitlements>`.
1576#[derive(Debug, Serialize, Deserialize)]
1577#[serde(rename_all = "camelCase")]
1578pub struct SetCapsArgs {
1579 pub actor: User,
1580 pub workspace: String,
1581 #[serde(default, alias = "run_cap_micros")]
1582 pub run_cap_micros: Option<i64>,
1583 #[serde(default, alias = "issue_cap_micros")]
1584 pub issue_cap_micros: Option<i64>,
1585}
1586
1587/// What staff see beside a request: the workspace's history with g1t.
1588#[derive(Clone, Debug, Default, Serialize, Deserialize)]
1589#[serde(rename_all = "camelCase")]
1590pub struct WorkspaceHistory {
1591 pub plan: Option<PlanKind>,
1592 /// The last six months, oldest first.
1593 pub months: Vec<MonthFigures>,
1594 /// Live payments that have cleared, and how many.
1595 pub paid_cleared_micros: i64,
1596 pub payments: u32,
1597 pub disputes: u32,
1598 pub declines: u32,
1599 /// The first time the workspace appears in billing, RFC 3339.
1600 pub first_seen: Option<String>,
1601 pub ceiling_micros: Option<i64>,
1602 pub max_ceiling_micros: Option<i64>,
1603 pub spend_limit_micros: Option<i64>,
1604 /// Recent velocity: the last hour, the usual hour over the last week,
1605 /// and the last 24 hours, at price.
1606 pub last_hour_micros: i64,
1607 pub average_hour_micros: i64,
1608 pub last_day_micros: i64,
1609}
1610
1611#[derive(Clone, Debug, Serialize, Deserialize)]
1612#[serde(rename_all = "camelCase")]
1613pub struct LimitRequestReview {
1614 pub request: LimitRequest,
1615 pub history: WorkspaceHistory,
1616}
1617
1618/// `admin_limit_requests`: requests for staff, oldest open first. Returns
1619/// `Vec<LimitRequestReview>`.
1620#[derive(Debug, Default, Serialize, Deserialize)]
1621pub struct AdminLimitRequestsArgs {
1622 /// `open` (the default), `approved`, `declined` or `all`.
1623 #[serde(default)]
1624 pub status: Option<String>,
1625}
1626
1627/// `admin_decide_limit_request`: approve (at the amount asked, or
1628/// `amount_micros`) or decline. The owner is told in the app and by email.
1629/// Recorded with who and why. Returns `Outcome<LimitRequest>`.
1630#[derive(Debug, Serialize, Deserialize)]
1631pub struct AdminDecideLimitRequestArgs {
1632 pub id: String,
1633 /// `approve` or `decline`.
1634 pub decision: String,
1635 #[serde(default)]
1636 pub amount_micros: Option<i64>,
1637 /// What the owner is told, beside the decision.
1638 #[serde(default)]
1639 pub note: String,
1640 pub by: String,
1641}
1642
1643/// `admin_record_payment`: money that reached g1t outside the card pages,
1644/// such as a bank transfer, entered as a payment (it raises the limit like
1645/// one). Recorded with who and the transfer's reference. Returns
1646/// `Outcome<LedgerEntry>`.
1647#[derive(Debug, Serialize, Deserialize)]
1648pub struct AdminRecordPaymentArgs {
1649 pub workspace: String,
1650 pub amount_micros: i64,
1651 /// The bank's reference for the transfer, or Stripe's payment id.
1652 pub reference: String,
1653 pub note: String,
1654 pub by: String,
1655}
1656
1657// --- Overages and goodwill (sudo) --------------------------------------------
1658
1659/// What a one-time goodwill credit would come to: g1t's margin on the
1660/// overage, always, plus as much of its underlying cost as the cap allows.
1661#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
1662#[serde(rename_all = "camelCase")]
1663pub struct Goodwill {
1664 /// This month's charges above the workspace's typical month.
1665 pub overage_micros: i64,
1666 /// The part of the overage that is g1t's margin.
1667 pub margin_micros: i64,
1668 /// The part that is what g1t paid its providers.
1669 pub cost_micros: i64,
1670 /// The one-click credit: the margin plus the cost up to the cap.
1671 pub credit_micros: i64,
1672 /// Of the credit, the real cost g1t absorbs.
1673 pub absorbed_micros: i64,
1674}
1675
1676/// A workspace whose month went well past its usual, or hit a spike.
1677#[derive(Clone, Debug, Serialize, Deserialize)]
1678#[serde(rename_all = "camelCase")]
1679pub struct Overage {
1680 pub workspace: String,
1681 pub plan: PlanKind,
1682 /// The median of its last three months' charges.
1683 pub typical_month_micros: i64,
1684 pub this_month_micros: i64,
1685 /// What this month cost g1t, and what g1t keeps of it.
1686 pub cost_micros: i64,
1687 pub margin_micros: i64,
1688 /// A spike this month, if there was one.
1689 pub spike: Option<Spike>,
1690 /// The runs that cost the most this month.
1691 pub top_entries: Vec<LedgerEntry>,
1692 pub goodwill: Goodwill,
1693 /// False when a goodwill credit was given in the last 12 months.
1694 pub goodwill_available: bool,
1695 pub last_goodwill_at: Option<String>,
1696 /// An open overage request from the owner, if there is one.
1697 pub request: Option<LimitRequest>,
1698}
1699
1700/// `admin_overages`: the Overages queue. Returns `Vec<Overage>`.
1701#[derive(Debug, Default, Serialize, Deserialize)]
1702pub struct AdminOveragesArgs {}
1703
1704/// `admin_goodwill`: credits a workspace for accidental usage. With no
1705/// amount, the one-click credit (`Goodwill::credit_micros`), once per
1706/// workspace in 12 months. A larger amount, or a second within 12 months,
1707/// needs a typed reason. It shows on the statement as "Credit from g1t:
1708/// accidental usage on <date>". Returns `Outcome<LedgerEntry>`.
1709#[derive(Debug, Serialize, Deserialize)]
1710pub struct AdminGoodwillArgs {
1711 pub workspace: String,
1712 #[serde(default)]
1713 pub amount_micros: Option<i64>,
1714 /// Why, typed by staff; needed past the one-click credit.
1715 #[serde(default)]
1716 pub reason: String,
1717 /// The day the accidental usage happened, `YYYY-MM-DD`; today if absent.
1718 #[serde(default)]
1719 pub day: Option<String>,
1720 pub by: String,
1721}
1722
1723/// One workspace's recent pace, for sudo's velocity view.
1724#[derive(Clone, Debug, Serialize, Deserialize)]
1725#[serde(rename_all = "camelCase")]
1726pub struct Velocity {
1727 pub workspace: String,
1728 pub plan: PlanKind,
1729 pub last_hour_micros: i64,
1730 pub average_hour_micros: i64,
1731 pub last_day_micros: i64,
1732 pub this_month_micros: i64,
1733 /// The last hour over the usual hour; 0 with no history.
1734 pub ratio: f64,
1735 pub spike: Option<Spike>,
1736 pub first_seen: Option<String>,
1737}
1738
1739/// `admin_velocity`: workspaces spending in the last day, fastest first.
1740/// Returns `Vec<Velocity>`.
1741#[derive(Debug, Default, Serialize, Deserialize)]
1742pub struct AdminVelocityArgs {}
1743
1744#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1745#[serde(rename_all = "snake_case")]
1746pub enum AccountKind {
1747 Workspace,
1748 Enterprise,
1749}
1750
1751/// How an account is charged. Standard unless g1t set otherwise in sudo.
1752#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1753#[serde(rename_all = "camelCase")]
1754pub struct Terms {
1755 pub kind: TermsKind,
1756 /// Off every usage charge, in percent. Custom terms only.
1757 #[serde(default)]
1758 pub discount_percent: u32,
1759 /// A ceiling on unpaid usage that replaces the one trust would give.
1760 #[serde(default)]
1761 pub ceiling_micros: Option<i64>,
1762 /// Why, for whoever looks next.
1763 #[serde(default)]
1764 pub note: String,
1765 /// When the terms end and the account goes back to standard.
1766 #[serde(default)]
1767 pub until: Option<String>,
1768 #[serde(default)]
1769 pub set_by: Option<String>,
1770 #[serde(default)]
1771 pub set_at: Option<String>,
1772}
1773
1774impl Terms {
1775 pub fn standard() -> Self {
1776 Terms {
1777 kind: TermsKind::Standard,
1778 discount_percent: 0,
1779 ceiling_micros: None,
1780 note: String::new(),
1781 until: None,
1782 set_by: None,
1783 set_at: None,
1784 }
1785 }
1786
1787 /// The discount in percent, 0 to 100. Terms from before discounts
1788 /// replaced "comped" read as 100%.
1789 pub fn percent_off(&self) -> u32 {
1790 match self.kind {
1791 TermsKind::Comped => 100,
1792 TermsKind::Custom => self.discount_percent.min(100),
1793 TermsKind::Standard => 0,
1794 }
1795 }
1796
1797 /// A 100% discount: nothing is charged, usage is recorded at its price
1798 /// and discounted in full. g1t's own workspaces and partners. Paid
1799 /// features are on without a plan, and g1t's own spend on it is held to
1800 /// a monthly budget (the terms' ceiling, at cost).
1801 pub fn full_discount(&self) -> bool {
1802 self.percent_off() >= 100
1803 }
1804
1805 /// What a charge becomes under these terms.
1806 pub fn apply(&self, charge_micros: i64) -> i64 {
1807 charge_micros * i64::from(100 - self.percent_off()) / 100
1808 }
1809
1810 /// What a charge at cost plus the margin becomes under these terms, and
1811 /// what the discount took off it (`ledger.discount_micros`), so the
1812 /// statement shows the usage at its price and the discount beside it,
1813 /// and a discount below cost plus the margin is counted as given, never
1814 /// lost. A 100% discount takes it all.
1815 pub fn discounted(&self, charge_micros: i64) -> (i64, i64) {
1816 let charged = self.apply(charge_micros);
1817 (charged, (charge_micros - charged).max(0))
1818 }
1819
1820 /// How the statement and sudo name the terms: `100% discount`, `30% off`.
1821 pub fn discount_label(&self) -> Option<String> {
1822 match self.percent_off() {
1823 0 => None,
1824 100 => Some("100% discount".to_owned()),
1825 percent => Some(format!("{percent}% off")),
1826 }
1827 }
1828}
1829
1830#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1831#[serde(rename_all = "snake_case")]
1832pub enum TermsKind {
1833 /// Prices as published, limits by trust.
1834 Standard,
1835 /// Before discounts: what a 100% discount is now. Read as one
1836 /// (`Terms::percent_off`); billing never writes it (migration 0039).
1837 Comped,
1838 /// A discount (up to 100%), a ceiling, or both.
1839 Custom,
1840}
1841
1842/// `stripe_webhook`: an event from Stripe, as the API received it: the raw
1843/// body and its `Stripe-Signature` header. Billing checks the signature
1844/// against the secret of the endpoint it registered, and handles each
1845/// event once. Returns `Outcome<bool>`: false for one already handled.
1846#[derive(Debug, Serialize, Deserialize)]
1847pub struct StripeWebhookArgs {
1848 pub payload: String,
1849 pub signature: String,
1850}
1851
1852/// `admin_stripe`: where billing stands with Stripe. Staff only. Returns
1853/// `StripeStatus`. With `fix: true`, first enables the destination at
1854/// billing's address and gives it the events billing needs.
1855#[derive(Debug, Default, Serialize, Deserialize)]
1856pub struct AdminStripeArgs {
1857 #[serde(default)]
1858 pub fix: bool,
1859 #[serde(default)]
1860 pub by: Option<String>,
1861}
1862
1863#[derive(Clone, Debug, Serialize, Deserialize)]
1864#[serde(rename_all = "camelCase")]
1865pub struct StripeStatus {
1866 /// `test` or `live`, from the key; `off` without one.
1867 pub mode: String,
1868 /// Whether `STRIPE_WEBHOOK_SECRET` is set, so events can be checked.
1869 pub secret_set: bool,
1870 /// The destination at billing's address in Stripe, as Stripe has it.
1871 pub webhook: Option<StripeWebhook>,
1872 /// Events billing handles that the destination does not send.
1873 pub missing_events: Vec<String>,
1874 /// The latest events handled, newest first.
1875 pub recent_events: Vec<StripeEventSummary>,
1876 /// What went wrong reading or fixing the destination, if it did.
1877 pub error: Option<String>,
1878}
1879
1880#[derive(Clone, Debug, Serialize, Deserialize)]
1881#[serde(rename_all = "camelCase")]
1882pub struct StripeWebhook {
1883 pub url: String,
1884 pub endpoint_id: String,
1885 /// `enabled` or `disabled`.
1886 pub status: String,
1887 pub events: Vec<String>,
1888 pub created_at: String,
1889}
1890
1891#[derive(Clone, Debug, Serialize, Deserialize)]
1892#[serde(rename_all = "camelCase")]
1893pub struct StripeEventSummary {
1894 pub id: String,
1895 pub kind: String,
1896 pub outcome: String,
1897 pub received_at: String,
1898}
1899
1900/// `admin_enterprise_billing`: where an enterprise's invoices go. Creates
1901/// or updates its Stripe customer. Returns `Outcome<BillingAccount>`.
1902#[derive(Debug, Serialize, Deserialize)]
1903pub struct AdminEnterpriseBillingArgs {
1904 pub id: String,
1905 pub email: String,
1906 pub by: String,
1907}
1908
1909/// `admin_enterprise_address`: the enterprise's billing address and tax ID,
1910/// saved on its Stripe customer (made by `admin_enterprise_billing`).
1911/// Stripe Tax works its invoices' tax out from the address; an invoice is
1912/// not sent without one. Returns `Outcome<bool>`.
1913#[derive(Debug, Serialize, Deserialize)]
1914#[serde(rename_all = "camelCase")]
1915pub struct AdminEnterpriseAddressArgs {
1916 pub id: String,
1917 pub address: PostalAddress,
1918 #[serde(default, alias = "tax_id_type")]
1919 pub tax_id_type: Option<String>,
1920 #[serde(default, alias = "tax_id")]
1921 pub tax_id: Option<String>,
1922 pub by: String,
1923}
1924
1925/// `admin_invoice_enterprise`: sends an enterprise its invoice now, for
1926/// what its workspaces owe, rather than waiting for the month to close.
1927/// Returns `Outcome<EnterpriseInvoice>`.
1928#[derive(Debug, Serialize, Deserialize)]
1929pub struct AdminInvoiceEnterpriseArgs {
1930 pub id: String,
1931 pub by: String,
1932}
1933
1934/// An enterprise's invoice: one line per workspace, paid on Stripe.
1935#[derive(Clone, Debug, Serialize, Deserialize)]
1936#[serde(rename_all = "camelCase")]
1937pub struct EnterpriseInvoice {
1938 pub invoice_id: String,
1939 /// Stripe's page for it, where it is paid.
1940 pub hosted_url: Option<String>,
1941 pub amount_micros: i64,
1942 /// `open`, `paid`, `overdue` or `void`.
1943 pub status: String,
1944 pub period: String,
1945 pub lines: Vec<InvoiceLine>,
1946 pub created_at: String,
1947}
1948
1949#[derive(Clone, Debug, Serialize, Deserialize)]
1950#[serde(rename_all = "camelCase")]
1951pub struct InvoiceLine {
1952 pub workspace: String,
1953 pub amount_micros: i64,
1954}
1955
1956/// A workspace's invoice from g1t: one per month, and one each time it is
1957/// charged near its limit. Itemised, charged to the card on file, and kept
1958/// in Stripe's billing page with its PDF.
1959#[derive(Clone, Debug, Serialize, Deserialize)]
1960#[serde(rename_all = "camelCase")]
1961pub struct WorkspaceInvoice {
1962 pub invoice_id: String,
1963 pub workspace: String,
1964 /// `month` (2026-10) or `threshold`.
1965 pub reason: String,
1966 pub period: String,
1967 pub amount_micros: i64,
1968 /// `paid`, `open`, `failed` or `void`.
1969 pub status: String,
1970 pub hosted_url: Option<String>,
1971 pub pdf_url: Option<String>,
1972 pub lines: Vec<InvoiceItem>,
1973 pub created_at: String,
1974 /// The card processing fee on top of `amount_micros`, when the invoice
1975 /// is charged to a card; never part of the usage it pays for.
1976 #[serde(default)]
1977 pub fee_micros: i64,
1978 /// The tax Stripe added on top, once it is known (after paying).
1979 #[serde(default)]
1980 pub tax_micros: i64,
1981}
1982
1983#[derive(Clone, Debug, Serialize, Deserialize)]
1984#[serde(rename_all = "camelCase")]
1985pub struct InvoiceItem {
1986 pub description: String,
1987 pub amount_micros: i64,
1988}
1989
1990/// `invoices`: a workspace's invoices from g1t, newest first. Members
1991/// only. Returns `Outcome<Vec<WorkspaceInvoice>>`.
1992#[derive(Debug, Serialize, Deserialize)]
1993pub struct InvoicesArgs {
1994 pub workspace: String,
1995 pub viewer: Viewer,
1996}
1997
1998/// `admin_workspace_invoices`: the same, for staff. Returns
1999/// `Vec<WorkspaceInvoice>`.
2000#[derive(Debug, Serialize, Deserialize)]
2001pub struct AdminWorkspaceInvoicesArgs {
2002 pub workspace: String,
2003}
2004
2005/// `statement`: a month of a workspace's ledger, grouped by day (or by
2006/// project) with a line per kind of charge. Members only. Returns
2007/// `Outcome<Statement>`.
2008#[derive(Debug, Serialize, Deserialize)]
2009pub struct StatementArgs {
2010 pub workspace: String,
2011 pub viewer: Viewer,
2012 /// YYYY-MM; this month when absent.
2013 #[serde(default)]
2014 pub month: Option<String>,
2015 /// `day` (the default) or `project`.
2016 #[serde(default)]
2017 pub group: Option<String>,
2018}
2019
2020#[derive(Clone, Debug, Serialize, Deserialize)]
2021#[serde(rename_all = "camelCase")]
2022pub struct Statement {
2023 pub month: String,
2024 /// Months with any entries, newest first.
2025 pub months: Vec<String>,
2026 pub groups: Vec<StatementGroup>,
2027 pub totals: StatementTotals,
2028}
2029
2030#[derive(Clone, Debug, Serialize, Deserialize)]
2031#[serde(rename_all = "camelCase")]
2032pub struct StatementGroup {
2033 /// The day (YYYY-MM-DD) or the project (`owner/name`, or empty).
2034 pub key: String,
2035 pub label: String,
2036 pub lines: Vec<StatementLine>,
2037 /// What the group's charges come to.
2038 pub charged_micros: i64,
2039 /// Its usage at price, and what the discount took off it.
2040 #[serde(default)]
2041 pub price_micros: i64,
2042 #[serde(default)]
2043 pub discount_micros: i64,
2044}
2045
2046#[derive(Clone, Debug, Serialize, Deserialize)]
2047#[serde(rename_all = "camelCase")]
2048pub struct StatementLine {
2049 /// Agent runs, Sandbox time, Deployments, Payments, Credits from g1t,
2050 /// Refunds, and, for older entries, Runs on your own model provider.
2051 pub kind: String,
2052 pub count: u32,
2053 /// Charges positive; money in (payments, credits) negative.
2054 pub charged_micros: i64,
2055 pub cost_micros: i64,
2056 /// Of the usage on the line, what was paid for before it was charged:
2057 /// by the plan's included usage, the trial credit, g1t's open-source
2058 /// pool, or g1t itself. Not in `charged_micros`.
2059 #[serde(default)]
2060 pub covered_micros: i64,
2061 /// Usage at its price: charged, plus what paid for it and what the
2062 /// discount took off. Zero for money in.
2063 #[serde(default)]
2064 pub price_micros: i64,
2065 /// What the account's discount took off the line's price.
2066 #[serde(default)]
2067 pub discount_micros: i64,
2068 /// On the `Tax` and `Card processing fees` lines: what was paid with
2069 /// payments on top of what reached the balance (negative for what a
2070 /// refund gave back). Never in `charged_micros` or the balance.
2071 #[serde(default)]
2072 pub passed_micros: i64,
2073}
2074
2075#[derive(Clone, Debug, Serialize, Deserialize)]
2076#[serde(rename_all = "camelCase")]
2077pub struct StatementTotals {
2078 pub charged_micros: i64,
2079 pub paid_micros: i64,
2080 pub cost_micros: i64,
2081 pub entries: u32,
2082 /// Usage at price, and what the discount took off it: charged is the
2083 /// price less the discount and what paid for it.
2084 #[serde(default)]
2085 pub price_micros: i64,
2086 #[serde(default)]
2087 pub discount_micros: i64,
2088 /// The account's discount now, in percent; absent without one.
2089 #[serde(default)]
2090 pub discount_percent: Option<u32>,
2091 /// What paid for usage before it was charged, one line per source,
2092 /// such as "Paid by g1t's open-source pool".
2093 #[serde(default)]
2094 pub covered: Vec<Covered>,
2095 /// Owed when the month closed but under the minimum charge, so it
2096 /// carries over to the next invoice. Zero when nothing carried.
2097 #[serde(default)]
2098 pub carried_micros: i64,
2099 /// Tax and card processing fees paid with the month's payments, on top
2100 /// of `paid_micros`.
2101 #[serde(default)]
2102 pub tax_micros: i64,
2103 #[serde(default)]
2104 pub card_fee_micros: i64,
2105}
2106
2107/// One source that paid for usage before it was charged.
2108#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
2109#[serde(rename_all = "camelCase")]
2110pub struct Covered {
2111 /// `included`, `trial`, `oss_pool` or `given`.
2112 pub source: String,
2113 /// "Paid by your plan's included usage", "Paid by your trial credit",
2114 /// "Paid by g1t's open-source pool", "Covered by g1t".
2115 pub label: String,
2116 pub micros: i64,
2117}
2118
2119/// `statement_entries`: one statement line's entries, newest first, 50 at
2120/// a time (`before` = the last id seen). Returns `Outcome<Vec<LedgerEntry>>`.
2121#[derive(Debug, Serialize, Deserialize)]
2122pub struct StatementEntriesArgs {
2123 pub workspace: String,
2124 pub viewer: Viewer,
2125 pub month: String,
2126 pub kind: String,
2127 #[serde(default)]
2128 pub day: Option<String>,
2129 #[serde(default)]
2130 pub project: Option<String>,
2131 #[serde(default)]
2132 pub before: Option<String>,
2133}
2134
2135// --- Sales (sudo.g1t.sh) ------------------------------------------------------
2136//
2137// What staff need to know to reach out: who is growing, who is close to
2138// their limit, who was declined, who has become a steady customer. And what
2139// was done about it: a stage, an owner on g1t's side, a next step, notes.
2140
2141/// Why a workspace is worth a look.
2142#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
2143#[serde(rename_all = "snake_case")]
2144pub enum SignalKind {
2145 /// At its limit, or its own spend limit: work is stopped.
2146 AtLimit,
2147 /// Past 80% of what is available to it: about to need more.
2148 NearCeiling,
2149 /// Its card was declined or a payment disputed.
2150 Declined,
2151 /// This month is well ahead of last month.
2152 Growing,
2153 /// Became Established: the ceiling now follows its spend.
2154 Established,
2155 /// Paid g1t for the first time.
2156 FirstPayment,
2157 /// Spending enough that custom terms or an enterprise may suit it.
2158 HighSpend,
2159 /// Costs g1t more on Cloudflare than it pays, over 30 days: a pricing
2160 /// gap or abuse to look at (billing's `margin`).
2161 CostOverRevenue,
2162}
2163
2164#[derive(Clone, Debug, Serialize, Deserialize)]
2165#[serde(rename_all = "camelCase")]
2166pub struct Signal {
2167 pub workspace: String,
2168 pub kind: SignalKind,
2169 /// One sentence, with the figures.
2170 pub detail: String,
2171 /// The figure that matters, such as this month's spend.
2172 pub value_micros: i64,
2173 /// Its sales stage, if staff gave it one.
2174 pub stage: Option<String>,
2175 pub owner: Option<String>,
2176 #[serde(default)]
2177 pub next_step: Option<String>,
2178 /// When the next step is due, `YYYY-MM-DD`.
2179 #[serde(default)]
2180 pub next_at: Option<String>,
2181}
2182
2183/// `admin_invoices`: every invoice g1t has sent, workspaces' and
2184/// enterprises', newest first. Returns `Vec<InvoiceSummary>`.
2185#[derive(Debug, Default, Serialize, Deserialize)]
2186pub struct AdminInvoicesArgs {
2187 /// `paid`, `open`, `failed`, `overdue` or `void`.
2188 #[serde(default)]
2189 pub status: Option<String>,
2190 /// YYYY-MM, by when it was sent.
2191 #[serde(default)]
2192 pub month: Option<String>,
2193}
2194
2195#[derive(Clone, Debug, Serialize, Deserialize)]
2196#[serde(rename_all = "camelCase")]
2197pub struct InvoiceSummary {
2198 pub invoice_id: String,
2199 /// `workspace` or `enterprise`.
2200 pub kind: String,
2201 /// The workspace's slug, or the enterprise's account id.
2202 pub account: String,
2203 /// What to call it: the workspace, or the enterprise's name.
2204 pub name: String,
2205 pub reason: String,
2206 pub period: String,
2207 pub amount_micros: i64,
2208 pub status: String,
2209 pub hosted_url: Option<String>,
2210 pub created_at: String,
2211 pub paid_at: Option<String>,
2212}
2213
2214/// `admin_audit`: every change made in sudo, and by Stripe, newest first.
2215/// Returns `Vec<AdminAction>`.
2216#[derive(Debug, Default, Serialize, Deserialize)]
2217pub struct AdminAuditArgs {
2218 #[serde(default)]
2219 pub by: Option<String>,
2220 #[serde(default)]
2221 pub action: Option<String>,
2222 /// Only those before this time, for paging.
2223 #[serde(default)]
2224 pub before: Option<String>,
2225}
2226
2227/// `admin_signals`: every workspace worth reaching out to, most urgent
2228/// first. Returns `Vec<Signal>`.
2229#[derive(Debug, Default, Serialize, Deserialize)]
2230pub struct AdminSignalsArgs {}
2231
2232/// What staff are doing about a workspace.
2233#[derive(Clone, Debug, Serialize, Deserialize)]
2234#[serde(rename_all = "camelCase")]
2235pub struct SalesRecord {
2236 pub workspace: String,
2237 /// `none`, `lead`, `contacted`, `negotiating`, `won`, `lost` or `churn_risk`.
2238 pub stage: String,
2239 /// The staff member looking after it.
2240 pub owner: Option<String>,
2241 pub next_step: Option<String>,
2242 /// RFC 3339 date.
2243 pub next_at: Option<String>,
2244 pub notes: Vec<SalesNote>,
2245 pub updated_at: Option<String>,
2246}
2247
2248#[derive(Clone, Debug, Serialize, Deserialize)]
2249#[serde(rename_all = "camelCase")]
2250pub struct SalesNote {
2251 pub id: String,
2252 pub text: String,
2253 pub by: String,
2254 pub created_at: String,
2255}
2256
2257/// `admin_sales`: a workspace's sales record. Returns `SalesRecord`.
2258#[derive(Debug, Serialize, Deserialize)]
2259pub struct AdminSalesArgs {
2260 pub workspace: String,
2261}
2262
2263/// `admin_set_sales`: its stage, owner and next step. Returns `Outcome<SalesRecord>`.
2264#[derive(Debug, Serialize, Deserialize)]
2265pub struct AdminSetSalesArgs {
2266 pub workspace: String,
2267 pub stage: String,
2268 #[serde(default)]
2269 pub owner: Option<String>,
2270 #[serde(default)]
2271 pub next_step: Option<String>,
2272 #[serde(default)]
2273 pub next_at: Option<String>,
2274 pub by: String,
2275}
2276
2277/// `admin_add_note`. Returns `Outcome<SalesRecord>`.
2278#[derive(Debug, Serialize, Deserialize)]
2279pub struct AdminAddNoteArgs {
2280 pub workspace: String,
2281 pub text: String,
2282 pub by: String,
2283}
2284
2285/// `admin_overview`: the business at a glance. Returns `Overview`.
2286#[derive(Debug, Default, Serialize, Deserialize)]
2287pub struct AdminOverviewArgs {}
2288
2289#[derive(Clone, Debug, Serialize, Deserialize)]
2290#[serde(rename_all = "camelCase")]
2291pub struct Overview {
2292 /// YYYY-MM.
2293 pub month: String,
2294 /// The last six months, oldest first, all workspaces together.
2295 pub months: Vec<MonthFigures>,
2296 /// This month by kind of usage: models, sandbox, deployments, plans.
2297 pub by_kind: Vec<KindFigures>,
2298 pub paying_workspaces: u32,
2299 pub stopped: u32,
2300 pub near_ceiling: u32,
2301 pub declined: u32,
2302 /// Sent and not yet paid, workspaces and enterprises.
2303 pub open_invoices_micros: i64,
2304 /// Follow-ups due today or earlier.
2305 pub follow_ups_due: u32,
2306 /// The capped budgets g1t pays from, this month.
2307 #[serde(default)]
2308 pub pools: Option<Pools>,
2309 /// This month's revenue: usage charged plus the plan's price paid.
2310 #[serde(default)]
2311 pub revenue_micros: i64,
2312 /// Workspaces on the paid plan now, and what their price comes to a
2313 /// month.
2314 #[serde(default)]
2315 pub active_plans: u32,
2316 #[serde(default)]
2317 pub plan_mrr_micros: i64,
2318 /// What g1t gave this month, by source, apart from its margin.
2319 #[serde(default)]
2320 pub given: Vec<GivenFigures>,
2321 /// g1t's own and Flagon's workspaces this month: what their use cost,
2322 /// and why they are not charged.
2323 #[serde(default)]
2324 pub internal: Vec<InternalUse>,
2325 /// Open limit requests, and workspaces in the Overages queue.
2326 #[serde(default)]
2327 pub open_requests: u32,
2328 #[serde(default)]
2329 pub overages: u32,
2330 /// Spend spikes waiting for an owner.
2331 #[serde(default)]
2332 pub open_spikes: u32,
2333}
2334
2335/// What g1t gave this month from one source.
2336#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2337#[serde(rename_all = "camelCase")]
2338pub struct GivenFigures {
2339 /// `internal`, `trial`, `oss_pool`, `goodwill` or `covered`.
2340 pub source: String,
2341 pub label: String,
2342 /// At price, and what it cost g1t.
2343 pub micros: i64,
2344 pub cost_micros: i64,
2345}
2346
2347/// One internal workspace's use this month.
2348#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2349#[serde(rename_all = "camelCase")]
2350pub struct InternalUse {
2351 pub workspace: String,
2352 /// Why it is not charged: its terms' note.
2353 pub reason: String,
2354 pub cost_micros: i64,
2355 pub entries: u32,
2356}
2357
2358/// g1t's capped budgets for free usage, this calendar month (UTC).
2359#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2360#[serde(rename_all = "camelCase")]
2361pub struct Pools {
2362 /// YYYY-MM.
2363 pub month: String,
2364 /// Trial grants made this month, against the month's pool.
2365 pub trial_granted_micros: i64,
2366 pub trial_pool_micros: i64,
2367 pub trial_grants: u32,
2368 /// What the open-source pool paid this month, against its cap.
2369 pub oss_used_micros: i64,
2370 pub oss_pool_micros: i64,
2371 /// Each public repository's monthly cap on the pool.
2372 pub oss_repo_micros: i64,
2373}
2374
2375#[derive(Clone, Debug, Serialize, Deserialize)]
2376#[serde(rename_all = "camelCase")]
2377pub struct KindFigures {
2378 pub kind: String,
2379 pub charged_micros: i64,
2380 pub cost_micros: i64,
2381}
2382
2383// --- Staff (sudo.g1t.sh) ------------------------------------------------------
2384//
2385// Called only by the sudo app, which only g1t staff can reach (behind
2386// Cloudflare Access). Each change names who made it, and is kept in the
2387// audit log.
2388
2389/// `admin_accounts`: every billing account, with where each stands this
2390/// month. Returns `Vec<AccountSummary>`.
2391#[derive(Debug, Default, Serialize, Deserialize)]
2392pub struct AdminAccountsArgs {
2393 #[serde(default)]
2394 pub query: Option<String>,
2395 /// Exactly these workspaces' accounts, such as one page of sudo's
2396 /// list; every account with activity when absent.
2397 #[serde(default)]
2398 pub workspaces: Option<Vec<String>>,
2399}
2400
2401#[derive(Clone, Debug, Serialize, Deserialize)]
2402#[serde(rename_all = "camelCase")]
2403pub struct AccountSummary {
2404 pub account: BillingAccount,
2405 pub limit: Limit,
2406 /// Charged this month, after terms.
2407 pub charged_micros: i64,
2408 /// What this month's usage cost g1t.
2409 pub cost_micros: i64,
2410 /// Paid, ever.
2411 pub paid_micros: i64,
2412 /// The same figures for each of the account's workspaces that has
2413 /// any, so staff can see what one member of an enterprise used.
2414 #[serde(default)]
2415 pub by_workspace: Vec<WorkspaceFigures>,
2416 /// The last six months, oldest first, for trends.
2417 #[serde(default)]
2418 pub months: Vec<MonthFigures>,
2419}
2420
2421/// One month of an account's billing.
2422#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2423#[serde(rename_all = "camelCase")]
2424pub struct MonthFigures {
2425 /// YYYY-MM.
2426 pub month: String,
2427 /// Usage charged, after what paid for it first.
2428 pub charged_micros: i64,
2429 /// What usage cost g1t: only what g1t paid for, never a workspace's own
2430 /// model provider.
2431 pub cost_micros: i64,
2432 pub paid_micros: i64,
2433 /// The plan's monthly price, paid.
2434 #[serde(default)]
2435 pub plans_micros: i64,
2436 /// What g1t gave, at price: internal (comped) use, trials, the
2437 /// open-source pool, goodwill credits and what g1t covered. Not margin.
2438 #[serde(default)]
2439 pub given_micros: i64,
2440}
2441
2442/// One workspace's share of an [`AccountSummary`].
2443#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2444#[serde(rename_all = "camelCase")]
2445pub struct WorkspaceFigures {
2446 pub workspace: String,
2447 pub charged_micros: i64,
2448 pub cost_micros: i64,
2449 pub paid_micros: i64,
2450}
2451
2452/// `admin_account`: one account in full. Returns `Outcome<AccountDetail>`.
2453#[derive(Debug, Serialize, Deserialize)]
2454pub struct AdminAccountArgs {
2455 /// An account id, or a workspace slug.
2456 pub id: String,
2457}
2458
2459#[derive(Clone, Debug, Serialize, Deserialize)]
2460#[serde(rename_all = "camelCase")]
2461pub struct AccountDetail {
2462 pub summary: AccountSummary,
2463 /// Each workspace's limit, for an enterprise.
2464 pub workspaces: Vec<Limit>,
2465 pub ledger: Vec<LedgerEntry>,
2466 pub audit: Vec<AdminAction>,
2467}
2468
2469/// `admin_set_terms`. Returns `Outcome<BillingAccount>`.
2470#[derive(Debug, Serialize, Deserialize)]
2471pub struct AdminSetTermsArgs {
2472 pub id: String,
2473 pub terms: Terms,
2474 pub by: String,
2475}
2476
2477/// `admin_create_enterprise`. Returns `Outcome<BillingAccount>`.
2478#[derive(Debug, Serialize, Deserialize)]
2479pub struct AdminCreateEnterpriseArgs {
2480 pub name: String,
2481 pub workspaces: Vec<String>,
2482 pub by: String,
2483}
2484
2485/// `admin_attach`: moves a workspace onto an enterprise account, or back
2486/// onto its own with `account: None`. Returns `Outcome<BillingAccount>`.
2487#[derive(Debug, Serialize, Deserialize)]
2488pub struct AdminAttachArgs {
2489 pub workspace: String,
2490 pub account: Option<String>,
2491 pub by: String,
2492}
2493
2494/// Why g1t gave a workspace credit.
2495#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
2496#[serde(rename_all = "snake_case")]
2497pub enum CreditKind {
2498 /// Marketing: a welcome, a referral, an event. Given away when spent.
2499 Promotional,
2500 /// An apology, or accidental usage forgiven. Given away when spent.
2501 #[default]
2502 Goodwill,
2503 /// Money back for something that went wrong. Not given away: it gives
2504 /// back money already paid, so it comes off what was paid on the day
2505 /// it refunds, and what it pays for later is paid for.
2506 Refund,
2507 /// Bought by the workspace (prepaid AI): money paid in up front, owed
2508 /// as usage until spent. What it pays for is paid for, never given.
2509 /// Staff never give it; its ledger line is a payment, not `crd…`.
2510 Purchased,
2511}
2512
2513impl CreditKind {
2514 pub fn as_str(self) -> &'static str {
2515 match self {
2516 CreditKind::Promotional => "promotional",
2517 CreditKind::Goodwill => "goodwill",
2518 CreditKind::Refund => "refund",
2519 CreditKind::Purchased => "purchased",
2520 }
2521 }
2522
2523 pub fn parse(text: &str) -> Option<CreditKind> {
2524 match text {
2525 "promotional" => Some(CreditKind::Promotional),
2526 "goodwill" => Some(CreditKind::Goodwill),
2527 "refund" => Some(CreditKind::Refund),
2528 "purchased" => Some(CreditKind::Purchased),
2529 _ => None,
2530 }
2531 }
2532
2533 /// As people read it: `Promotional`.
2534 pub fn label(self) -> &'static str {
2535 match self {
2536 CreditKind::Promotional => "Promotional",
2537 CreditKind::Goodwill => "Goodwill",
2538 CreditKind::Refund => "Refund",
2539 CreditKind::Purchased => "Purchased",
2540 }
2541 }
2542}
2543
2544/// `admin_credit`: credit g1t gives a workspace: promotional, goodwill or a
2545/// refund, with a note, and optionally an expiry. It is spent before
2546/// anything paid in advance, the soonest-expiring first. The workspace's
2547/// owners are emailed. Returns `Outcome<LedgerEntry>`.
2548#[derive(Debug, Serialize, Deserialize)]
2549pub struct AdminCreditArgs {
2550 pub workspace: String,
2551 pub amount_micros: i64,
2552 pub note: String,
2553 pub by: String,
2554 #[serde(default)]
2555 pub kind: CreditKind,
2556 /// RFC 3339; unused credit stops counting then. Never for a refund.
2557 #[serde(default)]
2558 pub expires_at: Option<String>,
2559 /// A refund: what it refunds, in a line, and the day of it
2560 /// (`YYYY-MM-DD`; today if absent).
2561 #[serde(default)]
2562 pub refund_for: Option<String>,
2563 #[serde(default)]
2564 pub refund_day: Option<String>,
2565}
2566
2567/// One credit g1t gave, with what of it was used: spent on usage, the
2568/// soonest-expiring grant first, before anything paid in advance.
2569#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2570#[serde(rename_all = "camelCase")]
2571pub struct CreditGrant {
2572 /// `crd_…`, the grant's ledger reference.
2573 pub id: String,
2574 pub workspace: String,
2575 pub kind: CreditKind,
2576 pub amount_micros: i64,
2577 pub used_micros: i64,
2578 /// What can still be spent: nothing once it expired or was revoked.
2579 pub left_micros: i64,
2580 pub note: String,
2581 #[serde(default)]
2582 pub refund_for: Option<String>,
2583 #[serde(default)]
2584 pub refund_day: Option<String>,
2585 pub expires_at: Option<String>,
2586 pub created_by: String,
2587 pub created_at: String,
2588 /// `open`, `used`, `expired` or `revoked`.
2589 pub state: String,
2590 #[serde(default)]
2591 pub closed_at: Option<String>,
2592 #[serde(default)]
2593 pub closed_note: Option<String>,
2594 #[serde(default)]
2595 pub closed_by: Option<String>,
2596 /// What expiring or revoking took off the balance.
2597 #[serde(default)]
2598 pub closed_micros: i64,
2599 /// What it pays for: `all` usage, or `models` only (agent runs' model
2600 /// cost), which is spent first.
2601 #[serde(default)]
2602 pub scope: String,
2603 /// Where it came from: `staff`, `purchase` or `promo_code`.
2604 #[serde(default)]
2605 pub source: String,
2606}
2607
2608/// `credits` (`Outcome<Credits>`, `AccountArgs`): a workspace's credits from
2609/// g1t, newest first, for its members.
2610#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2611#[serde(rename_all = "camelCase")]
2612pub struct Credits {
2613 pub grants: Vec<CreditGrant>,
2614 /// What is left to spend, in all.
2615 pub left_micros: i64,
2616}
2617
2618/// `admin_credits`: every credit g1t gave, newest first, filtered. Returns
2619/// `AdminCredits`.
2620#[derive(Debug, Default, Serialize, Deserialize)]
2621pub struct AdminCreditsArgs {
2622 #[serde(default)]
2623 pub workspace: Option<String>,
2624 #[serde(default)]
2625 pub kind: Option<CreditKind>,
2626 /// `YYYY-MM`: given that month.
2627 #[serde(default)]
2628 pub month: Option<String>,
2629 /// Given by this member of staff.
2630 #[serde(default)]
2631 pub by: Option<String>,
2632}
2633
2634/// One month's credits of one kind: given, used on usage that month, and
2635/// taken back unused (expired or revoked).
2636#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2637#[serde(rename_all = "camelCase")]
2638pub struct CreditMonth {
2639 pub month: String,
2640 pub kind: CreditKind,
2641 pub given_micros: i64,
2642 pub grants: u32,
2643 pub used_micros: i64,
2644 pub expired_micros: i64,
2645 pub revoked_micros: i64,
2646}
2647
2648#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2649#[serde(rename_all = "camelCase")]
2650pub struct AdminCredits {
2651 /// At most 200.
2652 pub grants: Vec<CreditGrant>,
2653 /// The last 12 months, newest first, whatever the month filter.
2654 pub months: Vec<CreditMonth>,
2655 /// Who has given credit, for the filter.
2656 pub staff: Vec<String>,
2657}
2658
2659/// `admin_revoke_credit`: what is left of a grant, taken off the balance,
2660/// with why. Returns `Outcome<CreditGrant>`.
2661#[derive(Debug, Serialize, Deserialize)]
2662pub struct AdminRevokeCreditArgs {
2663 pub id: String,
2664 pub note: String,
2665 pub by: String,
2666}
2667
2668/// `admin_reset_billing`: a test workspace's billing wiped, so it starts
2669/// again as a new customer. Only while billing runs on Stripe's test key;
2670/// never a comped workspace or one an enterprise pays for. `confirm` is the
2671/// workspace's slug typed out. Returns `Outcome<BillingReset>`.
2672#[derive(Debug, Serialize, Deserialize)]
2673pub struct AdminResetBillingArgs {
2674 pub workspace: String,
2675 pub confirm: String,
2676 pub note: String,
2677 pub by: String,
2678}
2679
2680/// What a reset removed.
2681#[derive(Clone, Debug, Serialize, Deserialize)]
2682#[serde(rename_all = "camelCase")]
2683pub struct BillingReset {
2684 pub workspace: String,
2685 pub rows: u32,
2686 /// Whether the costs analysis ran again after it, so the margin
2687 /// figures no longer hold the workspace's past usage.
2688 #[serde(default)]
2689 pub refreshed: bool,
2690}
2691
2692/// One change made in sudo.
2693#[derive(Clone, Debug, Serialize, Deserialize)]
2694#[serde(rename_all = "camelCase")]
2695pub struct AdminAction {
2696 pub id: String,
2697 pub account: String,
2698 pub action: String,
2699 pub detail: String,
2700 pub by: String,
2701 pub created_at: String,
2702}
2703
2704/// What a feature's plan costs and includes.
2705#[derive(Clone, Debug, Serialize, Deserialize)]
2706#[serde(rename_all = "camelCase")]
2707pub struct Plan {
2708 pub feature: Feature,
2709 pub title: String,
2710 /// Charged every month while the plan is on, in cents, excluding tax.
2711 pub monthly_cents: u32,
2712 /// The card processing fee on top each month, in cents (0 when the
2713 /// fee is off). Excluding tax, like the price.
2714 #[serde(default)]
2715 pub card_fee_cents: u32,
2716 /// What the monthly price includes, one line each, for people to read.
2717 pub includes: Vec<String>,
2718 /// How usage past the allowance is charged, for people to read.
2719 pub overage: String,
2720}
2721
2722#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
2723#[serde(rename_all = "snake_case")]
2724pub enum SubscriptionStatus {
2725 /// Paid up; the feature works.
2726 Active,
2727 /// Paid up to the end of the period, and ends then.
2728 Canceling,
2729 /// The last payment failed; the feature is off until it is paid.
2730 PastDue,
2731 /// Ended.
2732 Canceled,
2733}
2734
2735impl SubscriptionStatus {
2736 /// Whether the feature works in this state.
2737 pub fn on(self) -> bool {
2738 matches!(self, SubscriptionStatus::Active | SubscriptionStatus::Canceling)
2739 }
2740}
2741
2742/// A workspace's plan for one feature.
2743#[derive(Clone, Debug, Serialize, Deserialize)]
2744#[serde(rename_all = "camelCase")]
2745pub struct Subscription {
2746 pub feature: Feature,
2747 pub status: SubscriptionStatus,
2748 /// RFC 3339: when the period paid for ends, and the plan renews or
2749 /// ends.
2750 pub period_end: Option<String>,
2751 /// Username of whoever turned it on.
2752 pub started_by: String,
2753 /// RFC 3339.
2754 pub started_at: String,
2755}
2756
2757/// A feature as a workspace sees it: what it costs, and its plan if it has
2758/// one.
2759#[derive(Clone, Debug, Serialize, Deserialize)]
2760#[serde(rename_all = "camelCase")]
2761pub struct FeatureState {
2762 pub plan: Plan,
2763 pub subscription: Option<Subscription>,
2764 /// Whether the feature works for the workspace now.
2765 pub on: bool,
2766 /// On without a plan: comped terms, or given by g1t. Nothing to pay
2767 /// and nothing to turn off.
2768 #[serde(default)]
2769 pub included: bool,
2770}
2771
2772/// `features`: every paid feature and the workspace's plan for each.
2773/// Members only. Returns `Outcome<Vec<FeatureState>>`.
2774#[derive(Debug, Serialize, Deserialize)]
2775pub struct FeaturesArgs {
2776 pub workspace: String,
2777 pub viewer: Viewer,
2778}
2779
2780/// `subscribe`: starts the card page for a feature's monthly plan. Owners
2781/// only. Returns `Outcome<Checkout>`; the page's id comes back to
2782/// `return_url` as `session`, for `confirm_subscription`.
2783#[derive(Debug, Serialize, Deserialize)]
2784#[serde(rename_all = "camelCase")]
2785pub struct SubscribeArgs {
2786 pub actor: User,
2787 pub workspace: String,
2788 pub feature: Feature,
2789 pub return_url: String,
2790}
2791
2792/// `confirm_subscription`: turns the feature on once the processor says
2793/// the plan was paid for. Safe to call any number of times. Returns
2794/// `Outcome<FeatureState>`.
2795#[derive(Debug, Serialize, Deserialize)]
2796pub struct ConfirmSubscriptionArgs {
2797 pub workspace: String,
2798 pub viewer: Viewer,
2799 pub session: String,
2800}
2801
2802/// `admin_log`: a staff change another service made to a workspace, kept
2803/// in sudo's audit log with billing's own (`admin_audit`). For identity's
2804/// restores and purges of deleted workspaces. Returns `bool`.
2805#[derive(Debug, Serialize, Deserialize)]
2806pub struct AdminLogArgs {
2807 pub workspace: String,
2808 pub action: String,
2809 pub detail: String,
2810 /// The staff member's email.
2811 pub by: String,
2812}
2813
2814/// `close_workspace`: settles a workspace that is about to be deleted.
2815/// Owners only. Refused while it has an invoice that failed, while it
2816/// holds prepaid credit, or while it owes money it cannot be charged for
2817/// now; otherwise what it owes is invoiced to its card at once (no
2818/// minimum), its plan is cancelled at Stripe straight away, and its
2819/// account is marked closed, so the month-end close, autopay and limit
2820/// warnings pass it by. Its ledger, invoices and statements stay. With
2821/// `dry_run`, only says whether it could, changing nothing. Returns
2822/// `Outcome<bool>`.
2823#[derive(Debug, Serialize, Deserialize)]
2824#[serde(rename_all = "camelCase")]
2825pub struct CloseWorkspaceArgs {
2826 pub actor: User,
2827 pub workspace: String,
2828 #[serde(default)]
2829 pub dry_run: bool,
2830}
2831
2832/// `cancel_subscription` (`resume` false) ends a plan at the end of the
2833/// period paid for; with `resume` true, takes that back. Owners only.
2834/// Returns `Outcome<FeatureState>`.
2835#[derive(Debug, Serialize, Deserialize)]
2836pub struct CancelSubscriptionArgs {
2837 pub actor: User,
2838 pub workspace: String,
2839 pub feature: Feature,
2840 #[serde(default)]
2841 pub resume: bool,
2842}
2843
2844/// `has_feature`: whether a feature works for a workspace now, asked by the
2845/// service that provides it before doing paid work. Returns
2846/// `Outcome<bool>`: a failure, with the reason to show, when it does not.
2847/// True everywhere when no card processor is configured.
2848#[derive(Debug, Serialize, Deserialize)]
2849pub struct HasFeatureArgs {
2850 pub workspace: String,
2851 pub feature: Feature,
2852}
2853
2854/// `free_workspaces`: which of `workspaces` are free, that is on no paid
2855/// plan. Paid is the g1t plan, an enterprise's terms, or a discount of
2856/// 100% (g1t's own workspaces). Identity asks before a workspace is made
2857/// (a person owns at most one free workspace) and before anyone is added
2858/// to one (a free workspace cannot invite). Returns `Vec<String>`, the
2859/// free ones, lower-cased; none where payments are not set up.
2860#[derive(Debug, Serialize, Deserialize)]
2861pub struct FreeWorkspacesArgs {
2862 pub workspaces: Vec<String>,
2863}
2864
2865/// `charge_feature`: usage of a feature past its plan's allowance, charged
2866/// from the workspace's credit at cost plus the margin, whatever
2867/// `FREE_WHILE_BUILDING` says. Called by the service that provides it.
2868/// Charged once per `reference`. Returns `Outcome<bool>`: false if that
2869/// reference was charged before.
2870#[derive(Debug, Serialize, Deserialize)]
2871#[serde(rename_all = "camelCase")]
2872pub struct ChargeFeatureArgs {
2873 pub workspace: String,
2874 pub feature: Feature,
2875 /// What it cost g1t, in millionths of a dollar, before the margin.
2876 pub cost_micros: i64,
2877 pub description: String,
2878 /// `namespace/name`, when the usage was one repository's.
2879 pub repo: Option<String>,
2880 /// Unique to this charge, e.g. `deployments/acme/2026-10`.
2881 pub reference: String,
2882 /// For a build: how long it ran. The plan's included build time this
2883 /// month pays for what it can, and only the rest of `cost_micros` is
2884 /// charged.
2885 #[serde(default)]
2886 pub build_seconds: Option<u32>,
2887}
2888
2889// ---------------------------------------------------------------------
2890// Costs and margin: what Cloudflare charges g1t against what g1t
2891// charges (billing's costs.rs, margin.rs and pricing.rs). Staff only.
2892// ---------------------------------------------------------------------
2893
2894/// `admin_costs`: the Costs & margin page. Returns `CostsReport`.
2895#[derive(Debug, Default, Serialize, Deserialize)]
2896pub struct AdminCostsArgs {
2897 /// How many days back, 7 to 90; 30 when absent.
2898 #[serde(default)]
2899 pub days: Option<u32>,
2900}
2901
2902/// One of g1t's products on one day.
2903#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2904#[serde(rename_all = "camelCase")]
2905pub struct CostDay {
2906 pub day: String,
2907 pub bucket: String,
2908 /// What Cloudflare charged g1t.
2909 pub cf_cost_micros: i64,
2910 /// What g1t's meters recorded it cost, at the price book's cost.
2911 pub own_cost_micros: i64,
2912 /// What customers were charged for it at price, before included
2913 /// usage, trials and pools paid for some.
2914 pub value_micros: i64,
2915 /// Of that, what workspaces paid.
2916 pub cash_micros: i64,
2917}
2918
2919/// One product over the range.
2920#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2921#[serde(rename_all = "camelCase")]
2922pub struct ProductMargin {
2923 pub bucket: String,
2924 pub title: String,
2925 /// The cost the margin is taken from: Cloudflare's bill, or g1t's own
2926 /// figure for what Cloudflare does not bill (models).
2927 pub cost_micros: i64,
2928 pub cf_cost_micros: i64,
2929 pub own_cost_micros: i64,
2930 pub value_micros: i64,
2931 pub margin_micros: i64,
2932 pub margin_percent: Option<f64>,
2933 /// `cloudflare` or `ledger`.
2934 pub cost_source: String,
2935 /// Running g1t itself, paid for by the plan.
2936 pub overhead: bool,
2937}
2938
2939/// All of g1t over the range: money in against every cost, and against
2940/// the cost of what was sold (every cost less what g1t gave away).
2941#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2942#[serde(rename_all = "camelCase")]
2943pub struct OverallMargin {
2944 /// What workspaces paid for usage, and for the plan.
2945 pub usage_micros: i64,
2946 pub plans_micros: i64,
2947 pub cost_micros: i64,
2948 pub margin_micros: i64,
2949 pub margin_percent: Option<f64>,
2950 /// Of `cost_micros`, what went on usage g1t gave away on purpose:
2951 /// comped workspaces, free periods, the trial and the open-source pool.
2952 #[serde(default)]
2953 pub given_micros: i64,
2954 /// Money in against `cost_micros - given_micros`.
2955 #[serde(default)]
2956 pub sold_margin_micros: i64,
2957 #[serde(default)]
2958 pub sold_margin_percent: Option<f64>,
2959 /// What was sold, apart: usage (`usage_micros` against what that usage
2960 /// cost, less what was given), running g1t (`plans_micros` against the
2961 /// platform's cost, less its given share) and what no mapping names.
2962 #[serde(default)]
2963 pub usage_cost_micros: i64,
2964 #[serde(default)]
2965 pub usage_margin_micros: i64,
2966 #[serde(default)]
2967 pub usage_margin_percent: Option<f64>,
2968 #[serde(default)]
2969 pub running_cost_micros: i64,
2970 #[serde(default)]
2971 pub unmapped_cost_micros: i64,
2972 /// `given_micros` by why: comped workspaces, free use (free periods,
2973 /// free allowances, overruns g1t covered), the trial, the open-source pool.
2974 #[serde(default)]
2975 pub given_comped_micros: i64,
2976 #[serde(default)]
2977 pub given_free_micros: i64,
2978 #[serde(default)]
2979 pub given_trial_micros: i64,
2980 #[serde(default)]
2981 pub given_pool_micros: i64,
2982 /// What discounts on an account's terms took below cost plus the
2983 /// margin: given, so a discounted sale is not margin lost.
2984 #[serde(default)]
2985 pub given_discount_micros: i64,
2986 /// Credits from g1t spent on usage, by kind: given, so usage paid for
2987 /// with them is never money in. Refunds are not here: they come off
2988 /// money in on the day they refund.
2989 #[serde(default)]
2990 pub given_credit_promotional_micros: i64,
2991 #[serde(default)]
2992 pub given_credit_goodwill_micros: i64,
2993 /// What testing resets wiped that g1t paid for (`reset_costs`): the
2994 /// model calls and Cloudflare usage still happened, so their cost is
2995 /// given, never a leak.
2996 #[serde(default)]
2997 pub given_reset_micros: i64,
2998 /// Credits over the range: given (every kind), spent on usage, and
2999 /// refunds' money given back.
3000 #[serde(default)]
3001 pub credits_given_micros: i64,
3002 #[serde(default)]
3003 pub credits_used_micros: i64,
3004 #[serde(default)]
3005 pub credits_refunded_micros: i64,
3006 /// `cost_micros` by who g1t pays: Cloudflare's bill (billed amounts,
3007 /// after the included allowances), and model providers (the ledger's
3008 /// cost of the tokens, which Cloudflare's bill does not show).
3009 /// What the plan's included usage paid for, at price (the ledger's
3010 /// `credit_micros`, comped workspaces left out): money in for usage,
3011 /// paid out of `plans_micros`.
3012 #[serde(default)]
3013 pub included_micros: i64,
3014 #[serde(default)]
3015 pub cloudflare_cost_micros: i64,
3016 #[serde(default)]
3017 pub models_cost_micros: i64,
3018 /// Tax collected with payments over the range, net of refunds: owed to
3019 /// the tax authorities, never in cash or revenue.
3020 #[serde(default)]
3021 pub tax_collected_micros: i64,
3022 /// Card processing fees passed on with card payments, net of refunds:
3023 /// they pay Stripe's fee, so they are not revenue either.
3024 #[serde(default)]
3025 pub card_fees_micros: i64,
3026}
3027
3028/// A count, cost or leak that does not add up.
3029#[derive(Clone, Debug, Serialize, Deserialize)]
3030#[serde(rename_all = "camelCase")]
3031pub struct CostDrift {
3032 pub bucket: String,
3033 pub title: String,
3034 /// `count` (units g1t counted against Cloudflare's), `cost` (the bill
3035 /// against the price book's cost of the same usage; for models, what AI
3036 /// Gateway priced g1t's provider traffic at against the ledger's model
3037 /// cost), `unpriced` (model usage AI Gateway put no price on, so its
3038 /// cost is not the providers'), or `leak`.
3039 pub kind: String,
3040 pub ours: f64,
3041 pub cloudflare: f64,
3042 pub delta_percent: Option<f64>,
3043 pub detail: String,
3044 pub found_at: String,
3045}
3046
3047/// A margin alert, open while its condition lasts.
3048#[derive(Clone, Debug, Serialize, Deserialize)]
3049#[serde(rename_all = "camelCase")]
3050pub struct MarginAlert {
3051 pub id: String,
3052 /// `margin`, `overall`, `leak`, `drift` or `workspace`.
3053 pub kind: String,
3054 /// The product, or the workspace.
3055 pub subject: String,
3056 pub detail: String,
3057 pub since: String,
3058 pub opened_at: String,
3059 pub emailed_at: Option<String>,
3060}
3061
3062/// A change to a price the reconciler measured.
3063#[derive(Clone, Debug, Serialize, Deserialize)]
3064#[serde(rename_all = "camelCase")]
3065pub struct PriceProposal {
3066 pub id: String,
3067 pub meter: String,
3068 pub title: String,
3069 pub unit: String,
3070 pub current_cost_micros: f64,
3071 pub proposed_cost_micros: f64,
3072 pub change_percent: f64,
3073 pub markup_percent: u32,
3074 pub reason: String,
3075 /// `keeper` or `reconciler`.
3076 pub source: String,
3077 /// Far off the current cost: look before approving.
3078 pub suspect: bool,
3079 /// `open`, `applied`, `approved`, `rejected` or `superseded`.
3080 pub status: String,
3081 pub created_at: String,
3082 pub decided_at: Option<String>,
3083 pub decided_by: Option<String>,
3084 pub note: Option<String>,
3085 /// When it takes or took effect, once approved or applied.
3086 pub effective_at: Option<String>,
3087}
3088
3089/// One version of one meter's price. Never changed once written.
3090#[derive(Clone, Debug, Serialize, Deserialize)]
3091#[serde(rename_all = "camelCase")]
3092pub struct PriceVersion {
3093 pub id: String,
3094 pub meter: String,
3095 pub version: u32,
3096 pub cost_micros: f64,
3097 pub markup_percent: u32,
3098 pub price_micros: f64,
3099 pub effective_at: String,
3100 pub reason: String,
3101 pub created_by: String,
3102 /// When the price book took it on; absent while it waits for its date.
3103 pub applied_at: Option<String>,
3104}
3105
3106/// What a workspace cost g1t over the range, Cloudflare's costs shared
3107/// out by g1t's own meters, against what it paid.
3108#[derive(Clone, Debug, Serialize, Deserialize)]
3109#[serde(rename_all = "camelCase")]
3110pub struct WorkspaceCost {
3111 pub workspace: String,
3112 pub cost_micros: i64,
3113 pub revenue_micros: i64,
3114 /// Of `cost_micros`, what g1t gave away.
3115 #[serde(default)]
3116 pub given_micros: i64,
3117 /// One of g1t's own (comped) workspaces.
3118 pub internal: bool,
3119}
3120
3121/// One Cloudflare meter over the range, and the product it is a cost of.
3122#[derive(Clone, Debug, Serialize, Deserialize)]
3123#[serde(rename_all = "camelCase")]
3124pub struct CostLineSummary {
3125 pub product: String,
3126 pub meter: String,
3127 pub raw_name: String,
3128 pub unit: String,
3129 pub source: String,
3130 pub quantity: f64,
3131 pub cost_micros: i64,
3132 /// Absent when no mapping claims it.
3133 pub bucket: Option<String>,
3134}
3135
3136/// A row of the mapping from Cloudflare's meters to g1t's products.
3137#[derive(Clone, Debug, Serialize, Deserialize)]
3138#[serde(rename_all = "camelCase")]
3139pub struct CostMapping {
3140 pub product: String,
3141 pub meter: String,
3142 pub bucket: String,
3143 pub price_meter: Option<String>,
3144 pub own_meter: Option<String>,
3145 pub scale_to_own: bool,
3146 pub drift_percent: f64,
3147 pub note: String,
3148 pub updated_at: String,
3149 pub updated_by: String,
3150}
3151
3152/// The guardrails on prices and the alerts.
3153#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3154#[serde(rename_all = "camelCase")]
3155pub struct CostSettings {
3156 /// Apply small moves without staff.
3157 pub auto_apply: bool,
3158 /// The largest move applied without staff, either way, in percent.
3159 pub auto_apply_percent: f64,
3160 /// Days between telling customers of a rise and charging it.
3161 pub notice_days: u32,
3162 /// Below this margin, in percent, for `alert_days` days in a row, alert.
3163 pub margin_floor_percent: f64,
3164 pub alert_days: u32,
3165 /// Days with less cost than this say nothing about a margin.
3166 pub min_daily_cost_micros: i64,
3167 /// A workspace costing more than its revenue times this, over 30 days,
3168 /// and at least `anomaly_floor_micros`, is flagged.
3169 pub anomaly_factor: f64,
3170 pub anomaly_floor_micros: i64,
3171 /// Pass Stripe's card fee on as its own line on every card payment (the
3172 /// plan, Security and quality, prepaying, AI credit, auto-reload and
3173 /// invoices charged to a card), never on a bank transfer or an invoice
3174 /// sent to be paid (`card_fee_percent` and `card_fee_fixed` in the
3175 /// price book). On by default.
3176 #[serde(default = "yes")]
3177 pub card_fee: bool,
3178}
3179
3180impl Default for CostSettings {
3181 fn default() -> Self {
3182 CostSettings {
3183 auto_apply: true,
3184 auto_apply_percent: 25.0,
3185 notice_days: 14,
3186 margin_floor_percent: 10.0,
3187 alert_days: 3,
3188 min_daily_cost_micros: 100_000,
3189 anomaly_factor: 1.0,
3190 anomaly_floor_micros: 1_000_000,
3191 card_fee: true,
3192 }
3193 }
3194}
3195
3196/// The Costs & margin page.
3197#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3198#[serde(rename_all = "camelCase")]
3199pub struct CostsReport {
3200 /// A token to read Cloudflare's bill is set.
3201 pub configured: bool,
3202 /// When Cloudflare's bill was last read.
3203 pub fetched_at: Option<String>,
3204 /// The days shown, YYYY-MM-DD.
3205 pub since: String,
3206 pub until: String,
3207 pub days: Vec<CostDay>,
3208 pub products: Vec<ProductMargin>,
3209 pub overall: OverallMargin,
3210 pub drift: Vec<CostDrift>,
3211 pub alerts: Vec<MarginAlert>,
3212 pub proposals: Vec<PriceProposal>,
3213 pub versions: Vec<PriceVersion>,
3214 pub top_workspaces: Vec<WorkspaceCost>,
3215 pub lines: Vec<CostLineSummary>,
3216 pub mappings: Vec<CostMapping>,
3217 pub settings: CostSettings,
3218 /// g1t's own spend against its two caps.
3219 #[serde(default)]
3220 pub caps: SpendCaps,
3221}
3222
3223/// What g1t itself pays for, against its caps (billing's `budget`): the
3224/// daily breaker on all of it, and each comped account's monthly budget.
3225/// One of Cloudflare's subscriptions, at what it comes to a month.
3226#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
3227#[serde(rename_all = "camelCase")]
3228pub struct FixedCost {
3229 pub name: String,
3230 pub monthly_micros: i64,
3231}
3232
3233/// At cost, never at price. What sudo's Costs page and its red bar show.
3234#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3235#[serde(rename_all = "camelCase")]
3236pub struct SpendCaps {
3237 /// Today (UTC), YYYY-MM-DD, and this month, YYYY-MM.
3238 pub day: String,
3239 pub month: String,
3240 /// What g1t paid for itself today across every workspace: comped work,
3241 /// the trial and open-source pools, free workspaces' overruns, and
3242 /// anything charged without real money behind it.
3243 pub today_micros: i64,
3244 /// `PLATFORM_DAILY_SPEND_CAP_MICROS`. Zero: no breaker.
3245 pub daily_cap_micros: i64,
3246 /// The breaker is open: new hosted-model agent runs that g1t would pay
3247 /// for wait until tomorrow (UTC) or until staff lift it.
3248 pub tripped: bool,
3249 pub tripped_at: Option<String>,
3250 /// Staff lifted it for the rest of the day.
3251 pub lifted_by: Option<String>,
3252 pub lifted_at: Option<String>,
3253 pub lift_note: Option<String>,
3254 /// This month so far, by what paid: `comped`, `trial`, `oss`, `given`,
3255 /// `unpaid`.
3256 pub month_buckets: Vec<SpendBucket>,
3257 /// Each comped account's monthly budget.
3258 pub comped: Vec<CompedBudget>,
3259 /// Free workspaces' share of this month's reconciled costs (git,
3260 /// storage, platform), through yesterday.
3261 pub free_tier_micros: i64,
3262 /// Cloudflare's subscriptions a month: as read from Cloudflare each
3263 /// day, else `CLOUDFLARE_FIXED_MONTHLY_MICROS`, an estimate.
3264 pub fixed_monthly_micros: i64,
3265 /// `cloudflare` or `estimate`.
3266 #[serde(default)]
3267 pub fixed_source: String,
3268 #[serde(default)]
3269 pub fixed_read_at: Option<String>,
3270 /// Each subscription, when read from Cloudflare.
3271 #[serde(default)]
3272 pub fixed_items: Vec<FixedCost>,
3273 /// Money in this month, through the last reconciled day.
3274 pub revenue_micros: i64,
3275}
3276
3277#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3278#[serde(rename_all = "camelCase")]
3279pub struct SpendBucket {
3280 pub bucket: String,
3281 pub title: String,
3282 pub micros: i64,
3283}
3284
3285/// A comped account's monthly budget: what its work cost g1t this month.
3286#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3287#[serde(rename_all = "camelCase")]
3288pub struct CompedBudget {
3289 pub account: String,
3290 pub name: String,
3291 pub used_micros: i64,
3292 /// Zero: no budget.
3293 pub ceiling_micros: i64,
3294 /// The ceiling is `COMPED_MONTHLY_CEILING_MICROS`, not the account's own.
3295 pub default_ceiling: bool,
3296 /// 50, 75, 90, 100, or 0.
3297 pub level: u32,
3298}
3299
3300/// `admin_spend_caps`: g1t's own spend against its caps. Returns `SpendCaps`.
3301#[derive(Debug, Default, Serialize, Deserialize)]
3302pub struct AdminSpendCapsArgs {}
3303
3304/// `admin_lift_breaker`: lets hosted-model runs start again for the rest
3305/// of today (UTC), with why. Recorded in the audit log. Returns
3306/// `Outcome<SpendCaps>`.
3307#[derive(Debug, Serialize, Deserialize)]
3308pub struct AdminLiftBreakerArgs {
3309 pub note: String,
3310 pub by: String,
3311}
3312
3313/// `admin_cost_alerts`: the open margin alerts, for sudo's banner.
3314/// Returns `Vec<MarginAlert>`.
3315#[derive(Debug, Default, Serialize, Deserialize)]
3316pub struct AdminCostAlertsArgs {}
3317
3318/// `admin_decide_proposal`: approve or reject a price proposal. An
3319/// approved rise takes effect after the notice period. Returns
3320/// `Outcome<PriceProposal>`.
3321#[derive(Debug, Serialize, Deserialize)]
3322pub struct AdminDecideProposalArgs {
3323 pub id: String,
3324 /// `approve` or `reject`.
3325 pub decision: String,
3326 #[serde(default)]
3327 pub note: String,
3328 pub by: String,
3329}
3330
3331/// `admin_set_cost_settings`. Returns `Outcome<CostSettings>`.
3332#[derive(Debug, Serialize, Deserialize)]
3333pub struct AdminSetCostSettingsArgs {
3334 pub settings: CostSettings,
3335 pub by: String,
3336}
3337
3338/// `admin_set_cost_mapping`: adds, changes or (with `remove`) removes a
3339/// mapping row. Returns `Outcome<CostMapping>`.
3340#[derive(Debug, Serialize, Deserialize)]
3341pub struct AdminSetCostMappingArgs {
3342 pub product: String,
3343 pub meter: String,
3344 #[serde(default)]
3345 pub bucket: String,
3346 #[serde(default)]
3347 pub price_meter: Option<String>,
3348 #[serde(default)]
3349 pub own_meter: Option<String>,
3350 #[serde(default)]
3351 pub scale_to_own: bool,
3352 #[serde(default)]
3353 pub drift_percent: Option<f64>,
3354 #[serde(default)]
3355 pub note: String,
3356 #[serde(default)]
3357 pub remove: bool,
3358 pub by: String,
3359}
3360
3361/// `admin_run_costs`: reads Cloudflare's bill and reconciles now, as the
3362/// daily run does. Returns `Outcome<CostsRun>`.
3363#[derive(Debug, Default, Serialize, Deserialize)]
3364pub struct AdminRunCostsArgs {
3365 #[serde(default)]
3366 pub by: String,
3367}
3368
3369#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3370#[serde(rename_all = "camelCase")]
3371pub struct CostsRun {
3372 pub lines: u32,
3373 pub days: u32,
3374 pub proposals: u32,
3375 pub alerts: u32,
3376 /// What could not be read, in words.
3377 pub problems: Vec<String>,
3378}
3379
3380// --- The Usage page ----------------------------------------------------------
3381
3382/// The product families the Usage page groups meters into, in order, with
3383/// their names.
3384pub const PRODUCTS: [(&str, &str); 8] = [
3385 ("agent", "Agent"),
3386 ("sandboxes", "Sandboxes"),
3387 ("gateway", "AI Gateway"),
3388 ("deployments", "Deployments"),
3389 ("git_storage", "Git & storage"),
3390 ("packages", "Packages"),
3391 ("security", "Security & quality"),
3392 ("search", "Search"),
3393];
3394
3395/// `usage_report`: a workspace's usage over a range of days, at price, by
3396/// product, meter, project and day. The figures are the ledger's: the same
3397/// lines the statement and invoices read, so every page agrees. Members
3398/// only. Returns `Outcome<UsageReport>`.
3399#[derive(Debug, Serialize, Deserialize)]
3400#[serde(rename_all = "camelCase")]
3401pub struct UsageReportArgs {
3402 pub workspace: String,
3403 pub viewer: Viewer,
3404 /// The first day, `YYYY-MM-DD` (UTC).
3405 pub from: String,
3406 /// The last day, `YYYY-MM-DD`, included.
3407 pub until: String,
3408 /// Only these product families (`agent`, `sandboxes`…); all when empty.
3409 #[serde(default)]
3410 pub products: Vec<String>,
3411 /// Only these projects (repositories, `owner/name`); all when empty.
3412 #[serde(default)]
3413 pub projects: Vec<String>,
3414}
3415
3416/// What usage came to over a range, and what paid for it. `price_micros`
3417/// less `discount_micros`, `included_micros` and `credits_micros` is
3418/// `charged_micros`.
3419#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
3420#[serde(rename_all = "camelCase")]
3421pub struct UsageTotals {
3422 /// Usage at price, metered usage not yet charged (`pending_micros`)
3423 /// included.
3424 pub price_micros: i64,
3425 /// What the account's discount took off.
3426 pub discount_micros: i64,
3427 /// What the plan's included usage, the trial and g1t's pools paid.
3428 pub included_micros: i64,
3429 /// What credit paid: AI credit, credit from g1t.
3430 pub credits_micros: i64,
3431 /// What is left for the workspace to pay.
3432 pub charged_micros: i64,
3433 /// Metered this month and charged when it closes (storage, git
3434 /// operations, scans, embeddings, domains), at price.
3435 pub pending_micros: i64,
3436 /// What it cost g1t, before any markup.
3437 pub cost_micros: i64,
3438}
3439
3440/// One day's usage of one product, at price.
3441#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3442#[serde(rename_all = "camelCase")]
3443pub struct UsageDay {
3444 /// `YYYY-MM-DD`.
3445 pub day: String,
3446 pub product: String,
3447 pub micros: i64,
3448}
3449
3450/// How much of an allowance is used, in the meter's unit.
3451#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3452#[serde(rename_all = "camelCase")]
3453pub struct Allowance {
3454 pub used: f64,
3455 pub of: f64,
3456 /// `bytes`, `operations`, `dollars`…
3457 pub unit: String,
3458}
3459
3460/// One project's part of a meter.
3461#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3462#[serde(rename_all = "camelCase")]
3463pub struct ProjectUsage {
3464 /// `owner/name`, or empty for usage that is not one project's.
3465 pub project: String,
3466 pub micros: i64,
3467 pub quantity: f64,
3468}
3469
3470/// One meter over the range.
3471#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3472#[serde(rename_all = "camelCase")]
3473pub struct MeterLine {
3474 /// `agent_models`, `agent_rate`, `sandbox`, `builds`…
3475 pub key: String,
3476 pub label: String,
3477 pub product: String,
3478 /// What `quantity` counts: `tokens`, `seconds`, `bytes`, `operations`,
3479 /// `entries`.
3480 pub unit: String,
3481 pub quantity: f64,
3482 /// At price.
3483 pub micros: i64,
3484 /// Of `micros`, metered this month and charged when it closes.
3485 #[serde(default)]
3486 pub pending_micros: i64,
3487 /// Every day of the range, oldest first, at price: the sparkline.
3488 pub daily: Vec<i64>,
3489 #[serde(default)]
3490 pub allowance: Option<Allowance>,
3491 pub by_project: Vec<ProjectUsage>,
3492 /// How the quantity is counted, when that needs saying: for the agent
3493 /// rate, its tokens are weighted by kind, and this names the weights.
3494 #[serde(default)]
3495 pub note: Option<String>,
3496}
3497
3498/// A part of a product, such as the agent's runs, reviews and plans.
3499#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3500#[serde(rename_all = "camelCase")]
3501pub struct FeatureUsage {
3502 pub key: String,
3503 pub label: String,
3504 pub micros: i64,
3505 pub count: u32,
3506}
3507
3508/// The tokens one model used over the range, as the model proxy counted
3509/// them: on g1t's models and the workspace's own provider alike.
3510#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
3511#[serde(rename_all = "camelCase")]
3512pub struct ModelTokens {
3513 /// The model's id, as it ran.
3514 pub model: String,
3515 pub input: u64,
3516 pub output: u64,
3517 pub cache_read: u64,
3518 pub cache_write: u64,
3519}
3520
3521/// One product family over the range.
3522#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3523#[serde(rename_all = "camelCase")]
3524pub struct ProductUsage {
3525 pub key: String,
3526 pub label: String,
3527 pub micros: i64,
3528 pub meters: Vec<MeterLine>,
3529 /// For the agent: by what it was doing (runs, reviews, plans, checks).
3530 #[serde(default)]
3531 pub features: Vec<FeatureUsage>,
3532}
3533
3534#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3535#[serde(rename_all = "camelCase")]
3536pub struct UsageReport {
3537 pub from: String,
3538 pub until: String,
3539 pub totals: UsageTotals,
3540 /// Each day and product with usage, oldest first.
3541 pub days: Vec<UsageDay>,
3542 /// Every product family, in order, even with nothing used.
3543 pub products: Vec<ProductUsage>,
3544 /// Every project with usage in the range, for the filter.
3545 pub projects: Vec<String>,
3546 /// Agent tokens by model over the range, most first.
3547 #[serde(default)]
3548 pub models: Vec<ModelTokens>,
3549 /// The plan's included usage this month, when the workspace has it.
3550 #[serde(default)]
3551 pub included: Option<Allowance>,
3552 /// The account's discount, in percent, when it has one.
3553 #[serde(default)]
3554 pub discount_percent: Option<u32>,
3555 /// AI credit left now, and credit from g1t for everything.
3556 pub ai_credit_micros: i64,
3557 pub credit_micros: i64,
3558 /// The trial credit left, for a workspace on its trial.
3559 #[serde(default)]
3560 pub trial_micros: Option<i64>,
3561 pub plan: PlanKind,
3562 /// Nothing is charged while g1t is being built out.
3563 pub free: bool,
3564}
3565
3566// --- AI credit -----------------------------------------------------------------
3567
3568/// Auto-reload: when AI credit falls below `threshold_micros`, the saved
3569/// card is charged to bring it back to `target_micros`, at most
3570/// `monthly_max_micros` in a calendar month. Off by default. A failed
3571/// charge turns it off and tells the owners.
3572#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
3573#[serde(rename_all = "camelCase")]
3574pub struct AiReload {
3575 pub enabled: bool,
3576 pub threshold_micros: i64,
3577 pub target_micros: i64,
3578 pub monthly_max_micros: i64,
3579 /// Reloaded this month so far.
3580 #[serde(default)]
3581 pub reloaded_micros: i64,
3582 /// When it last failed and was turned off, and why.
3583 #[serde(default)]
3584 pub failed_at: Option<String>,
3585 #[serde(default)]
3586 pub error: Option<String>,
3587}
3588
3589/// The card fee passed on when AI credit is bought by card.
3590#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
3591#[serde(rename_all = "camelCase")]
3592pub struct CardFee {
3593 pub on: bool,
3594 /// Per dollar charged, in millionths: 29,000 is 2.9%.
3595 pub percent_micros: f64,
3596 pub fixed_cents: u32,
3597}
3598
3599/// `ai_credit` (`AccountArgs`): a workspace's prepaid AI credit, what it
3600/// pays for and how it is bought. Members only. Returns `Outcome<AiCredit>`.
3601#[derive(Clone, Debug, Serialize, Deserialize)]
3602#[serde(rename_all = "camelCase")]
3603pub struct AiCredit {
3604 /// What is left to spend on Agent and AI Gateway usage.
3605 pub balance_micros: i64,
3606 /// Of it, bought (paid) and given (promotional).
3607 pub purchased_micros: i64,
3608 pub given_micros: i64,
3609 /// Its grants, newest first.
3610 pub grants: Vec<CreditGrant>,
3611 /// A 100% discount: AI usage is free, shown at its price then the
3612 /// discount. Nothing to buy.
3613 pub free_via_discount: bool,
3614 /// Invoiced terms (an enterprise): models are billed after use, so no
3615 /// credit is needed.
3616 pub postpaid: bool,
3617 /// Whether new runs on g1t's models are refused now for want of credit.
3618 pub blocked: bool,
3619 /// Whether the workspace may buy it: on the plan, not free.
3620 pub can_buy: bool,
3621 pub presets_cents: Vec<u32>,
3622 pub min_cents: u32,
3623 pub max_cents: u32,
3624 pub card_fee: CardFee,
3625 pub reload: AiReload,
3626 /// The agent rate per million tokens, now, at price.
3627 pub agent_rate_micros: f64,
3628 /// The markup on models' provider price, in percent.
3629 pub model_markup_percent: u32,
3630 /// The markup on AI Gateway's provider price, in percent.
3631 pub gateway_markup_percent: u32,
3632 /// The AI credit given once on starting the plan.
3633 pub upgrade_credit_micros: i64,
3634 /// How long bought credit lasts, in days.
3635 pub expires_days: u32,
3636}
3637
3638/// `buy_ai_credit`: Stripe's page to buy AI credit, one payment by card,
3639/// with the card fee as its own line. Owners only. Returns
3640/// `Outcome<Checkout>`; the page's id comes back to `return_url` as
3641/// `ai_credit`, for `confirm_ai_credit`.
3642#[derive(Debug, Serialize, Deserialize)]
3643#[serde(rename_all = "camelCase")]
3644pub struct BuyAiCreditArgs {
3645 pub actor: User,
3646 pub workspace: String,
3647 /// The credit, in cents; the card fee is added on top.
3648 #[serde(alias = "amount_cents")]
3649 pub amount_cents: u32,
3650 #[serde(alias = "return_url")]
3651 pub return_url: String,
3652}
3653
3654/// `confirm_ai_credit`: credits a purchase once Stripe says it was paid,
3655/// once. Safe to repeat; the webhook does the same. Returns
3656/// `Outcome<AiCredit>`.
3657#[derive(Debug, Serialize, Deserialize)]
3658pub struct ConfirmAiCreditArgs {
3659 pub workspace: String,
3660 pub viewer: Viewer,
3661 pub session: String,
3662}
3663
3664/// `set_ai_reload`: auto-reload's settings. Owners only. Returns
3665/// `Outcome<AiCredit>`.
3666#[derive(Debug, Serialize, Deserialize)]
3667#[serde(rename_all = "camelCase")]
3668pub struct SetAiReloadArgs {
3669 pub actor: User,
3670 pub workspace: String,
3671 pub enabled: bool,
3672 #[serde(alias = "threshold_micros")]
3673 pub threshold_micros: i64,
3674 #[serde(alias = "target_micros")]
3675 pub target_micros: i64,
3676 #[serde(alias = "monthly_max_micros")]
3677 pub monthly_max_micros: i64,
3678}
3679
3680// --- Budgets ------------------------------------------------------------------
3681
3682/// `set_budget`: the monthly budget on usage after included usage: the
3683/// owners' spend limit, its alerts, whether usage pauses at 100%, and an
3684/// optional webhook. Owners only. Returns `Outcome<Limit>`.
3685#[derive(Debug, Serialize, Deserialize)]
3686#[serde(rename_all = "camelCase")]
3687pub struct SetBudgetArgs {
3688 pub actor: User,
3689 pub workspace: String,
3690 /// The amount; None keeps the automatic one.
3691 #[serde(default, alias = "amount_micros")]
3692 pub amount_micros: Option<i64>,
3693 /// Some of 50, 75, 90 and 100.
3694 #[serde(default)]
3695 pub alerts: Vec<u32>,
3696 #[serde(default = "yes", alias = "pause_at_limit")]
3697 pub pause_at_limit: bool,
3698 /// An HTTPS address, or None for no webhook.
3699 #[serde(default)]
3700 pub webhook: Option<String>,
3701 /// Leave the spend limit as it is and change only the alerts, the
3702 /// pause and the webhook.
3703 #[serde(default, alias = "keep_limit")]
3704 pub keep_limit: bool,
3705}
3706
3707// --- Billing details -----------------------------------------------------------
3708
3709/// A postal address, as Stripe keeps it.
3710#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
3711#[serde(rename_all = "camelCase")]
3712pub struct PostalAddress {
3713 #[serde(default)]
3714 pub line1: String,
3715 #[serde(default)]
3716 pub line2: String,
3717 #[serde(default)]
3718 pub city: String,
3719 #[serde(default)]
3720 pub state: String,
3721 #[serde(default)]
3722 pub postal_code: String,
3723 /// Two letters, `US`.
3724 #[serde(default)]
3725 pub country: String,
3726}
3727
3728/// The default way the workspace pays, as far as it is safe to show.
3729#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3730#[serde(rename_all = "camelCase")]
3731pub struct PaymentMethod {
3732 /// `card`, or another kind Stripe has.
3733 pub kind: String,
3734 #[serde(default)]
3735 pub brand: Option<String>,
3736 #[serde(default)]
3737 pub last4: Option<String>,
3738 #[serde(default)]
3739 pub exp_month: Option<u32>,
3740 #[serde(default)]
3741 pub exp_year: Option<u32>,
3742}
3743
3744/// One of the customer's invoices at Stripe: the plan, activations, AI
3745/// credit and month-end usage.
3746#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3747#[serde(rename_all = "camelCase")]
3748pub struct StripeInvoice {
3749 pub id: String,
3750 #[serde(default)]
3751 pub number: Option<String>,
3752 /// `paid`, `open`, `void`, `uncollectible` or `draft`.
3753 pub status: String,
3754 pub total_cents: i64,
3755 pub currency: String,
3756 /// RFC 3339.
3757 pub created_at: String,
3758 #[serde(default)]
3759 pub description: Option<String>,
3760 #[serde(default)]
3761 pub hosted_url: Option<String>,
3762 #[serde(default)]
3763 pub pdf_url: Option<String>,
3764}
3765
3766/// What the next invoice will be, from g1t's own ledger.
3767#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
3768#[serde(rename_all = "camelCase")]
3769pub struct UpcomingInvoice {
3770 /// When the month closes, RFC 3339.
3771 pub closes_at: String,
3772 /// The plan and activations, at their monthly price.
3773 pub subscriptions_micros: i64,
3774 /// Usage still owed, after included usage, credit and any discount.
3775 pub usage_micros: i64,
3776 pub total_micros: i64,
3777}
3778
3779/// `billing_details` (`AccountArgs`): who the invoices are for, the default
3780/// payment method, and the invoices, from the Stripe customer. Members see
3781/// it; owners change it. Returns `Outcome<BillingDetails>`.
3782#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
3783#[serde(rename_all = "camelCase")]
3784pub struct BillingDetails {
3785 /// Whether the workspace has a Stripe customer yet.
3786 pub customer: bool,
3787 pub email: Option<String>,
3788 pub name: Option<String>,
3789 pub address: Option<PostalAddress>,
3790 /// `eu_vat`, `us_ein`…, and its value.
3791 pub tax_id_type: Option<String>,
3792 pub tax_id: Option<String>,
3793 /// Printed on invoices.
3794 pub po_number: Option<String>,
3795 /// The invoices' language, such as `en` or `fr`.
3796 pub language: Option<String>,
3797 pub payment_method: Option<PaymentMethod>,
3798 pub invoices: Vec<StripeInvoice>,
3799 pub upcoming: UpcomingInvoice,
3800 /// Stripe could not be read: what is shown is what g1t keeps.
3801 #[serde(default)]
3802 pub unavailable: Option<String>,
3803 /// Whether Stripe Tax can place the customer from the address: tax
3804 /// is worked out from it, and without it nothing is charged.
3805 #[serde(default)]
3806 pub tax_location: bool,
3807 /// Set when g1t did not charge for want of an address (RFC 3339).
3808 #[serde(default)]
3809 pub tax_address_needed_at: Option<String>,
3810 /// Stripe's check of the tax ID: `pending`, `verified`, `unverified` or
3811 /// `unavailable`.
3812 #[serde(default)]
3813 pub tax_id_status: Option<String>,
3814 /// `none`, `exempt` or `reverse`, as staff set it at Stripe; g1t never
3815 /// changes it.
3816 #[serde(default)]
3817 pub tax_exempt: Option<String>,
3818}
3819
3820/// `set_billing_details`: saves the invoice details on the Stripe customer.
3821/// Owners only. Absent fields are left as they are; an empty string clears
3822/// one. Returns `Outcome<BillingDetails>`.
3823#[derive(Debug, Serialize, Deserialize)]
3824#[serde(rename_all = "camelCase")]
3825pub struct SetBillingDetailsArgs {
3826 pub actor: User,
3827 pub workspace: String,
3828 #[serde(default)]
3829 pub email: Option<String>,
3830 #[serde(default)]
3831 pub name: Option<String>,
3832 #[serde(default)]
3833 pub address: Option<PostalAddress>,
3834 #[serde(default, alias = "tax_id_type")]
3835 pub tax_id_type: Option<String>,
3836 #[serde(default, alias = "tax_id")]
3837 pub tax_id: Option<String>,
3838 #[serde(default, alias = "po_number")]
3839 pub po_number: Option<String>,
3840 #[serde(default)]
3841 pub language: Option<String>,
3842}
3843
3844#[cfg(test)]
3845mod tests {
3846 use super::*;
3847
3848 #[test]
3849 fn an_account_carries_no_run_fee() {
3850 let account = Account {
3851 workspace: "acme".into(),
3852 balance_micros: 0,
3853 status: Status { enabled: true, live: false, free: false },
3854 margin_percent: 20,
3855 card: None,
3856 };
3857 let json = serde_json::to_value(account).unwrap();
3858 let mut keys: Vec<&str> = json.as_object().unwrap().keys().map(String::as_str).collect();
3859 keys.sort_unstable();
3860 assert_eq!(keys, ["balanceMicros", "card", "marginPercent", "status", "workspace"]);
3861 }
3862
3863 #[test]
3864 fn a_price_change_says_when_the_markup_moved() {
3865 let change = PriceChange {
3866 meter: "sandbox_second".into(),
3867 old_cost_micros: 21.0,
3868 new_cost_micros: 21.0,
3869 markup_percent: 20,
3870 old_markup_percent: Some(138),
3871 reason: "Sandbox time is now charged at cost plus 20% from the first second".into(),
3872 created_at: "2026-10-05T00:00:00Z".into(),
3873 effective_at: None,
3874 };
3875 assert_eq!(serde_json::to_value(&change).unwrap()["oldMarkupPercent"], 138);
3876 let cost_only = PriceChange { old_markup_percent: None, ..change };
3877 assert!(serde_json::to_value(&cost_only).unwrap().get("oldMarkupPercent").is_none());
3878 }
3879
3880 #[test]
3881 fn features_are_named_as_the_site_sends_them() {
3882 assert_eq!(
3883 serde_json::to_value(Feature::Deployments).unwrap(),
3884 serde_json::json!("deployments")
3885 );
3886 assert_eq!(Feature::parse("deployments"), Some(Feature::Deployments));
3887 assert_eq!(serde_json::to_value(Feature::Plan).unwrap(), serde_json::json!("plan"));
3888 assert_eq!(Feature::parse("plan"), Some(Feature::Plan));
3889 // Older readers named the plan Team.
3890 assert_eq!(Feature::parse("team"), Some(Feature::Plan));
3891 assert_eq!(serde_json::from_value::<Feature>(serde_json::json!("team")).unwrap(), Feature::Plan);
3892 assert_eq!(Feature::ALL, [Feature::Plan, Feature::Security]);
3893 assert_eq!(Feature::parse("security"), Some(Feature::Security));
3894 assert_eq!(serde_json::to_value(Feature::Security).unwrap(), serde_json::json!("security"));
3895 assert!(SubscriptionStatus::Canceling.on());
3896 assert!(!SubscriptionStatus::PastDue.on());
3897 }
3898
3899 #[test]
3900 fn a_reservation_is_asked_for_and_answered_in_camel_case() {
3901 let asked: ReserveArgs = serde_json::from_value(serde_json::json!({
3902 "workspace": "acme",
3903 "repo": { "namespace": "acme", "name": "web" },
3904 "public": true,
3905 "kind": "check",
3906 "estimateMicros": 2_000_000,
3907 }))
3908 .unwrap();
3909 assert_eq!(asked.kind, ComputeKind::Check);
3910 assert!(asked.kind.open_source_pool());
3911 assert!(!ComputeKind::Agent.open_source_pool());
3912 // Rust callers that write snake_case are read too.
3913 let snake: ReserveArgs = serde_json::from_value(serde_json::json!({
3914 "workspace": "acme",
3915 "repo": { "namespace": "acme", "name": "web" },
3916 "public": false,
3917 "kind": "agent",
3918 "estimate_micros": 1,
3919 }))
3920 .unwrap();
3921 assert_eq!(snake.estimate_micros, 1);
3922 let answer = Reservation { id: "rsv_1".into(), paid_by: PaidBy::OnDemand, held_micros: 5, expires_at: String::new() };
3923 assert_eq!(serde_json::to_value(&answer).unwrap()["paidBy"], "on_demand");
3924 assert_eq!(serde_json::to_value(PlanKind::Internal).unwrap(), "internal");
3925 assert!(!PlanKind::Free.on_demand() && PlanKind::Enterprise.on_demand());
3926 }
3927
3928 #[test]
3929 fn a_refusal_carries_its_own_code() {
3930 let refused: crate::Outcome<Reservation> =
3931 crate::Outcome::fail(crate::FailureCode::OssPoolEmpty, "The open-source pool is spent.");
3932 let json = serde_json::to_value(&refused).unwrap();
3933 assert_eq!(json["error"]["code"], "oss_pool_empty");
3934 assert_eq!(crate::FailureCode::NotPaid.http_status(), 402);
3935 assert_eq!(crate::FailureCode::Paused.http_status(), 409);
3936 }
3937
3938 #[test]
3939 fn who_pays_is_read_as_the_runner_sends_it() {
3940 let run: StartRunArgs = serde_json::from_value(serde_json::json!({
3941 "workspace": "acme",
3942 "repo": { "namespace": "acme", "name": "web" },
3943 "number": 7,
3944 "task": "implement",
3945 "model": "Claude Sonnet 5.5",
3946 "billedTo": "workspace",
3947 }))
3948 .unwrap();
3949 assert_eq!(run.billed_to, "workspace");
3950 }
3951}