Skip to content
4,608 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1//! 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,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging193 /// 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>,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays201}
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,
Merge branch 'model-routing'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.
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays281 #[serde(default)]
282 pub session: Option<String>,
Merge branch 'model-routing'283 /// `small`, `large` or `frontier`: the tier g1t routed the run to.
284 /// None when the workspace's own provider names its model.
Auto model routing: the cheapest tier that can do each piece of work, a retry goes up a tier, and each run records its tier285 #[serde(default)]
286 pub tier: Option<String>,
Spend adds up on one ledger. Charged this month has one definition, price less discount, included usage and credit, shared by the plan card, the spend limit, Spend and the top bar; the limit had counted usage not yet closed at full price before the discount, so a comped workspace read as charged a cent. Every agent line on the ledger names the agent and who asked, repository runs by g1t included, so Spent is the sum of its products, Agents is the agent product, and by agent adds up to it; the billing API returns by_agent and by_person. The usage and billing guide says how spend is counted.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>,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays297}
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,
Merge branch 'model-routing'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 }
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays344}
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,
Billing and Usage reconcile: own-provider runs leave Billing's at-price total, and Usage's not-charged part is at price less charged373 /// 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.
Billing's usage total is labeled at price, and Usage says what part of it was paid for376 #[serde(default)]
377 pub covered_micros: i64,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging378 /// 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>,
Usage, Billing settings and prepaid AI credit; fixes from the UX audit386 /// 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,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays392 /// 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
Mission control shows model usage, yours and the workspace's: tokens, cost, active days, cache share, each day, and the mix418/// `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,
Merge branch 'model-routing'432 /// The tier g1t routed the run to: `small`, `large` or `frontier`.
Mission control shows model usage, yours and the workspace's: tokens, cost, active days, cache share, each day, and the mix433 #[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
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens491// --- AI Gateway -------------------------------------------------------------
492//
493// A workspace's own model requests, sent with one of its access tokens to
AI Gateway: OpenAI's format, open models, and your own providers494// 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
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens497// 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 {
AI Gateway: OpenAI's format, open models, and your own providers507 /// 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`).
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens511 pub model: String,
512 /// For people: `Claude Sonnet 5.5`.
513 pub name: String,
AI Gateway: OpenAI's format, open models, and your own providers514 /// `anthropic` or `workers-ai`.
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens515 pub provider: String,
AI Gateway: OpenAI's format, open models, and your own providers516 /// `chat`, or `embeddings` for a model that only embeds text.
517 #[serde(default = "chat")]
518 pub kind: String,
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens519 pub input_micros: i64,
520 pub output_micros: i64,
521 pub cache_read_micros: i64,
AI Gateway: OpenAI's format, open models, and your own providers522 /// Cache writes that live five minutes.
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens523 pub cache_write_micros: i64,
AI Gateway: OpenAI's format, open models, and your own providers524 /// 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,
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens542}
543
AI Gateway: OpenAI's format, open models, and your own providers544fn chat() -> String {
545 "chat".to_owned()
546}
547
548fn anthropic_format() -> String {
549 "anthropic".to_owned()
550}
551
Merge branch 'main' into actions-toolkit-oidc-artifacts552// --- 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
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens870/// `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,
AI Gateway: OpenAI's format, open models, and your own providers901 /// Every cache write, of either lifetime.
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens902 #[serde(default)]
903 pub cache_write: u64,
AI Gateway: OpenAI's format, open models, and your own providers904 /// Of `cache_write`, those that live an hour.
905 #[serde(default)]
906 pub cache_write_hour: u64,
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens907 /// 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,
AI Gateway: OpenAI's format, open models, and your own providers912 /// 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.
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens921 #[serde(default)]
AI Gateway: OpenAI's format, open models, and your own providers922 pub connection: Option<String>,
923 #[serde(default)]
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens924 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,
AI Gateway: OpenAI's format, open models, and your own providers960 /// Of `cache_write`, those that live an hour.
961 #[serde(default)]
962 pub cache_write_hour: u64,
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens963 /// 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,
AI Gateway: OpenAI's format, open models, and your own providers970 /// `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>,
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens980 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
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays996/// 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,
Pricing says it plainly: models at the provider's price, the agent rate for what g1t runs around every model call (the gateway, secrets, routing, context and pass-through to your own provider, so your own keys too), everything else at cost plus 20%, your own runners free, no seats; Security and quality comes with the plan with no separate fee, and live activations end. Each agent has an effort setting, Auto to Max, with what a typical task has cost at each level, and Spend's Spend less, keep quality suggests a lower level only when the agent's own past work shows quality held, to apply or dismiss. The pricing, spend and agents guides say how.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.
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar1018 Security,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1019}
1020
1021impl Feature {
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar1022 /// What is sold: the plan, and the Security and quality activation.
1023 pub const ALL: [Feature; 2] = [Feature::Plan, Feature::Security];
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1024
1025 pub fn as_str(self) -> &'static str {
1026 match self {
1027 Feature::Plan => "plan",
1028 Feature::Deployments => "deployments",
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar1029 Feature::Security => "security",
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1030 }
1031 }
1032
1033 pub fn parse(name: &str) -> Option<Feature> {
1034 match name {
1035 "plan" | "team" => Some(Feature::Plan),
1036 "deployments" => Some(Feature::Deployments),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar1037 "security" => Some(Feature::Security),
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1038 _ => None,
1039 }
1040 }
1041
1042 pub fn title(self) -> &'static str {
1043 match self {
1044 Feature::Plan => "g1t",
1045 Feature::Deployments => "Deployments",
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar1046 Feature::Security => "Security and quality",
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1047 }
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;
Merge GitHub pull request #8 (claude/cool-newton-7nm8r9): Docker deployments on g1t.page behind a switch that stays off until Cloudflare's container APIs are checked live, workflows a workspace manages in its repositories, tarball and zipball downloads, refs/pull/* kept to g1t alone, framework detection for g1t.page builds, and a workflow's event payload matching GitHub's.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;
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1082}
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>,
Spend adds up on one ledger. Charged this month has one definition, price less discount, included usage and credit, shared by the plan card, the spend limit, Spend and the top bar; the limit had counted usage not yet closed at full price before the discount, so a comped workspace read as charged a cent. Every agent line on the ledger names the agent and who asked, repository runs by g1t included, so Spent is the sum of its products, Agents is the agent product, and by agent adds up to it; the billing API returns by_agent and by_person. The usage and billing guide says how spend is counted.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>,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1133}
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>,
Spend adds up on one ledger. Charged this month has one definition, price less discount, included usage and credit, shared by the plan card, the spend limit, Spend and the top bar; the limit had counted usage not yet closed at full price before the discount, so a comped workspace read as charged a cent. Every agent line on the ledger names the agent and who asked, repository runs by g1t included, so Spent is the sum of its products, Agents is the agent product, and by agent adds up to it; the billing API returns by_agent and by_person. The usage and billing guide says how spend is counted.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).
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1198 #[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,
Usage, Billing settings and prepaid AI credit; fixes from the UX audit1230 /// 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>,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1241}
1242
Usage, Billing settings and prepaid AI credit; fixes from the UX audit1243fn yes() -> bool {
1244 true
1245}
1246
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1247/// `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,
Audit logs are kept by plan: a week on free, 90 days on the plan, and what staff set for an account in sudo1409 /// Days of audit log a free workspace keeps.
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1410 pub audit_retention_days: u32,
Audit logs are kept by plan: a week on free, 90 days on the plan, and what staff set for an account in sudo1411 /// 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,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1415 /// 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>,
Audit logs are kept by plan: a week on free, 90 days on the plan, and what staff set for an account in sudo1485 /// 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>,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1489 /// 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
Audit logs are kept by plan: a week on free, 90 days on the plan, and what staff set for an account in sudo1622/// `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
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1636#[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 // What the workspace's plan gives it, for its pages.
1677 /// What open reservations hold now.
1678 #[serde(default)]
1679 pub held_micros: i64,
1680 /// Paid in advance and not used yet.
1681 #[serde(default)]
1682 pub prepaid_micros: i64,
1683 /// The plan's included usage each month, and what of it is used.
1684 #[serde(default)]
1685 pub included_micros: i64,
1686 #[serde(default)]
1687 pub included_used_micros: i64,
Audit logs are kept by plan: a week on free, 90 days on the plan, and what staff set for an account in sudo1688 /// How far back the audit log can be read and exported, and what is
1689 /// kept: the plan's days, or what g1t staff set for the account.
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1690 pub audit_retention_days: u32,
Audit logs are kept by plan: a week on free, 90 days on the plan, and what staff set for an account in sudo1691 /// Whether `audit_retention_days` is what staff set for the account
1692 /// rather than the plan's.
1693 #[serde(default)]
1694 pub audit_retention_custom: bool,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1695 /// Private repository storage that is free for every workspace: past
1696 /// it, the plan pays for it and a free workspace's pushes stop.
1697 pub free_private_storage_bytes: i64,
1698 /// The last daily measure of the workspace's private repositories.
1699 pub private_storage_bytes: i64,
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member1700 /// On a paid plan (not Free): storage past the free amounts below is
1701 /// charged, so nothing is refused for it.
1702 #[serde(default)]
1703 pub has_plan: bool,
1704 /// Package storage free for every workspace, public and private: past
1705 /// it, the plan pays for it and a free workspace's pushes are refused.
1706 #[serde(default)]
1707 pub package_public_free_bytes: i64,
1708 #[serde(default)]
1709 pub package_private_free_bytes: i64,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1710 /// What g1t's open-source pool paid for the workspace this month.
1711 pub oss_paid_micros: i64,
1712 /// Deploy build time this month, every second of it metered.
1713 #[serde(default)]
1714 pub build_seconds_used: u32,
1715 /// Git operations this month, and how many are free for every
1716 /// workspace (past it: metered on the plan, slowed when free).
1717 #[serde(default)]
1718 pub git_operations: u64,
1719 #[serde(default)]
1720 pub git_operations_included: u64,
1721 /// The smallest amount a card is charged when a month closes.
1722 pub min_charge_micros: i64,
1723 /// A spend spike waiting for an owner, or decided.
1724 #[serde(default)]
1725 pub spike: Option<Spike>,
1726 /// Where usage stands against what is included and the limits, from 50%.
1727 #[serde(default)]
1728 pub alerts: Vec<UsageAlert>,
1729}
1730
1731/// One level reached: 50, 75, 90 or 100 percent of something.
1732#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1733#[serde(rename_all = "camelCase")]
1734pub struct UsageAlert {
1735 /// `included` (the plan's included usage), `spend_limit` (the owners'
1736 /// own limit) or `ceiling` (g1t's, on usage not yet paid for).
1737 pub meter: String,
1738 pub level: u32,
1739 pub used_micros: i64,
1740 pub limit_micros: i64,
1741 pub message: String,
1742}
1743
1744/// An hour's spend well above the workspace's usual pace: new compute
1745/// waits until an owner says to keep going.
1746#[derive(Clone, Debug, Serialize, Deserialize)]
1747#[serde(rename_all = "camelCase")]
1748pub struct Spike {
1749 pub id: String,
1750 /// `open` (waiting for an owner), `continued` (an owner said keep
1751 /// going) or `stopped` (an owner said stop).
1752 pub status: String,
1753 /// The hour's spend when it was found, and the usual hour's.
1754 pub hour_micros: i64,
1755 pub average_micros: i64,
1756 pub detected_at: String,
1757 #[serde(default)]
1758 pub decided_by: Option<String>,
1759 #[serde(default)]
1760 pub decided_at: Option<String>,
1761 /// While continued: until when, unless spend doubles again first.
1762 #[serde(default)]
1763 pub until: Option<String>,
1764}
1765
1766/// `reserve`: holds an estimate of a start's cost before the work starts.
1767/// Returns `Outcome<Reservation>`, or a failure whose code says why not:
1768///
1769/// - `paused`: a spend spike waiting for an owner, or a hold.
1770/// - `limit`: the spend limit or g1t's ceiling would be passed.
1771/// - `not_paid`: no plan, and nothing else pays for this kind of work (or
1772/// no card check yet).
1773/// - `trial_used`: the one-time trial is spent.
1774/// - `oss_pool_empty`: the open-source pool, or the repository's share of
1775/// it, is spent this month.
1776///
1777/// The message says exactly what to do, with the page to do it on (such as
1778/// `/acme/-/billing`).
1779#[derive(Debug, Serialize, Deserialize)]
1780#[serde(rename_all = "camelCase")]
1781pub struct ReserveArgs {
1782 pub workspace: String,
1783 pub repo: RepoPath,
1784 /// Whether the repository is public: the open-source pool pays only for
1785 /// public repositories' checks, workflows and merge queue.
1786 pub public: bool,
1787 pub kind: ComputeKind,
1788 /// The most the work is expected to cost g1t, before the margin, in
1789 /// millionths of a dollar (billing adds the margin, as it does to every
1790 /// charge). For an agent, its model's average plus its sandbox for its
1791 /// whole time cap.
1792 #[serde(alias = "estimate_micros")]
1793 pub estimate_micros: i64,
1794 /// An agent run on g1t's hosted models (not the workspace's own
1795 /// provider). Unsaid, an agent run is taken to be one. g1t's daily
1796 /// spend breaker pauses these when g1t is paying for them.
1797 #[serde(default, alias = "hosted_model")]
1798 pub hosted_model: Option<bool>,
1799}
1800
1801#[derive(Clone, Debug, Serialize, Deserialize)]
1802#[serde(rename_all = "camelCase")]
1803pub struct Reservation {
1804 pub id: String,
1805 pub paid_by: PaidBy,
1806 /// What is held, at cost; less than the estimate when a free
1807 /// workspace's last bit of trial credit is all there is.
1808 #[serde(default)]
1809 pub held_micros: i64,
1810 /// RFC 3339: when the hold lapses if never settled.
1811 #[serde(default)]
1812 pub expires_at: String,
1813}
1814
1815/// `settle`: releases a reservation's hold with what the work cost. The
1816/// charge goes on the ledger the usual way. Safe to repeat. Returns
1817/// `Outcome<bool>`: false if it was settled or had lapsed before.
1818#[derive(Debug, Serialize, Deserialize)]
1819#[serde(rename_all = "camelCase")]
1820pub struct SettleArgs {
1821 #[serde(alias = "reservation_id")]
1822 pub reservation_id: String,
1823 /// What the work cost g1t, before the margin.
1824 #[serde(alias = "actual_micros")]
1825 pub actual_micros: i64,
1826}
1827
1828// --- Card checks, the plan, prepayment -------------------------------------
1829
1830/// `card_check`: starts Stripe's page to save and verify a card: a setup
1831/// with 3-D Secure where the card supports it, which the card's bank sees
1832/// as a $0 or $1 authorization that is never charged. The trial and the
1833/// open-source pool need it, and it is the card the plan uses. Owners only.
1834/// Returns `Outcome<Checkout>`; the page's id comes back to `return_url` as
1835/// `session`, for `confirm_card_check`.
1836#[derive(Debug, Serialize, Deserialize)]
1837#[serde(rename_all = "camelCase")]
1838pub struct CardCheckArgs {
1839 pub actor: User,
1840 pub workspace: String,
1841 #[serde(alias = "return_url")]
1842 pub return_url: String,
1843}
1844
1845/// `confirm_card_check`: records the check once Stripe says the card was
1846/// verified, and grants the trial if the month's pool has room and the card
1847/// has not had one before. Safe to repeat. Returns `Outcome<Entitlements>`.
1848#[derive(Debug, Serialize, Deserialize)]
1849pub struct ConfirmCardCheckArgs {
1850 pub workspace: String,
1851 pub viewer: Viewer,
1852 pub session: String,
1853}
1854
1855// --- Limits: raising them, and spikes ---------------------------------------
1856
1857/// A request to g1t: a higher limit, or help with usage that went past
1858/// what was meant.
1859#[derive(Clone, Debug, Serialize, Deserialize)]
1860#[serde(rename_all = "camelCase")]
1861pub struct LimitRequest {
1862 pub id: String,
1863 pub workspace: String,
1864 /// `limit` (raise my limit) or `overage` (spent more than meant to).
1865 pub kind: String,
1866 /// The limit asked for; for an overage, what they think went wrong.
1867 pub amount_micros: i64,
1868 pub reason: String,
1869 pub expected_monthly_micros: i64,
1870 /// `open`, `approved` or `declined`.
1871 pub status: String,
1872 /// What was approved, which may differ from what was asked.
1873 #[serde(default)]
1874 pub decided_micros: Option<i64>,
1875 #[serde(default)]
1876 pub decided_by: Option<String>,
1877 /// The answer, as the owner sees it.
1878 #[serde(default)]
1879 pub answer: Option<String>,
1880 pub created_by: String,
1881 pub created_at: String,
1882 #[serde(default)]
1883 pub decided_at: Option<String>,
1884}
1885
1886/// `request_limit`: an owner asks g1t for more, or for help with usage past
1887/// what they meant. Answered within one business day, in the app and by
1888/// email. Owners only. Returns `Outcome<LimitRequest>`.
1889#[derive(Debug, Serialize, Deserialize)]
1890#[serde(rename_all = "camelCase")]
1891pub struct RequestLimitArgs {
1892 pub actor: User,
1893 pub workspace: String,
1894 /// `limit` or `overage`.
1895 pub kind: String,
1896 #[serde(alias = "amount_micros")]
1897 pub amount_micros: i64,
1898 pub reason: String,
1899 #[serde(default, alias = "expected_monthly_micros")]
1900 pub expected_monthly_micros: i64,
1901}
1902
1903/// `limit_requests`: a workspace's requests, newest first. Members only.
1904/// Returns `Outcome<Vec<LimitRequest>>`.
1905#[derive(Debug, Serialize, Deserialize)]
1906pub struct LimitRequestsArgs {
1907 pub workspace: String,
1908 pub viewer: Viewer,
1909}
1910
1911/// `confirm_spike`: an owner's answer to a spend spike. Keep going lifts the
1912/// pause for 24 hours, or until the hour's spend doubles again; stop keeps
1913/// new compute paused until an owner says to keep going. Owners only.
1914/// Returns `Outcome<Entitlements>`.
1915#[derive(Debug, Serialize, Deserialize)]
1916#[serde(rename_all = "camelCase")]
1917pub struct ConfirmSpikeArgs {
1918 pub actor: User,
1919 pub workspace: String,
1920 #[serde(alias = "keep_going")]
1921 pub keep_going: bool,
1922}
1923
1924/// `set_caps`: the owners' own caps on agents: one run's spend ($0.10 to
1925/// $100) and what the agents on one issue may spend in all ($1 to $1,000).
1926/// None goes back to the default ($2 and $10). A cap g1t staff set for the
1927/// account wins over both. Owners only. Returns `Outcome<Entitlements>`.
1928#[derive(Debug, Serialize, Deserialize)]
1929#[serde(rename_all = "camelCase")]
1930pub struct SetCapsArgs {
1931 pub actor: User,
1932 pub workspace: String,
1933 #[serde(default, alias = "run_cap_micros")]
1934 pub run_cap_micros: Option<i64>,
1935 #[serde(default, alias = "issue_cap_micros")]
1936 pub issue_cap_micros: Option<i64>,
1937}
1938
1939/// What staff see beside a request: the workspace's history with g1t.
1940#[derive(Clone, Debug, Default, Serialize, Deserialize)]
1941#[serde(rename_all = "camelCase")]
1942pub struct WorkspaceHistory {
1943 pub plan: Option<PlanKind>,
1944 /// The last six months, oldest first.
1945 pub months: Vec<MonthFigures>,
1946 /// Live payments that have cleared, and how many.
1947 pub paid_cleared_micros: i64,
1948 pub payments: u32,
1949 pub disputes: u32,
1950 pub declines: u32,
1951 /// The first time the workspace appears in billing, RFC 3339.
1952 pub first_seen: Option<String>,
1953 pub ceiling_micros: Option<i64>,
1954 pub max_ceiling_micros: Option<i64>,
1955 pub spend_limit_micros: Option<i64>,
1956 /// Recent velocity: the last hour, the usual hour over the last week,
1957 /// and the last 24 hours, at price.
1958 pub last_hour_micros: i64,
1959 pub average_hour_micros: i64,
1960 pub last_day_micros: i64,
1961}
1962
1963#[derive(Clone, Debug, Serialize, Deserialize)]
1964#[serde(rename_all = "camelCase")]
1965pub struct LimitRequestReview {
1966 pub request: LimitRequest,
1967 pub history: WorkspaceHistory,
1968}
1969
1970/// `admin_limit_requests`: requests for staff, oldest open first. Returns
1971/// `Vec<LimitRequestReview>`.
1972#[derive(Debug, Default, Serialize, Deserialize)]
1973pub struct AdminLimitRequestsArgs {
1974 /// `open` (the default), `approved`, `declined` or `all`.
1975 #[serde(default)]
1976 pub status: Option<String>,
1977}
1978
1979/// `admin_decide_limit_request`: approve (at the amount asked, or
1980/// `amount_micros`) or decline. The owner is told in the app and by email.
1981/// Recorded with who and why. Returns `Outcome<LimitRequest>`.
1982#[derive(Debug, Serialize, Deserialize)]
1983pub struct AdminDecideLimitRequestArgs {
1984 pub id: String,
1985 /// `approve` or `decline`.
1986 pub decision: String,
1987 #[serde(default)]
1988 pub amount_micros: Option<i64>,
1989 /// What the owner is told, beside the decision.
1990 #[serde(default)]
1991 pub note: String,
1992 pub by: String,
1993}
1994
1995/// `admin_record_payment`: money that reached g1t outside the card pages,
1996/// such as a bank transfer, entered as a payment (it raises the limit like
1997/// one). Recorded with who and the transfer's reference. Returns
1998/// `Outcome<LedgerEntry>`.
1999#[derive(Debug, Serialize, Deserialize)]
2000pub struct AdminRecordPaymentArgs {
2001 pub workspace: String,
2002 pub amount_micros: i64,
2003 /// The bank's reference for the transfer, or Stripe's payment id.
2004 pub reference: String,
2005 pub note: String,
2006 pub by: String,
2007}
2008
2009// --- Overages and goodwill (sudo) --------------------------------------------
2010
2011/// What a one-time goodwill credit would come to: g1t's margin on the
2012/// overage, always, plus as much of its underlying cost as the cap allows.
2013#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
2014#[serde(rename_all = "camelCase")]
2015pub struct Goodwill {
2016 /// This month's charges above the workspace's typical month.
2017 pub overage_micros: i64,
2018 /// The part of the overage that is g1t's margin.
2019 pub margin_micros: i64,
2020 /// The part that is what g1t paid its providers.
2021 pub cost_micros: i64,
2022 /// The one-click credit: the margin plus the cost up to the cap.
2023 pub credit_micros: i64,
2024 /// Of the credit, the real cost g1t absorbs.
2025 pub absorbed_micros: i64,
2026}
2027
2028/// A workspace whose month went well past its usual, or hit a spike.
2029#[derive(Clone, Debug, Serialize, Deserialize)]
2030#[serde(rename_all = "camelCase")]
2031pub struct Overage {
2032 pub workspace: String,
2033 pub plan: PlanKind,
2034 /// The median of its last three months' charges.
2035 pub typical_month_micros: i64,
2036 pub this_month_micros: i64,
2037 /// What this month cost g1t, and what g1t keeps of it.
2038 pub cost_micros: i64,
2039 pub margin_micros: i64,
2040 /// A spike this month, if there was one.
2041 pub spike: Option<Spike>,
2042 /// The runs that cost the most this month.
2043 pub top_entries: Vec<LedgerEntry>,
2044 pub goodwill: Goodwill,
2045 /// False when a goodwill credit was given in the last 12 months.
2046 pub goodwill_available: bool,
2047 pub last_goodwill_at: Option<String>,
2048 /// An open overage request from the owner, if there is one.
2049 pub request: Option<LimitRequest>,
2050}
2051
2052/// `admin_overages`: the Overages queue. Returns `Vec<Overage>`.
2053#[derive(Debug, Default, Serialize, Deserialize)]
2054pub struct AdminOveragesArgs {}
2055
2056/// `admin_goodwill`: credits a workspace for accidental usage. With no
2057/// amount, the one-click credit (`Goodwill::credit_micros`), once per
2058/// workspace in 12 months. A larger amount, or a second within 12 months,
2059/// needs a typed reason. It shows on the statement as "Credit from g1t:
2060/// accidental usage on <date>". Returns `Outcome<LedgerEntry>`.
2061#[derive(Debug, Serialize, Deserialize)]
2062pub struct AdminGoodwillArgs {
2063 pub workspace: String,
2064 #[serde(default)]
2065 pub amount_micros: Option<i64>,
2066 /// Why, typed by staff; needed past the one-click credit.
2067 #[serde(default)]
2068 pub reason: String,
2069 /// The day the accidental usage happened, `YYYY-MM-DD`; today if absent.
2070 #[serde(default)]
2071 pub day: Option<String>,
2072 pub by: String,
2073}
2074
2075/// One workspace's recent pace, for sudo's velocity view.
2076#[derive(Clone, Debug, Serialize, Deserialize)]
2077#[serde(rename_all = "camelCase")]
2078pub struct Velocity {
2079 pub workspace: String,
2080 pub plan: PlanKind,
2081 pub last_hour_micros: i64,
2082 pub average_hour_micros: i64,
2083 pub last_day_micros: i64,
2084 pub this_month_micros: i64,
2085 /// The last hour over the usual hour; 0 with no history.
2086 pub ratio: f64,
2087 pub spike: Option<Spike>,
2088 pub first_seen: Option<String>,
2089}
2090
2091/// `admin_velocity`: workspaces spending in the last day, fastest first.
2092/// Returns `Vec<Velocity>`.
2093#[derive(Debug, Default, Serialize, Deserialize)]
2094pub struct AdminVelocityArgs {}
2095
2096#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
2097#[serde(rename_all = "snake_case")]
2098pub enum AccountKind {
2099 Workspace,
2100 Enterprise,
2101}
2102
2103/// How an account is charged. Standard unless g1t set otherwise in sudo.
2104#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
2105#[serde(rename_all = "camelCase")]
2106pub struct Terms {
2107 pub kind: TermsKind,
2108 /// Off every usage charge, in percent. Custom terms only.
2109 #[serde(default)]
2110 pub discount_percent: u32,
2111 /// A ceiling on unpaid usage that replaces the one trust would give.
2112 #[serde(default)]
2113 pub ceiling_micros: Option<i64>,
2114 /// Why, for whoever looks next.
2115 #[serde(default)]
2116 pub note: String,
2117 /// When the terms end and the account goes back to standard.
2118 #[serde(default)]
2119 pub until: Option<String>,
2120 #[serde(default)]
2121 pub set_by: Option<String>,
2122 #[serde(default)]
2123 pub set_at: Option<String>,
2124}
2125
2126impl Terms {
2127 pub fn standard() -> Self {
2128 Terms {
2129 kind: TermsKind::Standard,
2130 discount_percent: 0,
2131 ceiling_micros: None,
2132 note: String::new(),
2133 until: None,
2134 set_by: None,
2135 set_at: None,
2136 }
2137 }
2138
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging2139 /// The discount in percent, 0 to 100. Terms from before discounts
2140 /// replaced "comped" read as 100%.
2141 pub fn percent_off(&self) -> u32 {
2142 match self.kind {
2143 TermsKind::Comped => 100,
2144 TermsKind::Custom => self.discount_percent.min(100),
2145 TermsKind::Standard => 0,
2146 }
2147 }
2148
2149 /// A 100% discount: nothing is charged, usage is recorded at its price
2150 /// and discounted in full. g1t's own workspaces and partners. Paid
2151 /// features are on without a plan, and g1t's own spend on it is held to
2152 /// a monthly budget (the terms' ceiling, at cost).
2153 pub fn full_discount(&self) -> bool {
2154 self.percent_off() >= 100
2155 }
2156
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2157 /// What a charge becomes under these terms.
2158 pub fn apply(&self, charge_micros: i64) -> i64 {
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging2159 charge_micros * i64::from(100 - self.percent_off()) / 100
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2160 }
Merge branch 'worktree-agent-a633ac0f7f66d419d'2161
2162 /// What a charge at cost plus the margin becomes under these terms, and
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging2163 /// what the discount took off it (`ledger.discount_micros`), so the
2164 /// statement shows the usage at its price and the discount beside it,
2165 /// and a discount below cost plus the margin is counted as given, never
2166 /// lost. A 100% discount takes it all.
Merge branch 'worktree-agent-a633ac0f7f66d419d'2167 pub fn discounted(&self, charge_micros: i64) -> (i64, i64) {
2168 let charged = self.apply(charge_micros);
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging2169 (charged, (charge_micros - charged).max(0))
2170 }
2171
2172 /// How the statement and sudo name the terms: `100% discount`, `30% off`.
2173 pub fn discount_label(&self) -> Option<String> {
2174 match self.percent_off() {
2175 0 => None,
2176 100 => Some("100% discount".to_owned()),
2177 percent => Some(format!("{percent}% off")),
Merge branch 'worktree-agent-a633ac0f7f66d419d'2178 }
2179 }
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2180}
2181
2182#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
2183#[serde(rename_all = "snake_case")]
2184pub enum TermsKind {
2185 /// Prices as published, limits by trust.
2186 Standard,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging2187 /// Before discounts: what a 100% discount is now. Read as one
2188 /// (`Terms::percent_off`); billing never writes it (migration 0039).
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2189 Comped,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging2190 /// A discount (up to 100%), a ceiling, or both.
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2191 Custom,
2192}
2193
2194/// `stripe_webhook`: an event from Stripe, as the API received it: the raw
2195/// body and its `Stripe-Signature` header. Billing checks the signature
2196/// against the secret of the endpoint it registered, and handles each
2197/// event once. Returns `Outcome<bool>`: false for one already handled.
2198#[derive(Debug, Serialize, Deserialize)]
2199pub struct StripeWebhookArgs {
2200 pub payload: String,
2201 pub signature: String,
2202}
2203
2204/// `admin_stripe`: where billing stands with Stripe. Staff only. Returns
Stripe's webhook secret is a Worker secret, STRIPE_WEBHOOK_SECRET, from a destination made in Stripe's dashboard2205/// `StripeStatus`. With `fix: true`, first enables the destination at
2206/// billing's address and gives it the events billing needs.
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2207#[derive(Debug, Default, Serialize, Deserialize)]
2208pub struct AdminStripeArgs {
2209 #[serde(default)]
Stripe's webhook secret is a Worker secret, STRIPE_WEBHOOK_SECRET, from a destination made in Stripe's dashboard2210 pub fix: bool,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2211 #[serde(default)]
2212 pub by: Option<String>,
2213}
2214
2215#[derive(Clone, Debug, Serialize, Deserialize)]
2216#[serde(rename_all = "camelCase")]
2217pub struct StripeStatus {
2218 /// `test` or `live`, from the key; `off` without one.
2219 pub mode: String,
Stripe's webhook secret is a Worker secret, STRIPE_WEBHOOK_SECRET, from a destination made in Stripe's dashboard2220 /// Whether `STRIPE_WEBHOOK_SECRET` is set, so events can be checked.
2221 pub secret_set: bool,
2222 /// The destination at billing's address in Stripe, as Stripe has it.
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2223 pub webhook: Option<StripeWebhook>,
Stripe's webhook secret is a Worker secret, STRIPE_WEBHOOK_SECRET, from a destination made in Stripe's dashboard2224 /// Events billing handles that the destination does not send.
2225 pub missing_events: Vec<String>,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2226 /// The latest events handled, newest first.
2227 pub recent_events: Vec<StripeEventSummary>,
Stripe's webhook secret is a Worker secret, STRIPE_WEBHOOK_SECRET, from a destination made in Stripe's dashboard2228 /// What went wrong reading or fixing the destination, if it did.
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2229 pub error: Option<String>,
2230}
2231
2232#[derive(Clone, Debug, Serialize, Deserialize)]
2233#[serde(rename_all = "camelCase")]
2234pub struct StripeWebhook {
2235 pub url: String,
2236 pub endpoint_id: String,
Stripe's webhook secret is a Worker secret, STRIPE_WEBHOOK_SECRET, from a destination made in Stripe's dashboard2237 /// `enabled` or `disabled`.
2238 pub status: String,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2239 pub events: Vec<String>,
2240 pub created_at: String,
2241}
2242
2243#[derive(Clone, Debug, Serialize, Deserialize)]
2244#[serde(rename_all = "camelCase")]
2245pub struct StripeEventSummary {
2246 pub id: String,
2247 pub kind: String,
2248 pub outcome: String,
2249 pub received_at: String,
2250}
2251
2252/// `admin_enterprise_billing`: where an enterprise's invoices go. Creates
2253/// or updates its Stripe customer. Returns `Outcome<BillingAccount>`.
2254#[derive(Debug, Serialize, Deserialize)]
2255pub struct AdminEnterpriseBillingArgs {
2256 pub id: String,
2257 pub email: String,
2258 pub by: String,
2259}
2260
Merge Stripe Tax, the card fee on card payments, and one free workspace per person2261/// `admin_enterprise_address`: the enterprise's billing address and tax ID,
2262/// saved on its Stripe customer (made by `admin_enterprise_billing`).
2263/// Stripe Tax works its invoices' tax out from the address; an invoice is
2264/// not sent without one. Returns `Outcome<bool>`.
2265#[derive(Debug, Serialize, Deserialize)]
2266#[serde(rename_all = "camelCase")]
2267pub struct AdminEnterpriseAddressArgs {
2268 pub id: String,
2269 pub address: PostalAddress,
2270 #[serde(default, alias = "tax_id_type")]
2271 pub tax_id_type: Option<String>,
2272 #[serde(default, alias = "tax_id")]
2273 pub tax_id: Option<String>,
2274 pub by: String,
2275}
2276
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2277/// `admin_invoice_enterprise`: sends an enterprise its invoice now, for
2278/// what its workspaces owe, rather than waiting for the month to close.
2279/// Returns `Outcome<EnterpriseInvoice>`.
2280#[derive(Debug, Serialize, Deserialize)]
2281pub struct AdminInvoiceEnterpriseArgs {
2282 pub id: String,
2283 pub by: String,
2284}
2285
2286/// An enterprise's invoice: one line per workspace, paid on Stripe.
2287#[derive(Clone, Debug, Serialize, Deserialize)]
2288#[serde(rename_all = "camelCase")]
2289pub struct EnterpriseInvoice {
2290 pub invoice_id: String,
2291 /// Stripe's page for it, where it is paid.
2292 pub hosted_url: Option<String>,
2293 pub amount_micros: i64,
2294 /// `open`, `paid`, `overdue` or `void`.
2295 pub status: String,
2296 pub period: String,
2297 pub lines: Vec<InvoiceLine>,
2298 pub created_at: String,
2299}
2300
2301#[derive(Clone, Debug, Serialize, Deserialize)]
2302#[serde(rename_all = "camelCase")]
2303pub struct InvoiceLine {
2304 pub workspace: String,
2305 pub amount_micros: i64,
2306}
2307
2308/// A workspace's invoice from g1t: one per month, and one each time it is
2309/// charged near its limit. Itemised, charged to the card on file, and kept
2310/// in Stripe's billing page with its PDF.
2311#[derive(Clone, Debug, Serialize, Deserialize)]
2312#[serde(rename_all = "camelCase")]
2313pub struct WorkspaceInvoice {
2314 pub invoice_id: String,
2315 pub workspace: String,
2316 /// `month` (2026-10) or `threshold`.
2317 pub reason: String,
2318 pub period: String,
2319 pub amount_micros: i64,
2320 /// `paid`, `open`, `failed` or `void`.
2321 pub status: String,
2322 pub hosted_url: Option<String>,
2323 pub pdf_url: Option<String>,
2324 pub lines: Vec<InvoiceItem>,
2325 pub created_at: String,
Merge Stripe Tax, the card fee on card payments, and one free workspace per person2326 /// The card processing fee on top of `amount_micros`, when the invoice
2327 /// is charged to a card; never part of the usage it pays for.
2328 #[serde(default)]
2329 pub fee_micros: i64,
2330 /// The tax Stripe added on top, once it is known (after paying).
2331 #[serde(default)]
2332 pub tax_micros: i64,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2333}
2334
2335#[derive(Clone, Debug, Serialize, Deserialize)]
2336#[serde(rename_all = "camelCase")]
2337pub struct InvoiceItem {
2338 pub description: String,
2339 pub amount_micros: i64,
2340}
2341
2342/// `invoices`: a workspace's invoices from g1t, newest first. Members
2343/// only. Returns `Outcome<Vec<WorkspaceInvoice>>`.
2344#[derive(Debug, Serialize, Deserialize)]
2345pub struct InvoicesArgs {
2346 pub workspace: String,
2347 pub viewer: Viewer,
2348}
2349
2350/// `admin_workspace_invoices`: the same, for staff. Returns
2351/// `Vec<WorkspaceInvoice>`.
2352#[derive(Debug, Serialize, Deserialize)]
2353pub struct AdminWorkspaceInvoicesArgs {
2354 pub workspace: String,
2355}
2356
2357/// `statement`: a month of a workspace's ledger, grouped by day (or by
2358/// project) with a line per kind of charge. Members only. Returns
2359/// `Outcome<Statement>`.
2360#[derive(Debug, Serialize, Deserialize)]
2361pub struct StatementArgs {
2362 pub workspace: String,
2363 pub viewer: Viewer,
2364 /// YYYY-MM; this month when absent.
2365 #[serde(default)]
2366 pub month: Option<String>,
2367 /// `day` (the default) or `project`.
2368 #[serde(default)]
2369 pub group: Option<String>,
2370}
2371
2372#[derive(Clone, Debug, Serialize, Deserialize)]
2373#[serde(rename_all = "camelCase")]
2374pub struct Statement {
2375 pub month: String,
2376 /// Months with any entries, newest first.
2377 pub months: Vec<String>,
2378 pub groups: Vec<StatementGroup>,
2379 pub totals: StatementTotals,
2380}
2381
2382#[derive(Clone, Debug, Serialize, Deserialize)]
2383#[serde(rename_all = "camelCase")]
2384pub struct StatementGroup {
2385 /// The day (YYYY-MM-DD) or the project (`owner/name`, or empty).
2386 pub key: String,
2387 pub label: String,
2388 pub lines: Vec<StatementLine>,
2389 /// What the group's charges come to.
2390 pub charged_micros: i64,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging2391 /// Its usage at price, and what the discount took off it.
2392 #[serde(default)]
2393 pub price_micros: i64,
2394 #[serde(default)]
2395 pub discount_micros: i64,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2396}
2397
2398#[derive(Clone, Debug, Serialize, Deserialize)]
2399#[serde(rename_all = "camelCase")]
2400pub struct StatementLine {
2401 /// Agent runs, Sandbox time, Deployments, Payments, Credits from g1t,
2402 /// Refunds, and, for older entries, Runs on your own model provider.
2403 pub kind: String,
2404 pub count: u32,
2405 /// Charges positive; money in (payments, credits) negative.
2406 pub charged_micros: i64,
2407 pub cost_micros: i64,
2408 /// Of the usage on the line, what was paid for before it was charged:
2409 /// by the plan's included usage, the trial credit, g1t's open-source
2410 /// pool, or g1t itself. Not in `charged_micros`.
2411 #[serde(default)]
2412 pub covered_micros: i64,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging2413 /// Usage at its price: charged, plus what paid for it and what the
2414 /// discount took off. Zero for money in.
2415 #[serde(default)]
2416 pub price_micros: i64,
2417 /// What the account's discount took off the line's price.
2418 #[serde(default)]
2419 pub discount_micros: i64,
Merge Stripe Tax, the card fee on card payments, and one free workspace per person2420 /// On the `Tax` and `Card processing fees` lines: what was paid with
2421 /// payments on top of what reached the balance (negative for what a
2422 /// refund gave back). Never in `charged_micros` or the balance.
2423 #[serde(default)]
2424 pub passed_micros: i64,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2425}
2426
2427#[derive(Clone, Debug, Serialize, Deserialize)]
2428#[serde(rename_all = "camelCase")]
2429pub struct StatementTotals {
2430 pub charged_micros: i64,
2431 pub paid_micros: i64,
2432 pub cost_micros: i64,
2433 pub entries: u32,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging2434 /// Usage at price, and what the discount took off it: charged is the
2435 /// price less the discount and what paid for it.
2436 #[serde(default)]
2437 pub price_micros: i64,
2438 #[serde(default)]
2439 pub discount_micros: i64,
2440 /// The account's discount now, in percent; absent without one.
2441 #[serde(default)]
2442 pub discount_percent: Option<u32>,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2443 /// What paid for usage before it was charged, one line per source,
2444 /// such as "Paid by g1t's open-source pool".
2445 #[serde(default)]
2446 pub covered: Vec<Covered>,
2447 /// Owed when the month closed but under the minimum charge, so it
2448 /// carries over to the next invoice. Zero when nothing carried.
2449 #[serde(default)]
2450 pub carried_micros: i64,
Merge Stripe Tax, the card fee on card payments, and one free workspace per person2451 /// Tax and card processing fees paid with the month's payments, on top
2452 /// of `paid_micros`.
2453 #[serde(default)]
2454 pub tax_micros: i64,
2455 #[serde(default)]
2456 pub card_fee_micros: i64,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2457}
2458
2459/// One source that paid for usage before it was charged.
2460#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
2461#[serde(rename_all = "camelCase")]
2462pub struct Covered {
2463 /// `included`, `trial`, `oss_pool` or `given`.
2464 pub source: String,
2465 /// "Paid by your plan's included usage", "Paid by your trial credit",
2466 /// "Paid by g1t's open-source pool", "Covered by g1t".
2467 pub label: String,
2468 pub micros: i64,
2469}
2470
2471/// `statement_entries`: one statement line's entries, newest first, 50 at
2472/// a time (`before` = the last id seen). Returns `Outcome<Vec<LedgerEntry>>`.
2473#[derive(Debug, Serialize, Deserialize)]
2474pub struct StatementEntriesArgs {
2475 pub workspace: String,
2476 pub viewer: Viewer,
2477 pub month: String,
2478 pub kind: String,
2479 #[serde(default)]
2480 pub day: Option<String>,
2481 #[serde(default)]
2482 pub project: Option<String>,
2483 #[serde(default)]
2484 pub before: Option<String>,
2485}
2486
2487// --- Sales (sudo.g1t.sh) ------------------------------------------------------
2488//
2489// What staff need to know to reach out: who is growing, who is close to
2490// their limit, who was declined, who has become a steady customer. And what
2491// was done about it: a stage, an owner on g1t's side, a next step, notes.
2492
2493/// Why a workspace is worth a look.
2494#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
2495#[serde(rename_all = "snake_case")]
2496pub enum SignalKind {
2497 /// At its limit, or its own spend limit: work is stopped.
2498 AtLimit,
2499 /// Past 80% of what is available to it: about to need more.
2500 NearCeiling,
2501 /// Its card was declined or a payment disputed.
2502 Declined,
2503 /// This month is well ahead of last month.
2504 Growing,
2505 /// Became Established: the ceiling now follows its spend.
2506 Established,
2507 /// Paid g1t for the first time.
2508 FirstPayment,
2509 /// Spending enough that custom terms or an enterprise may suit it.
2510 HighSpend,
2511 /// Costs g1t more on Cloudflare than it pays, over 30 days: a pricing
2512 /// gap or abuse to look at (billing's `margin`).
2513 CostOverRevenue,
2514}
2515
2516#[derive(Clone, Debug, Serialize, Deserialize)]
2517#[serde(rename_all = "camelCase")]
2518pub struct Signal {
2519 pub workspace: String,
2520 pub kind: SignalKind,
2521 /// One sentence, with the figures.
2522 pub detail: String,
2523 /// The figure that matters, such as this month's spend.
2524 pub value_micros: i64,
2525 /// Its sales stage, if staff gave it one.
2526 pub stage: Option<String>,
2527 pub owner: Option<String>,
2528 #[serde(default)]
2529 pub next_step: Option<String>,
2530 /// When the next step is due, `YYYY-MM-DD`.
2531 #[serde(default)]
2532 pub next_at: Option<String>,
2533}
2534
2535/// `admin_invoices`: every invoice g1t has sent, workspaces' and
2536/// enterprises', newest first. Returns `Vec<InvoiceSummary>`.
2537#[derive(Debug, Default, Serialize, Deserialize)]
2538pub struct AdminInvoicesArgs {
2539 /// `paid`, `open`, `failed`, `overdue` or `void`.
2540 #[serde(default)]
2541 pub status: Option<String>,
2542 /// YYYY-MM, by when it was sent.
2543 #[serde(default)]
2544 pub month: Option<String>,
2545}
2546
2547#[derive(Clone, Debug, Serialize, Deserialize)]
2548#[serde(rename_all = "camelCase")]
2549pub struct InvoiceSummary {
2550 pub invoice_id: String,
2551 /// `workspace` or `enterprise`.
2552 pub kind: String,
2553 /// The workspace's slug, or the enterprise's account id.
2554 pub account: String,
2555 /// What to call it: the workspace, or the enterprise's name.
2556 pub name: String,
2557 pub reason: String,
2558 pub period: String,
2559 pub amount_micros: i64,
2560 pub status: String,
2561 pub hosted_url: Option<String>,
2562 pub created_at: String,
2563 pub paid_at: Option<String>,
2564}
2565
2566/// `admin_audit`: every change made in sudo, and by Stripe, newest first.
2567/// Returns `Vec<AdminAction>`.
2568#[derive(Debug, Default, Serialize, Deserialize)]
2569pub struct AdminAuditArgs {
2570 #[serde(default)]
2571 pub by: Option<String>,
2572 #[serde(default)]
2573 pub action: Option<String>,
2574 /// Only those before this time, for paging.
2575 #[serde(default)]
2576 pub before: Option<String>,
2577}
2578
2579/// `admin_signals`: every workspace worth reaching out to, most urgent
2580/// first. Returns `Vec<Signal>`.
2581#[derive(Debug, Default, Serialize, Deserialize)]
2582pub struct AdminSignalsArgs {}
2583
2584/// What staff are doing about a workspace.
2585#[derive(Clone, Debug, Serialize, Deserialize)]
2586#[serde(rename_all = "camelCase")]
2587pub struct SalesRecord {
2588 pub workspace: String,
2589 /// `none`, `lead`, `contacted`, `negotiating`, `won`, `lost` or `churn_risk`.
2590 pub stage: String,
2591 /// The staff member looking after it.
2592 pub owner: Option<String>,
2593 pub next_step: Option<String>,
2594 /// RFC 3339 date.
2595 pub next_at: Option<String>,
2596 pub notes: Vec<SalesNote>,
2597 pub updated_at: Option<String>,
2598}
2599
2600#[derive(Clone, Debug, Serialize, Deserialize)]
2601#[serde(rename_all = "camelCase")]
2602pub struct SalesNote {
2603 pub id: String,
2604 pub text: String,
2605 pub by: String,
2606 pub created_at: String,
2607}
2608
2609/// `admin_sales`: a workspace's sales record. Returns `SalesRecord`.
2610#[derive(Debug, Serialize, Deserialize)]
2611pub struct AdminSalesArgs {
2612 pub workspace: String,
2613}
2614
2615/// `admin_set_sales`: its stage, owner and next step. Returns `Outcome<SalesRecord>`.
2616#[derive(Debug, Serialize, Deserialize)]
2617pub struct AdminSetSalesArgs {
2618 pub workspace: String,
2619 pub stage: String,
2620 #[serde(default)]
2621 pub owner: Option<String>,
2622 #[serde(default)]
2623 pub next_step: Option<String>,
2624 #[serde(default)]
2625 pub next_at: Option<String>,
2626 pub by: String,
2627}
2628
2629/// `admin_add_note`. Returns `Outcome<SalesRecord>`.
2630#[derive(Debug, Serialize, Deserialize)]
2631pub struct AdminAddNoteArgs {
2632 pub workspace: String,
2633 pub text: String,
2634 pub by: String,
2635}
2636
2637/// `admin_overview`: the business at a glance. Returns `Overview`.
2638#[derive(Debug, Default, Serialize, Deserialize)]
2639pub struct AdminOverviewArgs {}
2640
2641#[derive(Clone, Debug, Serialize, Deserialize)]
2642#[serde(rename_all = "camelCase")]
2643pub struct Overview {
2644 /// YYYY-MM.
2645 pub month: String,
2646 /// The last six months, oldest first, all workspaces together.
2647 pub months: Vec<MonthFigures>,
2648 /// This month by kind of usage: models, sandbox, deployments, plans.
2649 pub by_kind: Vec<KindFigures>,
2650 pub paying_workspaces: u32,
2651 pub stopped: u32,
2652 pub near_ceiling: u32,
2653 pub declined: u32,
2654 /// Sent and not yet paid, workspaces and enterprises.
2655 pub open_invoices_micros: i64,
2656 /// Follow-ups due today or earlier.
2657 pub follow_ups_due: u32,
2658 /// The capped budgets g1t pays from, this month.
2659 #[serde(default)]
2660 pub pools: Option<Pools>,
2661 /// This month's revenue: usage charged plus the plan's price paid.
2662 #[serde(default)]
2663 pub revenue_micros: i64,
2664 /// Workspaces on the paid plan now, and what their price comes to a
2665 /// month.
2666 #[serde(default)]
2667 pub active_plans: u32,
2668 #[serde(default)]
2669 pub plan_mrr_micros: i64,
2670 /// What g1t gave this month, by source, apart from its margin.
2671 #[serde(default)]
2672 pub given: Vec<GivenFigures>,
2673 /// g1t's own and Flagon's workspaces this month: what their use cost,
2674 /// and why they are not charged.
2675 #[serde(default)]
2676 pub internal: Vec<InternalUse>,
2677 /// Open limit requests, and workspaces in the Overages queue.
2678 #[serde(default)]
2679 pub open_requests: u32,
2680 #[serde(default)]
2681 pub overages: u32,
2682 /// Spend spikes waiting for an owner.
2683 #[serde(default)]
2684 pub open_spikes: u32,
2685}
2686
2687/// What g1t gave this month from one source.
2688#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2689#[serde(rename_all = "camelCase")]
2690pub struct GivenFigures {
2691 /// `internal`, `trial`, `oss_pool`, `goodwill` or `covered`.
2692 pub source: String,
2693 pub label: String,
2694 /// At price, and what it cost g1t.
2695 pub micros: i64,
2696 pub cost_micros: i64,
2697}
2698
2699/// One internal workspace's use this month.
2700#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2701#[serde(rename_all = "camelCase")]
2702pub struct InternalUse {
2703 pub workspace: String,
2704 /// Why it is not charged: its terms' note.
2705 pub reason: String,
2706 pub cost_micros: i64,
2707 pub entries: u32,
2708}
2709
2710/// g1t's capped budgets for free usage, this calendar month (UTC).
2711#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2712#[serde(rename_all = "camelCase")]
2713pub struct Pools {
2714 /// YYYY-MM.
2715 pub month: String,
2716 /// Trial grants made this month, against the month's pool.
2717 pub trial_granted_micros: i64,
2718 pub trial_pool_micros: i64,
2719 pub trial_grants: u32,
2720 /// What the open-source pool paid this month, against its cap.
2721 pub oss_used_micros: i64,
2722 pub oss_pool_micros: i64,
2723 /// Each public repository's monthly cap on the pool.
2724 pub oss_repo_micros: i64,
2725}
2726
2727#[derive(Clone, Debug, Serialize, Deserialize)]
2728#[serde(rename_all = "camelCase")]
2729pub struct KindFigures {
2730 pub kind: String,
2731 pub charged_micros: i64,
2732 pub cost_micros: i64,
2733}
2734
2735// --- Staff (sudo.g1t.sh) ------------------------------------------------------
2736//
2737// Called only by the sudo app, which only g1t staff can reach (behind
2738// Cloudflare Access). Each change names who made it, and is kept in the
2739// audit log.
2740
2741/// `admin_accounts`: every billing account, with where each stands this
2742/// month. Returns `Vec<AccountSummary>`.
2743#[derive(Debug, Default, Serialize, Deserialize)]
2744pub struct AdminAccountsArgs {
2745 #[serde(default)]
2746 pub query: Option<String>,
2747 /// Exactly these workspaces' accounts, such as one page of sudo's
2748 /// list; every account with activity when absent.
2749 #[serde(default)]
2750 pub workspaces: Option<Vec<String>>,
2751}
2752
2753#[derive(Clone, Debug, Serialize, Deserialize)]
2754#[serde(rename_all = "camelCase")]
2755pub struct AccountSummary {
2756 pub account: BillingAccount,
2757 pub limit: Limit,
2758 /// Charged this month, after terms.
2759 pub charged_micros: i64,
2760 /// What this month's usage cost g1t.
2761 pub cost_micros: i64,
2762 /// Paid, ever.
2763 pub paid_micros: i64,
2764 /// The same figures for each of the account's workspaces that has
2765 /// any, so staff can see what one member of an enterprise used.
2766 #[serde(default)]
2767 pub by_workspace: Vec<WorkspaceFigures>,
2768 /// The last six months, oldest first, for trends.
2769 #[serde(default)]
2770 pub months: Vec<MonthFigures>,
2771}
2772
2773/// One month of an account's billing.
2774#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2775#[serde(rename_all = "camelCase")]
2776pub struct MonthFigures {
2777 /// YYYY-MM.
2778 pub month: String,
2779 /// Usage charged, after what paid for it first.
2780 pub charged_micros: i64,
2781 /// What usage cost g1t: only what g1t paid for, never a workspace's own
2782 /// model provider.
2783 pub cost_micros: i64,
2784 pub paid_micros: i64,
2785 /// The plan's monthly price, paid.
2786 #[serde(default)]
2787 pub plans_micros: i64,
2788 /// What g1t gave, at price: internal (comped) use, trials, the
2789 /// open-source pool, goodwill credits and what g1t covered. Not margin.
2790 #[serde(default)]
2791 pub given_micros: i64,
2792}
2793
2794/// One workspace's share of an [`AccountSummary`].
2795#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2796#[serde(rename_all = "camelCase")]
2797pub struct WorkspaceFigures {
2798 pub workspace: String,
2799 pub charged_micros: i64,
2800 pub cost_micros: i64,
2801 pub paid_micros: i64,
2802}
2803
2804/// `admin_account`: one account in full. Returns `Outcome<AccountDetail>`.
2805#[derive(Debug, Serialize, Deserialize)]
2806pub struct AdminAccountArgs {
2807 /// An account id, or a workspace slug.
2808 pub id: String,
2809}
2810
2811#[derive(Clone, Debug, Serialize, Deserialize)]
2812#[serde(rename_all = "camelCase")]
2813pub struct AccountDetail {
2814 pub summary: AccountSummary,
2815 /// Each workspace's limit, for an enterprise.
2816 pub workspaces: Vec<Limit>,
2817 pub ledger: Vec<LedgerEntry>,
2818 pub audit: Vec<AdminAction>,
2819}
2820
2821/// `admin_set_terms`. Returns `Outcome<BillingAccount>`.
2822#[derive(Debug, Serialize, Deserialize)]
2823pub struct AdminSetTermsArgs {
2824 pub id: String,
2825 pub terms: Terms,
2826 pub by: String,
2827}
2828
2829/// `admin_create_enterprise`. Returns `Outcome<BillingAccount>`.
2830#[derive(Debug, Serialize, Deserialize)]
2831pub struct AdminCreateEnterpriseArgs {
2832 pub name: String,
2833 pub workspaces: Vec<String>,
2834 pub by: String,
2835}
2836
2837/// `admin_attach`: moves a workspace onto an enterprise account, or back
2838/// onto its own with `account: None`. Returns `Outcome<BillingAccount>`.
2839#[derive(Debug, Serialize, Deserialize)]
2840pub struct AdminAttachArgs {
2841 pub workspace: String,
2842 pub account: Option<String>,
2843 pub by: String,
2844}
2845
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging2846/// Why g1t gave a workspace credit.
2847#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
2848#[serde(rename_all = "snake_case")]
2849pub enum CreditKind {
2850 /// Marketing: a welcome, a referral, an event. Given away when spent.
2851 Promotional,
2852 /// An apology, or accidental usage forgiven. Given away when spent.
2853 #[default]
2854 Goodwill,
2855 /// Money back for something that went wrong. Not given away: it gives
2856 /// back money already paid, so it comes off what was paid on the day
2857 /// it refunds, and what it pays for later is paid for.
2858 Refund,
2859 /// Bought by the workspace (prepaid AI): money paid in up front, owed
2860 /// as usage until spent. What it pays for is paid for, never given.
2861 /// Staff never give it; its ledger line is a payment, not `crd…`.
2862 Purchased,
2863}
2864
2865impl CreditKind {
2866 pub fn as_str(self) -> &'static str {
2867 match self {
2868 CreditKind::Promotional => "promotional",
2869 CreditKind::Goodwill => "goodwill",
2870 CreditKind::Refund => "refund",
2871 CreditKind::Purchased => "purchased",
2872 }
2873 }
2874
2875 pub fn parse(text: &str) -> Option<CreditKind> {
2876 match text {
2877 "promotional" => Some(CreditKind::Promotional),
2878 "goodwill" => Some(CreditKind::Goodwill),
2879 "refund" => Some(CreditKind::Refund),
2880 "purchased" => Some(CreditKind::Purchased),
2881 _ => None,
2882 }
2883 }
2884
2885 /// As people read it: `Promotional`.
2886 pub fn label(self) -> &'static str {
2887 match self {
2888 CreditKind::Promotional => "Promotional",
2889 CreditKind::Goodwill => "Goodwill",
2890 CreditKind::Refund => "Refund",
2891 CreditKind::Purchased => "Purchased",
2892 }
2893 }
2894}
2895
2896/// `admin_credit`: credit g1t gives a workspace: promotional, goodwill or a
2897/// refund, with a note, and optionally an expiry. It is spent before
2898/// anything paid in advance, the soonest-expiring first. The workspace's
2899/// owners are emailed. Returns `Outcome<LedgerEntry>`.
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays2900#[derive(Debug, Serialize, Deserialize)]
2901pub struct AdminCreditArgs {
2902 pub workspace: String,
2903 pub amount_micros: i64,
2904 pub note: String,
2905 pub by: String,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging2906 #[serde(default)]
2907 pub kind: CreditKind,
2908 /// RFC 3339; unused credit stops counting then. Never for a refund.
2909 #[serde(default)]
2910 pub expires_at: Option<String>,
2911 /// A refund: what it refunds, in a line, and the day of it
2912 /// (`YYYY-MM-DD`; today if absent).
2913 #[serde(default)]
2914 pub refund_for: Option<String>,
2915 #[serde(default)]
2916 pub refund_day: Option<String>,
2917}
2918
2919/// One credit g1t gave, with what of it was used: spent on usage, the
2920/// soonest-expiring grant first, before anything paid in advance.
2921#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2922#[serde(rename_all = "camelCase")]
2923pub struct CreditGrant {
2924 /// `crd_…`, the grant's ledger reference.
2925 pub id: String,
2926 pub workspace: String,
2927 pub kind: CreditKind,
2928 pub amount_micros: i64,
2929 pub used_micros: i64,
2930 /// What can still be spent: nothing once it expired or was revoked.
2931 pub left_micros: i64,
2932 pub note: String,
2933 #[serde(default)]
2934 pub refund_for: Option<String>,
2935 #[serde(default)]
2936 pub refund_day: Option<String>,
2937 pub expires_at: Option<String>,
2938 pub created_by: String,
2939 pub created_at: String,
2940 /// `open`, `used`, `expired` or `revoked`.
2941 pub state: String,
2942 #[serde(default)]
2943 pub closed_at: Option<String>,
2944 #[serde(default)]
2945 pub closed_note: Option<String>,
2946 #[serde(default)]
2947 pub closed_by: Option<String>,
2948 /// What expiring or revoking took off the balance.
2949 #[serde(default)]
2950 pub closed_micros: i64,
2951 /// What it pays for: `all` usage, or `models` only (agent runs' model
2952 /// cost), which is spent first.
2953 #[serde(default)]
2954 pub scope: String,
2955 /// Where it came from: `staff`, `purchase` or `promo_code`.
2956 #[serde(default)]
2957 pub source: String,
2958}
2959
2960/// `credits` (`Outcome<Credits>`, `AccountArgs`): a workspace's credits from
2961/// g1t, newest first, for its members.
2962#[derive(Clone, Debug, Default, Serialize, Deserialize)]
2963#[serde(rename_all = "camelCase")]
2964pub struct Credits {
2965 pub grants: Vec<CreditGrant>,
2966 /// What is left to spend, in all.
2967 pub left_micros: i64,
2968}
2969
2970/// `admin_credits`: every credit g1t gave, newest first, filtered. Returns
2971/// `AdminCredits`.
2972#[derive(Debug, Default, Serialize, Deserialize)]
2973pub struct AdminCreditsArgs {
2974 #[serde(default)]
2975 pub workspace: Option<String>,
2976 #[serde(default)]
2977 pub kind: Option<CreditKind>,
2978 /// `YYYY-MM`: given that month.
2979 #[serde(default)]
2980 pub month: Option<String>,
2981 /// Given by this member of staff.
2982 #[serde(default)]
2983 pub by: Option<String>,
2984}
2985
2986/// One month's credits of one kind: given, used on usage that month, and
2987/// taken back unused (expired or revoked).
2988#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
2989#[serde(rename_all = "camelCase")]
2990pub struct CreditMonth {
2991 pub month: String,
2992 pub kind: CreditKind,
2993 pub given_micros: i64,
2994 pub grants: u32,
2995 pub used_micros: i64,
2996 pub expired_micros: i64,
2997 pub revoked_micros: i64,
2998}
2999
3000#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3001#[serde(rename_all = "camelCase")]
3002pub struct AdminCredits {
3003 /// At most 200.
3004 pub grants: Vec<CreditGrant>,
3005 /// The last 12 months, newest first, whatever the month filter.
3006 pub months: Vec<CreditMonth>,
3007 /// Who has given credit, for the filter.
3008 pub staff: Vec<String>,
3009}
3010
3011/// `admin_revoke_credit`: what is left of a grant, taken off the balance,
3012/// with why. Returns `Outcome<CreditGrant>`.
3013#[derive(Debug, Serialize, Deserialize)]
3014pub struct AdminRevokeCreditArgs {
3015 pub id: String,
3016 pub note: String,
3017 pub by: String,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3018}
3019
sudo: reset a test workspace's billing so it starts again as a new customer; refused on a live Stripe key, for comped workspaces and for an enterprise's3020/// `admin_reset_billing`: a test workspace's billing wiped, so it starts
3021/// again as a new customer. Only while billing runs on Stripe's test key;
3022/// never a comped workspace or one an enterprise pays for. `confirm` is the
3023/// workspace's slug typed out. Returns `Outcome<BillingReset>`.
3024#[derive(Debug, Serialize, Deserialize)]
3025pub struct AdminResetBillingArgs {
3026 pub workspace: String,
3027 pub confirm: String,
3028 pub note: String,
3029 pub by: String,
3030}
3031
3032/// What a reset removed.
3033#[derive(Clone, Debug, Serialize, Deserialize)]
3034#[serde(rename_all = "camelCase")]
3035pub struct BillingReset {
3036 pub workspace: String,
3037 pub rows: u32,
sudo: a billing reset runs the costs analysis again so every figure is fresh; every submit button shows it is working (CSS only); no margin percentage on less than a cent sold3038 /// Whether the costs analysis ran again after it, so the margin
3039 /// figures no longer hold the workspace's past usage.
3040 #[serde(default)]
3041 pub refreshed: bool,
sudo: reset a test workspace's billing so it starts again as a new customer; refused on a live Stripe key, for comped workspaces and for an enterprise's3042}
3043
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3044/// One change made in sudo.
3045#[derive(Clone, Debug, Serialize, Deserialize)]
3046#[serde(rename_all = "camelCase")]
3047pub struct AdminAction {
3048 pub id: String,
3049 pub account: String,
3050 pub action: String,
3051 pub detail: String,
3052 pub by: String,
3053 pub created_at: String,
3054}
3055
3056/// What a feature's plan costs and includes.
3057#[derive(Clone, Debug, Serialize, Deserialize)]
3058#[serde(rename_all = "camelCase")]
3059pub struct Plan {
3060 pub feature: Feature,
3061 pub title: String,
Merge Stripe Tax, the card fee on card payments, and one free workspace per person3062 /// Charged every month while the plan is on, in cents, excluding tax.
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3063 pub monthly_cents: u32,
Merge Stripe Tax, the card fee on card payments, and one free workspace per person3064 /// The card processing fee on top each month, in cents (0 when the
3065 /// fee is off). Excluding tax, like the price.
3066 #[serde(default)]
3067 pub card_fee_cents: u32,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3068 /// What the monthly price includes, one line each, for people to read.
3069 pub includes: Vec<String>,
3070 /// How usage past the allowance is charged, for people to read.
3071 pub overage: String,
3072}
3073
3074#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
3075#[serde(rename_all = "snake_case")]
3076pub enum SubscriptionStatus {
3077 /// Paid up; the feature works.
3078 Active,
3079 /// Paid up to the end of the period, and ends then.
3080 Canceling,
3081 /// The last payment failed; the feature is off until it is paid.
3082 PastDue,
3083 /// Ended.
3084 Canceled,
3085}
3086
3087impl SubscriptionStatus {
3088 /// Whether the feature works in this state.
3089 pub fn on(self) -> bool {
3090 matches!(self, SubscriptionStatus::Active | SubscriptionStatus::Canceling)
3091 }
3092}
3093
3094/// A workspace's plan for one feature.
3095#[derive(Clone, Debug, Serialize, Deserialize)]
3096#[serde(rename_all = "camelCase")]
3097pub struct Subscription {
3098 pub feature: Feature,
3099 pub status: SubscriptionStatus,
3100 /// RFC 3339: when the period paid for ends, and the plan renews or
3101 /// ends.
3102 pub period_end: Option<String>,
3103 /// Username of whoever turned it on.
3104 pub started_by: String,
3105 /// RFC 3339.
3106 pub started_at: String,
3107}
3108
3109/// A feature as a workspace sees it: what it costs, and its plan if it has
3110/// one.
3111#[derive(Clone, Debug, Serialize, Deserialize)]
3112#[serde(rename_all = "camelCase")]
3113pub struct FeatureState {
3114 pub plan: Plan,
3115 pub subscription: Option<Subscription>,
3116 /// Whether the feature works for the workspace now.
3117 pub on: bool,
3118 /// On without a plan: comped terms, or given by g1t. Nothing to pay
3119 /// and nothing to turn off.
3120 #[serde(default)]
3121 pub included: bool,
3122}
3123
3124/// `features`: every paid feature and the workspace's plan for each.
3125/// Members only. Returns `Outcome<Vec<FeatureState>>`.
3126#[derive(Debug, Serialize, Deserialize)]
3127pub struct FeaturesArgs {
3128 pub workspace: String,
3129 pub viewer: Viewer,
3130}
3131
3132/// `subscribe`: starts the card page for a feature's monthly plan. Owners
3133/// only. Returns `Outcome<Checkout>`; the page's id comes back to
3134/// `return_url` as `session`, for `confirm_subscription`.
3135#[derive(Debug, Serialize, Deserialize)]
3136#[serde(rename_all = "camelCase")]
3137pub struct SubscribeArgs {
3138 pub actor: User,
3139 pub workspace: String,
3140 pub feature: Feature,
3141 pub return_url: String,
3142}
3143
3144/// `confirm_subscription`: turns the feature on once the processor says
3145/// the plan was paid for. Safe to call any number of times. Returns
3146/// `Outcome<FeatureState>`.
3147#[derive(Debug, Serialize, Deserialize)]
3148pub struct ConfirmSubscriptionArgs {
3149 pub workspace: String,
3150 pub viewer: Viewer,
3151 pub session: String,
3152}
3153
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member3154/// `admin_log`: a staff change another service made to a workspace, kept
3155/// in sudo's audit log with billing's own (`admin_audit`). For identity's
3156/// restores and purges of deleted workspaces. Returns `bool`.
3157#[derive(Debug, Serialize, Deserialize)]
3158pub struct AdminLogArgs {
3159 pub workspace: String,
3160 pub action: String,
3161 pub detail: String,
3162 /// The staff member's email.
3163 pub by: String,
3164}
3165
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3166/// `close_workspace`: settles a workspace that is about to be deleted.
3167/// Owners only. Refused while it has an invoice that failed, while it
3168/// holds prepaid credit, or while it owes money it cannot be charged for
3169/// now; otherwise what it owes is invoiced to its card at once (no
3170/// minimum), its plan is cancelled at Stripe straight away, and its
3171/// account is marked closed, so the month-end close, autopay and limit
3172/// warnings pass it by. Its ledger, invoices and statements stay. With
3173/// `dry_run`, only says whether it could, changing nothing. Returns
3174/// `Outcome<bool>`.
3175#[derive(Debug, Serialize, Deserialize)]
3176#[serde(rename_all = "camelCase")]
3177pub struct CloseWorkspaceArgs {
3178 pub actor: User,
3179 pub workspace: String,
3180 #[serde(default)]
3181 pub dry_run: bool,
3182}
3183
3184/// `cancel_subscription` (`resume` false) ends a plan at the end of the
3185/// period paid for; with `resume` true, takes that back. Owners only.
3186/// Returns `Outcome<FeatureState>`.
3187#[derive(Debug, Serialize, Deserialize)]
3188pub struct CancelSubscriptionArgs {
3189 pub actor: User,
3190 pub workspace: String,
3191 pub feature: Feature,
3192 #[serde(default)]
3193 pub resume: bool,
3194}
3195
3196/// `has_feature`: whether a feature works for a workspace now, asked by the
3197/// service that provides it before doing paid work. Returns
3198/// `Outcome<bool>`: a failure, with the reason to show, when it does not.
3199/// True everywhere when no card processor is configured.
3200#[derive(Debug, Serialize, Deserialize)]
3201pub struct HasFeatureArgs {
3202 pub workspace: String,
3203 pub feature: Feature,
3204}
3205
Merge Stripe Tax, the card fee on card payments, and one free workspace per person3206/// `free_workspaces`: which of `workspaces` are free, that is on no paid
3207/// plan. Paid is the g1t plan, an enterprise's terms, or a discount of
3208/// 100% (g1t's own workspaces). Identity asks before a workspace is made
3209/// (a person owns at most one free workspace) and before anyone is added
3210/// to one (a free workspace cannot invite). Returns `Vec<String>`, the
3211/// free ones, lower-cased; none where payments are not set up.
3212#[derive(Debug, Serialize, Deserialize)]
3213pub struct FreeWorkspacesArgs {
3214 pub workspaces: Vec<String>,
3215}
3216
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3217/// `charge_feature`: usage of a feature past its plan's allowance, charged
3218/// from the workspace's credit at cost plus the margin, whatever
3219/// `FREE_WHILE_BUILDING` says. Called by the service that provides it.
3220/// Charged once per `reference`. Returns `Outcome<bool>`: false if that
3221/// reference was charged before.
3222#[derive(Debug, Serialize, Deserialize)]
3223#[serde(rename_all = "camelCase")]
3224pub struct ChargeFeatureArgs {
3225 pub workspace: String,
3226 pub feature: Feature,
3227 /// What it cost g1t, in millionths of a dollar, before the margin.
3228 pub cost_micros: i64,
3229 pub description: String,
3230 /// `namespace/name`, when the usage was one repository's.
3231 pub repo: Option<String>,
3232 /// Unique to this charge, e.g. `deployments/acme/2026-10`.
3233 pub reference: String,
3234 /// For a build: how long it ran. The plan's included build time this
3235 /// month pays for what it can, and only the rest of `cost_micros` is
3236 /// charged.
3237 #[serde(default)]
3238 pub build_seconds: Option<u32>,
3239}
3240
3241// ---------------------------------------------------------------------
3242// Costs and margin: what Cloudflare charges g1t against what g1t
3243// charges (billing's costs.rs, margin.rs and pricing.rs). Staff only.
3244// ---------------------------------------------------------------------
3245
3246/// `admin_costs`: the Costs & margin page. Returns `CostsReport`.
3247#[derive(Debug, Default, Serialize, Deserialize)]
3248pub struct AdminCostsArgs {
3249 /// How many days back, 7 to 90; 30 when absent.
3250 #[serde(default)]
3251 pub days: Option<u32>,
3252}
3253
3254/// One of g1t's products on one day.
3255#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3256#[serde(rename_all = "camelCase")]
3257pub struct CostDay {
3258 pub day: String,
3259 pub bucket: String,
3260 /// What Cloudflare charged g1t.
3261 pub cf_cost_micros: i64,
3262 /// What g1t's meters recorded it cost, at the price book's cost.
3263 pub own_cost_micros: i64,
3264 /// What customers were charged for it at price, before included
3265 /// usage, trials and pools paid for some.
3266 pub value_micros: i64,
3267 /// Of that, what workspaces paid.
3268 pub cash_micros: i64,
3269}
3270
3271/// One product over the range.
3272#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3273#[serde(rename_all = "camelCase")]
3274pub struct ProductMargin {
3275 pub bucket: String,
3276 pub title: String,
3277 /// The cost the margin is taken from: Cloudflare's bill, or g1t's own
3278 /// figure for what Cloudflare does not bill (models).
3279 pub cost_micros: i64,
3280 pub cf_cost_micros: i64,
3281 pub own_cost_micros: i64,
3282 pub value_micros: i64,
3283 pub margin_micros: i64,
3284 pub margin_percent: Option<f64>,
3285 /// `cloudflare` or `ledger`.
3286 pub cost_source: String,
3287 /// Running g1t itself, paid for by the plan.
3288 pub overhead: bool,
3289}
3290
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it3291/// All of g1t over the range: money in against every cost, and against
3292/// the cost of what was sold (every cost less what g1t gave away).
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3293#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3294#[serde(rename_all = "camelCase")]
3295pub struct OverallMargin {
3296 /// What workspaces paid for usage, and for the plan.
3297 pub usage_micros: i64,
3298 pub plans_micros: i64,
3299 pub cost_micros: i64,
3300 pub margin_micros: i64,
3301 pub margin_percent: Option<f64>,
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it3302 /// Of `cost_micros`, what went on usage g1t gave away on purpose:
3303 /// comped workspaces, free periods, the trial and the open-source pool.
3304 #[serde(default)]
3305 pub given_micros: i64,
3306 /// Money in against `cost_micros - given_micros`.
3307 #[serde(default)]
3308 pub sold_margin_micros: i64,
3309 #[serde(default)]
3310 pub sold_margin_percent: Option<f64>,
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running3311 /// What was sold, apart: usage (`usage_micros` against what that usage
3312 /// cost, less what was given), running g1t (`plans_micros` against the
3313 /// platform's cost, less its given share) and what no mapping names.
3314 #[serde(default)]
3315 pub usage_cost_micros: i64,
3316 #[serde(default)]
3317 pub usage_margin_micros: i64,
3318 #[serde(default)]
3319 pub usage_margin_percent: Option<f64>,
3320 #[serde(default)]
3321 pub running_cost_micros: i64,
3322 #[serde(default)]
3323 pub unmapped_cost_micros: i64,
3324 /// `given_micros` by why: comped workspaces, free use (free periods,
3325 /// free allowances, overruns g1t covered), the trial, the open-source pool.
3326 #[serde(default)]
3327 pub given_comped_micros: i64,
3328 #[serde(default)]
3329 pub given_free_micros: i64,
3330 #[serde(default)]
3331 pub given_trial_micros: i64,
3332 #[serde(default)]
3333 pub given_pool_micros: i64,
Merge branch 'worktree-agent-a633ac0f7f66d419d'3334 /// What discounts on an account's terms took below cost plus the
3335 /// margin: given, so a discounted sale is not margin lost.
3336 #[serde(default)]
3337 pub given_discount_micros: i64,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging3338 /// Credits from g1t spent on usage, by kind: given, so usage paid for
3339 /// with them is never money in. Refunds are not here: they come off
3340 /// money in on the day they refund.
3341 #[serde(default)]
3342 pub given_credit_promotional_micros: i64,
3343 #[serde(default)]
3344 pub given_credit_goodwill_micros: i64,
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb973345 /// What testing resets wiped that g1t paid for (`reset_costs`): the
3346 /// model calls and Cloudflare usage still happened, so their cost is
3347 /// given, never a leak.
3348 #[serde(default)]
3349 pub given_reset_micros: i64,
Merge Cloudflare's usage over its billing cycle: every page read, included amounts once a cycle, a projection, test-mode charges never money in (billing 0052)3350 /// What workspaces were charged while payments were not live (Stripe's
3351 /// test mode): no real money came in, so it is given, never money in.
3352 #[serde(default)]
3353 pub given_unpaid_micros: i64,
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging3354 /// Credits over the range: given (every kind), spent on usage, and
3355 /// refunds' money given back.
3356 #[serde(default)]
3357 pub credits_given_micros: i64,
3358 #[serde(default)]
3359 pub credits_used_micros: i64,
3360 #[serde(default)]
3361 pub credits_refunded_micros: i64,
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running3362 /// `cost_micros` by who g1t pays: Cloudflare's bill (billed amounts,
3363 /// after the included allowances), and model providers (the ledger's
3364 /// cost of the tokens, which Cloudflare's bill does not show).
Costs: the plan's included usage counts as paid for the usage it covered, out of what plans leave for running g1t; the run button shows it is running with CSS alone (sudo ships no JavaScript)3365 /// What the plan's included usage paid for, at price (the ledger's
3366 /// `credit_micros`, comped workspaces left out): money in for usage,
3367 /// paid out of `plans_micros`.
3368 #[serde(default)]
3369 pub included_micros: i64,
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running3370 #[serde(default)]
3371 pub cloudflare_cost_micros: i64,
3372 #[serde(default)]
3373 pub models_cost_micros: i64,
Merge Stripe Tax, the card fee on card payments, and one free workspace per person3374 /// Tax collected with payments over the range, net of refunds: owed to
3375 /// the tax authorities, never in cash or revenue.
3376 #[serde(default)]
3377 pub tax_collected_micros: i64,
3378 /// Card processing fees passed on with card payments, net of refunds:
3379 /// they pay Stripe's fee, so they are not revenue either.
3380 #[serde(default)]
3381 pub card_fees_micros: i64,
Merge Cloudflare's usage over its billing cycle: every page read, included amounts once a cycle, a projection, test-mode charges never money in (billing 0052)3382 /// Cloudflare's subscriptions over the range: each day's share of the
3383 /// billing cycle it is in (a month's price over the cycle's days), the
3384 /// same accrual g1t's own spend uses for the calendar month.
3385 #[serde(default)]
3386 pub subscriptions_micros: i64,
3387 /// What AI Gateway priced g1t's own provider traffic at over the range
3388 /// (Cloudflare-billed requests left out): what the providers bill, to
3389 /// set beside `models_cost_micros`, the ledger's figure.
3390 #[serde(default)]
3391 pub gateway_cost_micros: i64,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3392}
3393
3394/// A count, cost or leak that does not add up.
3395#[derive(Clone, Debug, Serialize, Deserialize)]
3396#[serde(rename_all = "camelCase")]
3397pub struct CostDrift {
3398 pub bucket: String,
3399 pub title: String,
3400 /// `count` (units g1t counted against Cloudflare's), `cost` (the bill
Merge branch 'worktree-agent-a633ac0f7f66d419d'3401 /// against the price book's cost of the same usage; for models, what AI
3402 /// Gateway priced g1t's provider traffic at against the ledger's model
3403 /// cost), `unpriced` (model usage AI Gateway put no price on, so its
3404 /// cost is not the providers'), or `leak`.
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3405 pub kind: String,
3406 pub ours: f64,
3407 pub cloudflare: f64,
3408 pub delta_percent: Option<f64>,
3409 pub detail: String,
3410 pub found_at: String,
3411}
3412
3413/// A margin alert, open while its condition lasts.
3414#[derive(Clone, Debug, Serialize, Deserialize)]
3415#[serde(rename_all = "camelCase")]
3416pub struct MarginAlert {
3417 pub id: String,
3418 /// `margin`, `overall`, `leak`, `drift` or `workspace`.
3419 pub kind: String,
3420 /// The product, or the workspace.
3421 pub subject: String,
3422 pub detail: String,
3423 pub since: String,
3424 pub opened_at: String,
3425 pub emailed_at: Option<String>,
3426}
3427
3428/// A change to a price the reconciler measured.
3429#[derive(Clone, Debug, Serialize, Deserialize)]
3430#[serde(rename_all = "camelCase")]
3431pub struct PriceProposal {
3432 pub id: String,
3433 pub meter: String,
3434 pub title: String,
3435 pub unit: String,
3436 pub current_cost_micros: f64,
3437 pub proposed_cost_micros: f64,
3438 pub change_percent: f64,
3439 pub markup_percent: u32,
3440 pub reason: String,
3441 /// `keeper` or `reconciler`.
3442 pub source: String,
3443 /// Far off the current cost: look before approving.
3444 pub suspect: bool,
3445 /// `open`, `applied`, `approved`, `rejected` or `superseded`.
3446 pub status: String,
3447 pub created_at: String,
3448 pub decided_at: Option<String>,
3449 pub decided_by: Option<String>,
3450 pub note: Option<String>,
3451 /// When it takes or took effect, once approved or applied.
3452 pub effective_at: Option<String>,
3453}
3454
3455/// One version of one meter's price. Never changed once written.
3456#[derive(Clone, Debug, Serialize, Deserialize)]
3457#[serde(rename_all = "camelCase")]
3458pub struct PriceVersion {
3459 pub id: String,
3460 pub meter: String,
3461 pub version: u32,
3462 pub cost_micros: f64,
3463 pub markup_percent: u32,
3464 pub price_micros: f64,
3465 pub effective_at: String,
3466 pub reason: String,
3467 pub created_by: String,
3468 /// When the price book took it on; absent while it waits for its date.
3469 pub applied_at: Option<String>,
Merge costs and margin review: gateway query, own spend, discount meters, superseded rises3470 /// What `cost_micros` is: `cost`, what g1t pays for a unit (a
3471 /// provider's dollar passed on at cost is one); `rate`, a price g1t
3472 /// sets with no cost behind it (the agent rate, security activation),
3473 /// so its cost column is its price; `weight`, a multiplier in
3474 /// millionths, not money (the agent rate's token weights).
3475 #[serde(default)]
3476 pub basis: String,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3477}
3478
3479/// What a workspace cost g1t over the range, Cloudflare's costs shared
3480/// out by g1t's own meters, against what it paid.
3481#[derive(Clone, Debug, Serialize, Deserialize)]
3482#[serde(rename_all = "camelCase")]
3483pub struct WorkspaceCost {
3484 pub workspace: String,
3485 pub cost_micros: i64,
3486 pub revenue_micros: i64,
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it3487 /// Of `cost_micros`, what g1t gave away.
3488 #[serde(default)]
3489 pub given_micros: i64,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3490 /// One of g1t's own (comped) workspaces.
3491 pub internal: bool,
3492}
3493
3494/// One Cloudflare meter over the range, and the product it is a cost of.
3495#[derive(Clone, Debug, Serialize, Deserialize)]
3496#[serde(rename_all = "camelCase")]
3497pub struct CostLineSummary {
3498 pub product: String,
3499 pub meter: String,
3500 pub raw_name: String,
3501 pub unit: String,
3502 pub source: String,
3503 pub quantity: f64,
3504 pub cost_micros: i64,
3505 /// Absent when no mapping claims it.
3506 pub bucket: Option<String>,
3507}
3508
3509/// A row of the mapping from Cloudflare's meters to g1t's products.
3510#[derive(Clone, Debug, Serialize, Deserialize)]
3511#[serde(rename_all = "camelCase")]
3512pub struct CostMapping {
3513 pub product: String,
3514 pub meter: String,
3515 pub bucket: String,
3516 pub price_meter: Option<String>,
3517 pub own_meter: Option<String>,
3518 pub scale_to_own: bool,
3519 pub drift_percent: f64,
3520 pub note: String,
3521 pub updated_at: String,
3522 pub updated_by: String,
3523}
3524
3525/// The guardrails on prices and the alerts.
3526#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3527#[serde(rename_all = "camelCase")]
3528pub struct CostSettings {
3529 /// Apply small moves without staff.
3530 pub auto_apply: bool,
3531 /// The largest move applied without staff, either way, in percent.
3532 pub auto_apply_percent: f64,
3533 /// Days between telling customers of a rise and charging it.
3534 pub notice_days: u32,
3535 /// Below this margin, in percent, for `alert_days` days in a row, alert.
3536 pub margin_floor_percent: f64,
3537 pub alert_days: u32,
3538 /// Days with less cost than this say nothing about a margin.
3539 pub min_daily_cost_micros: i64,
3540 /// A workspace costing more than its revenue times this, over 30 days,
3541 /// and at least `anomaly_floor_micros`, is flagged.
3542 pub anomaly_factor: f64,
3543 pub anomaly_floor_micros: i64,
Merge Stripe Tax, the card fee on card payments, and one free workspace per person3544 /// Pass Stripe's card fee on as its own line on every card payment (the
3545 /// plan, Security and quality, prepaying, AI credit, auto-reload and
3546 /// invoices charged to a card), never on a bank transfer or an invoice
3547 /// sent to be paid (`card_fee_percent` and `card_fee_fixed` in the
3548 /// price book). On by default.
Usage, Billing settings and prepaid AI credit; fixes from the UX audit3549 #[serde(default = "yes")]
3550 pub card_fee: bool,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3551}
3552
3553impl Default for CostSettings {
3554 fn default() -> Self {
3555 CostSettings {
3556 auto_apply: true,
3557 auto_apply_percent: 25.0,
3558 notice_days: 14,
3559 margin_floor_percent: 10.0,
3560 alert_days: 3,
3561 min_daily_cost_micros: 100_000,
3562 anomaly_factor: 1.0,
3563 anomaly_floor_micros: 1_000_000,
Usage, Billing settings and prepaid AI credit; fixes from the UX audit3564 card_fee: true,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3565 }
3566 }
3567}
3568
3569/// The Costs & margin page.
3570#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3571#[serde(rename_all = "camelCase")]
3572pub struct CostsReport {
3573 /// A token to read Cloudflare's bill is set.
3574 pub configured: bool,
3575 /// When Cloudflare's bill was last read.
3576 pub fetched_at: Option<String>,
3577 /// The days shown, YYYY-MM-DD.
3578 pub since: String,
3579 pub until: String,
3580 pub days: Vec<CostDay>,
3581 pub products: Vec<ProductMargin>,
3582 pub overall: OverallMargin,
3583 pub drift: Vec<CostDrift>,
3584 pub alerts: Vec<MarginAlert>,
3585 pub proposals: Vec<PriceProposal>,
3586 pub versions: Vec<PriceVersion>,
3587 pub top_workspaces: Vec<WorkspaceCost>,
3588 pub lines: Vec<CostLineSummary>,
3589 pub mappings: Vec<CostMapping>,
3590 pub settings: CostSettings,
3591 /// g1t's own spend against its two caps.
3592 #[serde(default)]
3593 pub caps: SpendCaps,
Merge Cloudflare's usage over its billing cycle: every page read, included amounts once a cycle, a projection, test-mode charges never money in (billing 0052)3594 /// Cloudflare's current billing cycle: its usage cost so far, by meter,
3595 /// and where it is heading. Absent until the bill has been read.
3596 #[serde(default)]
3597 pub cycle: Option<CloudflareCycle>,
3598 /// The last read of Cloudflare's billable usage: what came back.
3599 #[serde(default)]
3600 pub bill_read: Option<BillRead>,
3601 /// Of the range's cost, what no workspace's usage could carry (a day
3602 /// with no usage at all): running g1t, attributed to no one. The
3603 /// workspaces' costs and this add up to the cost.
3604 #[serde(default)]
3605 pub unattributed_micros: i64,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3606}
3607
Merge Cloudflare's usage over its billing cycle: every page read, included amounts once a cycle, a projection, test-mode charges never money in (billing 0052)3608/// Cloudflare's billing cycle (monthly, from the day the account's
3609/// subscription renews), as Cloudflare's Billable usage page shows it.
3610#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3611#[serde(rename_all = "camelCase")]
3612pub struct CloudflareCycle {
3613 /// The cycle's first and last days, YYYY-MM-DD, UTC.
3614 pub start: String,
3615 pub end: String,
3616 pub days: u32,
3617 /// Days from its start to today, today included.
3618 pub days_elapsed: u32,
3619 /// Usage cost so far, after the included allowances.
3620 pub usage_micros: i64,
3621 /// `usage_micros` over the days elapsed, times the cycle's days.
3622 pub projected_micros: i64,
3623 pub average_daily_micros: i64,
3624 /// Cloudflare's subscriptions for the cycle (not on the usage bill).
3625 pub subscriptions_micros: i64,
3626 pub meters: Vec<CycleMeter>,
3627}
3628
3629/// One of Cloudflare's meters over the cycle so far.
3630#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3631#[serde(rename_all = "camelCase")]
3632pub struct CycleMeter {
3633 pub product: String,
3634 pub meter: String,
3635 pub raw_name: String,
3636 pub unit: String,
3637 /// What was used.
3638 pub quantity: f64,
3639 /// What the cycle includes, in the same unit; None without a list price.
3640 pub included: Option<f64>,
3641 /// Past the included amount, as Cloudflare bills it.
3642 pub billable_quantity: f64,
3643 pub cost_micros: i64,
3644 /// `cloudflare` (the cost Cloudflare put on its lines), `list` (the
3645 /// list price past the included amount, while Cloudflare's lines carry
3646 /// no cost), or `none` (no list price known: costed at $0).
3647 pub basis: String,
3648}
3649
3650/// What the last read of Cloudflare's billable usage got back.
3651#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3652#[serde(rename_all = "camelCase")]
3653pub struct BillRead {
3654 pub read_at: String,
3655 pub since: String,
3656 pub until: String,
3657 pub rows: u32,
3658 pub pages: u32,
3659 /// Rows with a consumed quantity (`ConsumedQuantity`), and rows with
3660 /// only a pricing quantity.
3661 pub consumed_rows: u32,
3662 pub pricing_only_rows: u32,
3663 /// Rows Cloudflare put a cost on.
3664 pub costed_rows: u32,
3665}
3666
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3667/// What g1t itself pays for, against its caps (billing's `budget`): the
3668/// daily breaker on all of it, and each comped account's monthly budget.
Costs: Cloudflare's subscriptions read from Cloudflare each day, the estimate only until then; sudo's costs split into Costs & margin and Bill & pricing3669/// One of Cloudflare's subscriptions, at what it comes to a month.
3670#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
3671#[serde(rename_all = "camelCase")]
3672pub struct FixedCost {
3673 pub name: String,
3674 pub monthly_micros: i64,
3675}
3676
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3677/// At cost, never at price. What sudo's Costs page and its red bar show.
3678#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3679#[serde(rename_all = "camelCase")]
3680pub struct SpendCaps {
3681 /// Today (UTC), YYYY-MM-DD, and this month, YYYY-MM.
3682 pub day: String,
3683 pub month: String,
3684 /// What g1t paid for itself today across every workspace: comped work,
3685 /// the trial and open-source pools, free workspaces' overruns, and
3686 /// anything charged without real money behind it.
3687 pub today_micros: i64,
3688 /// `PLATFORM_DAILY_SPEND_CAP_MICROS`. Zero: no breaker.
3689 pub daily_cap_micros: i64,
3690 /// The breaker is open: new hosted-model agent runs that g1t would pay
3691 /// for wait until tomorrow (UTC) or until staff lift it.
3692 pub tripped: bool,
3693 pub tripped_at: Option<String>,
3694 /// Staff lifted it for the rest of the day.
3695 pub lifted_by: Option<String>,
3696 pub lifted_at: Option<String>,
3697 pub lift_note: Option<String>,
3698 /// This month so far, by what paid: `comped`, `trial`, `oss`, `given`,
3699 /// `unpaid`.
3700 pub month_buckets: Vec<SpendBucket>,
3701 /// Each comped account's monthly budget.
3702 pub comped: Vec<CompedBudget>,
3703 /// Free workspaces' share of this month's reconciled costs (git,
3704 /// storage, platform), through yesterday.
3705 pub free_tier_micros: i64,
Costs: Cloudflare's subscriptions read from Cloudflare each day, the estimate only until then; sudo's costs split into Costs & margin and Bill & pricing3706 /// Cloudflare's subscriptions a month: as read from Cloudflare each
3707 /// day, else `CLOUDFLARE_FIXED_MONTHLY_MICROS`, an estimate.
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3708 pub fixed_monthly_micros: i64,
Costs: Cloudflare's subscriptions read from Cloudflare each day, the estimate only until then; sudo's costs split into Costs & margin and Bill & pricing3709 /// `cloudflare` or `estimate`.
3710 #[serde(default)]
3711 pub fixed_source: String,
3712 #[serde(default)]
3713 pub fixed_read_at: Option<String>,
3714 /// Each subscription, when read from Cloudflare.
3715 #[serde(default)]
3716 pub fixed_items: Vec<FixedCost>,
Merge Cloudflare's usage over its billing cycle: every page read, included amounts once a cycle, a projection, test-mode charges never money in (billing 0052)3717 /// Of `fixed_monthly_micros`, this calendar month's days so far: each
3718 /// day's share of the billing cycle it is in, today included.
3719 #[serde(default)]
3720 pub fixed_month_micros: i64,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3721 /// Money in this month, through the last reconciled day.
3722 pub revenue_micros: i64,
Merge costs and margin review: gateway query, own spend, discount meters, superseded rises3723 /// Of this month's buckets, what was spent on workspaces whose billing
3724 /// a testing reset later wiped: still g1t's spend, but no longer on
3725 /// their ledger, so the reconciled figures have it only where the
3726 /// reset kept it (as given away, testing resets).
3727 #[serde(default)]
3728 pub reset_micros: i64,
3729 /// Those workspaces.
3730 #[serde(default)]
3731 pub reset_workspaces: Vec<String>,
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3732}
3733
3734#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3735#[serde(rename_all = "camelCase")]
3736pub struct SpendBucket {
3737 pub bucket: String,
3738 pub title: String,
3739 pub micros: i64,
3740}
3741
3742/// A comped account's monthly budget: what its work cost g1t this month.
3743#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3744#[serde(rename_all = "camelCase")]
3745pub struct CompedBudget {
3746 pub account: String,
3747 pub name: String,
3748 pub used_micros: i64,
3749 /// Zero: no budget.
3750 pub ceiling_micros: i64,
3751 /// The ceiling is `COMPED_MONTHLY_CEILING_MICROS`, not the account's own.
3752 pub default_ceiling: bool,
3753 /// 50, 75, 90, 100, or 0.
3754 pub level: u32,
3755}
3756
3757/// `admin_spend_caps`: g1t's own spend against its caps. Returns `SpendCaps`.
3758#[derive(Debug, Default, Serialize, Deserialize)]
3759pub struct AdminSpendCapsArgs {}
3760
3761/// `admin_lift_breaker`: lets hosted-model runs start again for the rest
3762/// of today (UTC), with why. Recorded in the audit log. Returns
3763/// `Outcome<SpendCaps>`.
3764#[derive(Debug, Serialize, Deserialize)]
3765pub struct AdminLiftBreakerArgs {
3766 pub note: String,
3767 pub by: String,
3768}
3769
The docs folder is gone, and what it held lives where people read it: how a self-hosted g1t runs and how to deploy g1t to Cloudflare are pages on docs.g1t.sh under Run g1t yourself, and speed, rate limits and operating g1t.sh are sections of CONTRIBUTING.md; code that cited a file in docs/ now points to the page or section that covers it, or says what it means itself, and applied migrations and the runner images are left as they were.3770// ---- Platform pauses and the usage watcher ----
3771// docs.g1t.sh/guides/deploy-to-cloudflare/#spend-guardrails
Merge platform pause and the hourly usage watcher: staff can pause compute, schedules, indexing or renders for everyone, the watcher emails on a breach and is never blind quietly, and the models proxy holds each run to its cap (billing 0051, integrations 0006)3772
3773/// A g1t-wide pause, set by staff in sudo or by billing's hourly usage
3774/// watcher on a severe breach. Each level is independent.
3775#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
3776#[serde(rename_all = "snake_case")]
3777pub enum PauseLevel {
3778 /// Agents, sandboxes, Actions hosted jobs, deploy builds: every
3779 /// reservation through billing's `reserve` but embeddings.
3780 Compute,
3781 /// Actions' cron-triggered runs, and the runner's sweep that starts
3782 /// queued agents.
3783 Schedules,
3784 /// Context embeddings and backfills, and search's backfills.
3785 Indexing,
3786 /// Social card rendering, which falls back to a static image.
3787 Renders,
3788}
3789
3790impl PauseLevel {
3791 pub const ALL: [PauseLevel; 4] = [PauseLevel::Compute, PauseLevel::Schedules, PauseLevel::Indexing, PauseLevel::Renders];
3792
3793 pub fn as_str(self) -> &'static str {
3794 match self {
3795 PauseLevel::Compute => "compute",
3796 PauseLevel::Schedules => "schedules",
3797 PauseLevel::Indexing => "indexing",
3798 PauseLevel::Renders => "renders",
3799 }
3800 }
3801
3802 pub fn parse(text: &str) -> Option<PauseLevel> {
3803 PauseLevel::ALL.into_iter().find(|level| level.as_str() == text.trim())
3804 }
3805}
3806
3807/// `platform_pause`: which levels are paused now. Takes nothing. Callers
3808/// keep the answer about 30 seconds; one that cannot read it runs (fails
3809/// open).
3810#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
3811pub struct PlatformPause {
3812 #[serde(default)]
3813 pub compute: bool,
3814 #[serde(default)]
3815 pub schedules: bool,
3816 #[serde(default)]
3817 pub indexing: bool,
3818 #[serde(default)]
3819 pub renders: bool,
3820}
3821
3822impl PlatformPause {
3823 pub fn is(&self, level: PauseLevel) -> bool {
3824 match level {
3825 PauseLevel::Compute => self.compute,
3826 PauseLevel::Schedules => self.schedules,
3827 PauseLevel::Indexing => self.indexing,
3828 PauseLevel::Renders => self.renders,
3829 }
3830 }
3831
3832 pub fn set(&mut self, level: PauseLevel, paused: bool) {
3833 match level {
3834 PauseLevel::Compute => self.compute = paused,
3835 PauseLevel::Schedules => self.schedules = paused,
3836 PauseLevel::Indexing => self.indexing = paused,
3837 PauseLevel::Renders => self.renders = paused,
3838 }
3839 }
3840
3841 pub fn any(&self) -> bool {
3842 PauseLevel::ALL.into_iter().any(|level| self.is(level))
3843 }
3844}
3845
3846/// One level as sudo shows it: who paused it, when and why.
3847#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3848pub struct PauseState {
3849 pub level: String,
3850 pub paused: bool,
3851 pub note: Option<String>,
3852 pub set_by: Option<String>,
3853 pub set_at: Option<String>,
3854 /// Set by the usage watcher, not a person.
3855 pub auto: bool,
3856}
3857
3858/// One metric's usage over an hour or the month so far.
3859#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3860pub struct PlatformMetric {
3861 pub metric: String,
3862 pub title: String,
3863 pub value: f64,
3864 /// Its hourly threshold (`PLATFORM_HOURLY_*`); zero: none.
3865 pub threshold: f64,
3866 /// The script, queue, database or namespace that counted most.
3867 pub top_name: Option<String>,
3868 pub top_value: Option<f64>,
3869}
3870
3871/// A breach the watcher found.
3872#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3873pub struct PlatformBreach {
3874 pub id: String,
3875 pub metric: String,
3876 pub hour: String,
3877 /// `threshold` or `spike`.
3878 pub rule: String,
3879 pub value: f64,
3880 pub threshold: f64,
3881 pub severe: bool,
3882 pub top_name: Option<String>,
3883 pub detail: String,
3884 /// Levels it paused.
3885 pub paused: Vec<String>,
3886 pub opened_at: String,
3887 pub emailed_at: Option<String>,
3888}
3889
3890/// `admin_platform_guard`: the pauses, the last hour read, the month so
3891/// far and the last day's breaches, for sudo's Costs page and its banner.
3892#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3893pub struct PlatformGuard {
3894 pub levels: Vec<PauseState>,
3895 /// The last hour the watcher read (`YYYY-MM-DDTHH:00:00Z`), if any.
3896 pub hour: Option<String>,
3897 pub last_hour: Vec<PlatformMetric>,
3898 pub month: String,
3899 pub month_to_date: Vec<PlatformMetric>,
3900 /// The last 24 hours' breaches, newest first.
3901 pub breaches: Vec<PlatformBreach>,
3902 /// Whether the watcher can read Cloudflare's analytics at all.
3903 pub can_read: bool,
3904 /// `AUTO_PAUSE`: the levels a severe breach may pause.
3905 pub auto_pause: Vec<String>,
3906 /// What the latest run could not see: each query that failed.
3907 #[serde(default)]
3908 pub blind: Vec<BlindQuery>,
3909 /// The latest run found every dataset empty (the wrong account, or a
3910 /// token that cannot see its analytics).
3911 #[serde(default)]
3912 pub empty: bool,
3913 /// The hour the latest run read.
3914 #[serde(default)]
3915 pub last_run: Option<String>,
3916}
3917
3918/// A query the watcher's latest run could not read.
3919#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3920pub struct BlindQuery {
3921 pub key: String,
3922 pub dataset: String,
3923 pub error: String,
3924}
3925
3926/// `admin_platform_guard`. Returns `PlatformGuard`.
3927#[derive(Debug, Default, Serialize, Deserialize)]
3928pub struct AdminPlatformGuardArgs {}
3929
3930/// `admin_set_pause`: pauses or resumes one level, with why. Recorded in
3931/// the audit log. Returns `Outcome<PlatformGuard>`.
3932#[derive(Debug, Serialize, Deserialize)]
3933pub struct AdminSetPauseArgs {
3934 pub level: String,
3935 pub paused: bool,
3936 pub note: String,
3937 pub by: String,
3938}
3939
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays3940/// `admin_cost_alerts`: the open margin alerts, for sudo's banner.
3941/// Returns `Vec<MarginAlert>`.
3942#[derive(Debug, Default, Serialize, Deserialize)]
3943pub struct AdminCostAlertsArgs {}
3944
3945/// `admin_decide_proposal`: approve or reject a price proposal. An
3946/// approved rise takes effect after the notice period. Returns
3947/// `Outcome<PriceProposal>`.
3948#[derive(Debug, Serialize, Deserialize)]
3949pub struct AdminDecideProposalArgs {
3950 pub id: String,
3951 /// `approve` or `reject`.
3952 pub decision: String,
3953 #[serde(default)]
3954 pub note: String,
3955 pub by: String,
3956}
3957
3958/// `admin_set_cost_settings`. Returns `Outcome<CostSettings>`.
3959#[derive(Debug, Serialize, Deserialize)]
3960pub struct AdminSetCostSettingsArgs {
3961 pub settings: CostSettings,
3962 pub by: String,
3963}
3964
3965/// `admin_set_cost_mapping`: adds, changes or (with `remove`) removes a
3966/// mapping row. Returns `Outcome<CostMapping>`.
3967#[derive(Debug, Serialize, Deserialize)]
3968pub struct AdminSetCostMappingArgs {
3969 pub product: String,
3970 pub meter: String,
3971 #[serde(default)]
3972 pub bucket: String,
3973 #[serde(default)]
3974 pub price_meter: Option<String>,
3975 #[serde(default)]
3976 pub own_meter: Option<String>,
3977 #[serde(default)]
3978 pub scale_to_own: bool,
3979 #[serde(default)]
3980 pub drift_percent: Option<f64>,
3981 #[serde(default)]
3982 pub note: String,
3983 #[serde(default)]
3984 pub remove: bool,
3985 pub by: String,
3986}
3987
3988/// `admin_run_costs`: reads Cloudflare's bill and reconciles now, as the
3989/// daily run does. Returns `Outcome<CostsRun>`.
3990#[derive(Debug, Default, Serialize, Deserialize)]
3991pub struct AdminRunCostsArgs {
3992 #[serde(default)]
3993 pub by: String,
3994}
3995
3996#[derive(Clone, Debug, Default, Serialize, Deserialize)]
3997#[serde(rename_all = "camelCase")]
3998pub struct CostsRun {
3999 pub lines: u32,
4000 pub days: u32,
4001 pub proposals: u32,
4002 pub alerts: u32,
4003 /// What could not be read, in words.
4004 pub problems: Vec<String>,
4005}
4006
Usage, Billing settings and prepaid AI credit; fixes from the UX audit4007// --- The Usage page ----------------------------------------------------------
4008
4009/// The product families the Usage page groups meters into, in order, with
4010/// their names.
4011pub const PRODUCTS: [(&str, &str); 8] = [
4012 ("agent", "Agent"),
4013 ("sandboxes", "Sandboxes"),
4014 ("gateway", "AI Gateway"),
4015 ("deployments", "Deployments"),
4016 ("git_storage", "Git & storage"),
4017 ("packages", "Packages"),
4018 ("security", "Security & quality"),
4019 ("search", "Search"),
4020];
4021
4022/// `usage_report`: a workspace's usage over a range of days, at price, by
4023/// product, meter, project and day. The figures are the ledger's: the same
4024/// lines the statement and invoices read, so every page agrees. Members
4025/// only. Returns `Outcome<UsageReport>`.
4026#[derive(Debug, Serialize, Deserialize)]
4027#[serde(rename_all = "camelCase")]
4028pub struct UsageReportArgs {
4029 pub workspace: String,
4030 pub viewer: Viewer,
4031 /// The first day, `YYYY-MM-DD` (UTC).
4032 pub from: String,
4033 /// The last day, `YYYY-MM-DD`, included.
4034 pub until: String,
4035 /// Only these product families (`agent`, `sandboxes`…); all when empty.
4036 #[serde(default)]
4037 pub products: Vec<String>,
4038 /// Only these projects (repositories, `owner/name`); all when empty.
4039 #[serde(default)]
4040 pub projects: Vec<String>,
4041}
4042
4043/// What usage came to over a range, and what paid for it. `price_micros`
4044/// less `discount_micros`, `included_micros` and `credits_micros` is
4045/// `charged_micros`.
4046#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
4047#[serde(rename_all = "camelCase")]
4048pub struct UsageTotals {
4049 /// Usage at price, metered usage not yet charged (`pending_micros`)
4050 /// included.
4051 pub price_micros: i64,
4052 /// What the account's discount took off.
4053 pub discount_micros: i64,
4054 /// What the plan's included usage, the trial and g1t's pools paid.
4055 pub included_micros: i64,
4056 /// What credit paid: AI credit, credit from g1t.
4057 pub credits_micros: i64,
4058 /// What is left for the workspace to pay.
4059 pub charged_micros: i64,
4060 /// Metered this month and charged when it closes (storage, git
4061 /// operations, scans, embeddings, domains), at price.
4062 pub pending_micros: i64,
Money is written one way. A single formatter turns millionths of a dollar into dollars, rounding half up on whole micros rather than on a float, so the same sum reads the same on every page: under a cent reads <$0.01 on a total and exactly nothing is $0.00, while the statement's lines, a session's receipt, the price book and an agent's effort costs carry up to four places where the fraction of a cent is the point; the six formatters that each rounded their own way are gone. This month is the calendar month in UTC from its first day to today everywhere, and billing counts the month's not-yet-closed usage in any range that reaches into the current month, so the top bar's pill, Spend, Home and Usage ask for the same days and get the same figure; Home now reads the usage report the others read instead of adding up statements. Usage's pending sentence says what of that usage the close will charge after the discount and included usage, which the billing API returns as pending_charged_micros. A reconciliation test holds the pill, Spend, Home and Usage to one number for one month. The usage and billing guide says how amounts are written and what this month means.4063 /// What of `pending_micros` the workspace will be charged when the
4064 /// month closes: its price less what g1t covers and what the discount
4065 /// takes off, as the close will enter it. Credit comes off at the close.
4066 #[serde(default)]
4067 pub pending_charged_micros: i64,
Usage, Billing settings and prepaid AI credit; fixes from the UX audit4068 /// What it cost g1t, before any markup.
4069 pub cost_micros: i64,
4070}
4071
Spend adds up on one ledger. Charged this month has one definition, price less discount, included usage and credit, shared by the plan card, the spend limit, Spend and the top bar; the limit had counted usage not yet closed at full price before the discount, so a comped workspace read as charged a cent. Every agent line on the ledger names the agent and who asked, repository runs by g1t included, so Spent is the sum of its products, Agents is the agent product, and by agent adds up to it; the billing API returns by_agent and by_person. The usage and billing guide says how spend is counted.4072/// One agent's or one person's share of the agent product over the range,
4073/// at price, from the ledger lines attributed to them.
4074#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
4075#[serde(rename_all = "camelCase")]
4076pub struct UsageShare {
4077 /// The agent's handle or the person's username; empty for lines
4078 /// attributed to no one (work from before attribution, or that no
4079 /// person asked for).
4080 pub key: String,
4081 pub label: String,
4082 pub micros: i64,
4083 /// Ledger lines.
4084 pub count: u32,
4085}
4086
Usage, Billing settings and prepaid AI credit; fixes from the UX audit4087/// One day's usage of one product, at price.
4088#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
4089#[serde(rename_all = "camelCase")]
4090pub struct UsageDay {
4091 /// `YYYY-MM-DD`.
4092 pub day: String,
4093 pub product: String,
4094 pub micros: i64,
4095}
4096
4097/// How much of an allowance is used, in the meter's unit.
4098#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
4099#[serde(rename_all = "camelCase")]
4100pub struct Allowance {
4101 pub used: f64,
4102 pub of: f64,
4103 /// `bytes`, `operations`, `dollars`…
4104 pub unit: String,
4105}
4106
4107/// One project's part of a meter.
4108#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
4109#[serde(rename_all = "camelCase")]
4110pub struct ProjectUsage {
4111 /// `owner/name`, or empty for usage that is not one project's.
4112 pub project: String,
4113 pub micros: i64,
4114 pub quantity: f64,
4115}
4116
4117/// One meter over the range.
4118#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
4119#[serde(rename_all = "camelCase")]
4120pub struct MeterLine {
4121 /// `agent_models`, `agent_rate`, `sandbox`, `builds`…
4122 pub key: String,
4123 pub label: String,
4124 pub product: String,
4125 /// What `quantity` counts: `tokens`, `seconds`, `bytes`, `operations`,
4126 /// `entries`.
4127 pub unit: String,
4128 pub quantity: f64,
4129 /// At price.
4130 pub micros: i64,
4131 /// Of `micros`, metered this month and charged when it closes.
4132 #[serde(default)]
4133 pub pending_micros: i64,
4134 /// Every day of the range, oldest first, at price: the sparkline.
4135 pub daily: Vec<i64>,
4136 #[serde(default)]
4137 pub allowance: Option<Allowance>,
4138 pub by_project: Vec<ProjectUsage>,
Merge branch 'model-routing'4139 /// How the quantity is counted, when that needs saying: for the agent
4140 /// rate, its tokens are weighted by kind, and this names the weights.
4141 #[serde(default)]
4142 pub note: Option<String>,
Usage, Billing settings and prepaid AI credit; fixes from the UX audit4143}
4144
4145/// A part of a product, such as the agent's runs, reviews and plans.
4146#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
4147#[serde(rename_all = "camelCase")]
4148pub struct FeatureUsage {
4149 pub key: String,
4150 pub label: String,
4151 pub micros: i64,
4152 pub count: u32,
4153}
4154
Merge branch 'model-routing'4155/// The tokens one model used over the range, as the model proxy counted
4156/// them: on g1t's models and the workspace's own provider alike.
4157#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
4158#[serde(rename_all = "camelCase")]
4159pub struct ModelTokens {
4160 /// The model's id, as it ran.
4161 pub model: String,
4162 pub input: u64,
4163 pub output: u64,
4164 pub cache_read: u64,
4165 pub cache_write: u64,
4166}
4167
Usage, Billing settings and prepaid AI credit; fixes from the UX audit4168/// One product family over the range.
4169#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
4170#[serde(rename_all = "camelCase")]
4171pub struct ProductUsage {
4172 pub key: String,
4173 pub label: String,
4174 pub micros: i64,
4175 pub meters: Vec<MeterLine>,
4176 /// For the agent: by what it was doing (runs, reviews, plans, checks).
4177 #[serde(default)]
4178 pub features: Vec<FeatureUsage>,
4179}
4180
4181#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
4182#[serde(rename_all = "camelCase")]
4183pub struct UsageReport {
4184 pub from: String,
4185 pub until: String,
4186 pub totals: UsageTotals,
4187 /// Each day and product with usage, oldest first.
4188 pub days: Vec<UsageDay>,
4189 /// Every product family, in order, even with nothing used.
4190 pub products: Vec<ProductUsage>,
4191 /// Every project with usage in the range, for the filter.
4192 pub projects: Vec<String>,
Merge branch 'model-routing'4193 /// Agent tokens by model over the range, most first.
4194 #[serde(default)]
4195 pub models: Vec<ModelTokens>,
Spend adds up on one ledger. Charged this month has one definition, price less discount, included usage and credit, shared by the plan card, the spend limit, Spend and the top bar; the limit had counted usage not yet closed at full price before the discount, so a comped workspace read as charged a cent. Every agent line on the ledger names the agent and who asked, repository runs by g1t included, so Spent is the sum of its products, Agents is the agent product, and by agent adds up to it; the billing API returns by_agent and by_person. The usage and billing guide says how spend is counted.4196 /// The agent product (model tokens, the agent rate and agents'
4197 /// sandbox time) by the agent that did the work, most first. Their sum
4198 /// is the agent product's total: what agents cost is what the ledger
4199 /// charges for them, not a second count.
4200 #[serde(default)]
4201 pub by_agent: Vec<UsageShare>,
4202 /// The same by who asked; work no person asked for (routines, agents
4203 /// helping agents, lines from before attribution) under an empty key.
4204 #[serde(default)]
4205 pub by_person: Vec<UsageShare>,
Usage, Billing settings and prepaid AI credit; fixes from the UX audit4206 /// The plan's included usage this month, when the workspace has it.
4207 #[serde(default)]
4208 pub included: Option<Allowance>,
4209 /// The account's discount, in percent, when it has one.
4210 #[serde(default)]
4211 pub discount_percent: Option<u32>,
4212 /// AI credit left now, and credit from g1t for everything.
4213 pub ai_credit_micros: i64,
4214 pub credit_micros: i64,
4215 /// The trial credit left, for a workspace on its trial.
4216 #[serde(default)]
4217 pub trial_micros: Option<i64>,
4218 pub plan: PlanKind,
4219 /// Nothing is charged while g1t is being built out.
4220 pub free: bool,
4221}
4222
4223// --- AI credit -----------------------------------------------------------------
4224
4225/// Auto-reload: when AI credit falls below `threshold_micros`, the saved
4226/// card is charged to bring it back to `target_micros`, at most
4227/// `monthly_max_micros` in a calendar month. Off by default. A failed
4228/// charge turns it off and tells the owners.
4229#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
4230#[serde(rename_all = "camelCase")]
4231pub struct AiReload {
4232 pub enabled: bool,
4233 pub threshold_micros: i64,
4234 pub target_micros: i64,
4235 pub monthly_max_micros: i64,
4236 /// Reloaded this month so far.
4237 #[serde(default)]
4238 pub reloaded_micros: i64,
4239 /// When it last failed and was turned off, and why.
4240 #[serde(default)]
4241 pub failed_at: Option<String>,
4242 #[serde(default)]
4243 pub error: Option<String>,
4244}
4245
4246/// The card fee passed on when AI credit is bought by card.
4247#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
4248#[serde(rename_all = "camelCase")]
4249pub struct CardFee {
4250 pub on: bool,
4251 /// Per dollar charged, in millionths: 29,000 is 2.9%.
4252 pub percent_micros: f64,
4253 pub fixed_cents: u32,
4254}
4255
4256/// `ai_credit` (`AccountArgs`): a workspace's prepaid AI credit, what it
4257/// pays for and how it is bought. Members only. Returns `Outcome<AiCredit>`.
4258#[derive(Clone, Debug, Serialize, Deserialize)]
4259#[serde(rename_all = "camelCase")]
4260pub struct AiCredit {
4261 /// What is left to spend on Agent and AI Gateway usage.
4262 pub balance_micros: i64,
4263 /// Of it, bought (paid) and given (promotional).
4264 pub purchased_micros: i64,
4265 pub given_micros: i64,
4266 /// Its grants, newest first.
4267 pub grants: Vec<CreditGrant>,
4268 /// A 100% discount: AI usage is free, shown at its price then the
4269 /// discount. Nothing to buy.
4270 pub free_via_discount: bool,
4271 /// Invoiced terms (an enterprise): models are billed after use, so no
4272 /// credit is needed.
4273 pub postpaid: bool,
4274 /// Whether new runs on g1t's models are refused now for want of credit.
4275 pub blocked: bool,
4276 /// Whether the workspace may buy it: on the plan, not free.
4277 pub can_buy: bool,
4278 pub presets_cents: Vec<u32>,
4279 pub min_cents: u32,
4280 pub max_cents: u32,
4281 pub card_fee: CardFee,
4282 pub reload: AiReload,
4283 /// The agent rate per million tokens, now, at price.
4284 pub agent_rate_micros: f64,
4285 /// The markup on models' provider price, in percent.
4286 pub model_markup_percent: u32,
4287 /// The markup on AI Gateway's provider price, in percent.
4288 pub gateway_markup_percent: u32,
4289 /// The AI credit given once on starting the plan.
4290 pub upgrade_credit_micros: i64,
4291 /// How long bought credit lasts, in days.
4292 pub expires_days: u32,
4293}
4294
4295/// `buy_ai_credit`: Stripe's page to buy AI credit, one payment by card,
4296/// with the card fee as its own line. Owners only. Returns
4297/// `Outcome<Checkout>`; the page's id comes back to `return_url` as
4298/// `ai_credit`, for `confirm_ai_credit`.
4299#[derive(Debug, Serialize, Deserialize)]
4300#[serde(rename_all = "camelCase")]
4301pub struct BuyAiCreditArgs {
4302 pub actor: User,
4303 pub workspace: String,
4304 /// The credit, in cents; the card fee is added on top.
4305 #[serde(alias = "amount_cents")]
4306 pub amount_cents: u32,
4307 #[serde(alias = "return_url")]
4308 pub return_url: String,
4309}
4310
4311/// `confirm_ai_credit`: credits a purchase once Stripe says it was paid,
4312/// once. Safe to repeat; the webhook does the same. Returns
4313/// `Outcome<AiCredit>`.
4314#[derive(Debug, Serialize, Deserialize)]
4315pub struct ConfirmAiCreditArgs {
4316 pub workspace: String,
4317 pub viewer: Viewer,
4318 pub session: String,
4319}
4320
4321/// `set_ai_reload`: auto-reload's settings. Owners only. Returns
4322/// `Outcome<AiCredit>`.
4323#[derive(Debug, Serialize, Deserialize)]
4324#[serde(rename_all = "camelCase")]
4325pub struct SetAiReloadArgs {
4326 pub actor: User,
4327 pub workspace: String,
4328 pub enabled: bool,
4329 #[serde(alias = "threshold_micros")]
4330 pub threshold_micros: i64,
4331 #[serde(alias = "target_micros")]
4332 pub target_micros: i64,
4333 #[serde(alias = "monthly_max_micros")]
4334 pub monthly_max_micros: i64,
4335}
4336
4337// --- Budgets ------------------------------------------------------------------
4338
4339/// `set_budget`: the monthly budget on usage after included usage: the
4340/// owners' spend limit, its alerts, whether usage pauses at 100%, and an
4341/// optional webhook. Owners only. Returns `Outcome<Limit>`.
4342#[derive(Debug, Serialize, Deserialize)]
4343#[serde(rename_all = "camelCase")]
4344pub struct SetBudgetArgs {
4345 pub actor: User,
4346 pub workspace: String,
4347 /// The amount; None keeps the automatic one.
4348 #[serde(default, alias = "amount_micros")]
4349 pub amount_micros: Option<i64>,
4350 /// Some of 50, 75, 90 and 100.
4351 #[serde(default)]
4352 pub alerts: Vec<u32>,
4353 #[serde(default = "yes", alias = "pause_at_limit")]
4354 pub pause_at_limit: bool,
4355 /// An HTTPS address, or None for no webhook.
4356 #[serde(default)]
4357 pub webhook: Option<String>,
4358 /// Leave the spend limit as it is and change only the alerts, the
4359 /// pause and the webhook.
4360 #[serde(default, alias = "keep_limit")]
4361 pub keep_limit: bool,
4362}
4363
4364// --- Billing details -----------------------------------------------------------
4365
4366/// A postal address, as Stripe keeps it.
4367#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
4368#[serde(rename_all = "camelCase")]
4369pub struct PostalAddress {
4370 #[serde(default)]
4371 pub line1: String,
4372 #[serde(default)]
4373 pub line2: String,
4374 #[serde(default)]
4375 pub city: String,
4376 #[serde(default)]
4377 pub state: String,
4378 #[serde(default)]
4379 pub postal_code: String,
4380 /// Two letters, `US`.
4381 #[serde(default)]
4382 pub country: String,
4383}
4384
4385/// The default way the workspace pays, as far as it is safe to show.
4386#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
4387#[serde(rename_all = "camelCase")]
4388pub struct PaymentMethod {
4389 /// `card`, or another kind Stripe has.
4390 pub kind: String,
4391 #[serde(default)]
4392 pub brand: Option<String>,
4393 #[serde(default)]
4394 pub last4: Option<String>,
4395 #[serde(default)]
4396 pub exp_month: Option<u32>,
4397 #[serde(default)]
4398 pub exp_year: Option<u32>,
4399}
4400
4401/// One of the customer's invoices at Stripe: the plan, activations, AI
4402/// credit and month-end usage.
4403#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
4404#[serde(rename_all = "camelCase")]
4405pub struct StripeInvoice {
4406 pub id: String,
4407 #[serde(default)]
4408 pub number: Option<String>,
4409 /// `paid`, `open`, `void`, `uncollectible` or `draft`.
4410 pub status: String,
4411 pub total_cents: i64,
4412 pub currency: String,
4413 /// RFC 3339.
4414 pub created_at: String,
4415 #[serde(default)]
4416 pub description: Option<String>,
4417 #[serde(default)]
4418 pub hosted_url: Option<String>,
4419 #[serde(default)]
4420 pub pdf_url: Option<String>,
4421}
4422
4423/// What the next invoice will be, from g1t's own ledger.
4424#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
4425#[serde(rename_all = "camelCase")]
4426pub struct UpcomingInvoice {
4427 /// When the month closes, RFC 3339.
4428 pub closes_at: String,
4429 /// The plan and activations, at their monthly price.
4430 pub subscriptions_micros: i64,
4431 /// Usage still owed, after included usage, credit and any discount.
4432 pub usage_micros: i64,
4433 pub total_micros: i64,
4434}
4435
4436/// `billing_details` (`AccountArgs`): who the invoices are for, the default
4437/// payment method, and the invoices, from the Stripe customer. Members see
4438/// it; owners change it. Returns `Outcome<BillingDetails>`.
4439#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
4440#[serde(rename_all = "camelCase")]
4441pub struct BillingDetails {
4442 /// Whether the workspace has a Stripe customer yet.
4443 pub customer: bool,
4444 pub email: Option<String>,
4445 pub name: Option<String>,
4446 pub address: Option<PostalAddress>,
4447 /// `eu_vat`, `us_ein`…, and its value.
4448 pub tax_id_type: Option<String>,
4449 pub tax_id: Option<String>,
4450 /// Printed on invoices.
4451 pub po_number: Option<String>,
4452 /// The invoices' language, such as `en` or `fr`.
4453 pub language: Option<String>,
4454 pub payment_method: Option<PaymentMethod>,
4455 pub invoices: Vec<StripeInvoice>,
4456 pub upcoming: UpcomingInvoice,
4457 /// Stripe could not be read: what is shown is what g1t keeps.
4458 #[serde(default)]
4459 pub unavailable: Option<String>,
Merge Stripe Tax, the card fee on card payments, and one free workspace per person4460 /// Whether Stripe Tax can place the customer from the address: tax
4461 /// is worked out from it, and without it nothing is charged.
4462 #[serde(default)]
4463 pub tax_location: bool,
4464 /// Set when g1t did not charge for want of an address (RFC 3339).
4465 #[serde(default)]
4466 pub tax_address_needed_at: Option<String>,
4467 /// Stripe's check of the tax ID: `pending`, `verified`, `unverified` or
4468 /// `unavailable`.
4469 #[serde(default)]
4470 pub tax_id_status: Option<String>,
4471 /// `none`, `exempt` or `reverse`, as staff set it at Stripe; g1t never
4472 /// changes it.
4473 #[serde(default)]
4474 pub tax_exempt: Option<String>,
Usage, Billing settings and prepaid AI credit; fixes from the UX audit4475}
4476
4477/// `set_billing_details`: saves the invoice details on the Stripe customer.
4478/// Owners only. Absent fields are left as they are; an empty string clears
4479/// one. Returns `Outcome<BillingDetails>`.
4480#[derive(Debug, Serialize, Deserialize)]
4481#[serde(rename_all = "camelCase")]
4482pub struct SetBillingDetailsArgs {
4483 pub actor: User,
4484 pub workspace: String,
4485 #[serde(default)]
4486 pub email: Option<String>,
4487 #[serde(default)]
4488 pub name: Option<String>,
4489 #[serde(default)]
4490 pub address: Option<PostalAddress>,
4491 #[serde(default, alias = "tax_id_type")]
4492 pub tax_id_type: Option<String>,
4493 #[serde(default, alias = "tax_id")]
4494 pub tax_id: Option<String>,
4495 #[serde(default, alias = "po_number")]
4496 pub po_number: Option<String>,
4497 #[serde(default)]
4498 pub language: Option<String>,
4499}
4500
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays4501#[cfg(test)]
4502mod tests {
4503 use super::*;
4504
4505 #[test]
4506 fn an_account_carries_no_run_fee() {
4507 let account = Account {
4508 workspace: "acme".into(),
4509 balance_micros: 0,
4510 status: Status { enabled: true, live: false, free: false },
4511 margin_percent: 20,
4512 card: None,
4513 };
4514 let json = serde_json::to_value(account).unwrap();
4515 let mut keys: Vec<&str> = json.as_object().unwrap().keys().map(String::as_str).collect();
4516 keys.sort_unstable();
4517 assert_eq!(keys, ["balanceMicros", "card", "marginPercent", "status", "workspace"]);
4518 }
4519
4520 #[test]
4521 fn a_price_change_says_when_the_markup_moved() {
4522 let change = PriceChange {
4523 meter: "sandbox_second".into(),
4524 old_cost_micros: 21.0,
4525 new_cost_micros: 21.0,
4526 markup_percent: 20,
4527 old_markup_percent: Some(138),
4528 reason: "Sandbox time is now charged at cost plus 20% from the first second".into(),
4529 created_at: "2026-10-05T00:00:00Z".into(),
4530 effective_at: None,
4531 };
4532 assert_eq!(serde_json::to_value(&change).unwrap()["oldMarkupPercent"], 138);
4533 let cost_only = PriceChange { old_markup_percent: None, ..change };
4534 assert!(serde_json::to_value(&cost_only).unwrap().get("oldMarkupPercent").is_none());
4535 }
4536
4537 #[test]
4538 fn features_are_named_as_the_site_sends_them() {
4539 assert_eq!(
4540 serde_json::to_value(Feature::Deployments).unwrap(),
4541 serde_json::json!("deployments")
4542 );
4543 assert_eq!(Feature::parse("deployments"), Some(Feature::Deployments));
4544 assert_eq!(serde_json::to_value(Feature::Plan).unwrap(), serde_json::json!("plan"));
4545 assert_eq!(Feature::parse("plan"), Some(Feature::Plan));
4546 // Older readers named the plan Team.
4547 assert_eq!(Feature::parse("team"), Some(Feature::Plan));
4548 assert_eq!(serde_json::from_value::<Feature>(serde_json::json!("team")).unwrap(), Feature::Plan);
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar4549 assert_eq!(Feature::ALL, [Feature::Plan, Feature::Security]);
4550 assert_eq!(Feature::parse("security"), Some(Feature::Security));
4551 assert_eq!(serde_json::to_value(Feature::Security).unwrap(), serde_json::json!("security"));
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays4552 assert!(SubscriptionStatus::Canceling.on());
4553 assert!(!SubscriptionStatus::PastDue.on());
4554 }
4555
4556 #[test]
4557 fn a_reservation_is_asked_for_and_answered_in_camel_case() {
4558 let asked: ReserveArgs = serde_json::from_value(serde_json::json!({
4559 "workspace": "acme",
4560 "repo": { "namespace": "acme", "name": "web" },
4561 "public": true,
4562 "kind": "check",
4563 "estimateMicros": 2_000_000,
4564 }))
4565 .unwrap();
4566 assert_eq!(asked.kind, ComputeKind::Check);
4567 assert!(asked.kind.open_source_pool());
4568 assert!(!ComputeKind::Agent.open_source_pool());
4569 // Rust callers that write snake_case are read too.
4570 let snake: ReserveArgs = serde_json::from_value(serde_json::json!({
4571 "workspace": "acme",
4572 "repo": { "namespace": "acme", "name": "web" },
4573 "public": false,
4574 "kind": "agent",
4575 "estimate_micros": 1,
4576 }))
4577 .unwrap();
4578 assert_eq!(snake.estimate_micros, 1);
4579 let answer = Reservation { id: "rsv_1".into(), paid_by: PaidBy::OnDemand, held_micros: 5, expires_at: String::new() };
4580 assert_eq!(serde_json::to_value(&answer).unwrap()["paidBy"], "on_demand");
4581 assert_eq!(serde_json::to_value(PlanKind::Internal).unwrap(), "internal");
4582 assert!(!PlanKind::Free.on_demand() && PlanKind::Enterprise.on_demand());
4583 }
4584
4585 #[test]
4586 fn a_refusal_carries_its_own_code() {
4587 let refused: crate::Outcome<Reservation> =
4588 crate::Outcome::fail(crate::FailureCode::OssPoolEmpty, "The open-source pool is spent.");
4589 let json = serde_json::to_value(&refused).unwrap();
4590 assert_eq!(json["error"]["code"], "oss_pool_empty");
4591 assert_eq!(crate::FailureCode::NotPaid.http_status(), 402);
4592 assert_eq!(crate::FailureCode::Paused.http_status(), 409);
4593 }
4594
4595 #[test]
4596 fn who_pays_is_read_as_the_runner_sends_it() {
4597 let run: StartRunArgs = serde_json::from_value(serde_json::json!({
4598 "workspace": "acme",
4599 "repo": { "namespace": "acme", "name": "web" },
4600 "number": 7,
4601 "task": "implement",
4602 "model": "Claude Sonnet 5.5",
4603 "billedTo": "workspace",
4604 }))
4605 .unwrap();
4606 assert_eq!(run.billed_to, "workspace");
4607 }
4608}

This file's history is long; its oldest lines are credited to the oldest commit read.