Skip to content
4,598 linesCodeBlameRaw

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

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

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