Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

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