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