Skip to content

g1t/crates/contracts/src/billing.rs

3,888 lines141,041 bytesCodeBlame

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.

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

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