Skip to content

g1t/packages/contracts/src/billing.ts

1,693 lines67,539 bytesCodeBlame

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

Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1import type { ComputeKind, Reservation } from "./compute";
Agents as a team: lifecycle, merge queue, billing and a new shell2import type { User, Viewer } from "./identity";
3import type { RepoPath } from "./repos";
4import type { Result } from "./result";
5
6/** Millionths of a US dollar in one dollar: the unit money is held in. */
7export const MICROS_PER_DOLLAR = 1_000_000;
8
9/** Whether workspaces are charged for agents at all, and with real money. */
10export type BillingStatus = {
11 /**
12 * False when no card processor is configured: nothing is charged, and who
13 * may run agents is decided some other way.
14 */
15 enabled: boolean;
16 /** False while the card processor is in its test mode, where cards are not real. */
17 live: boolean;
Free while g1t is being built out; agents can check out their own forks18 /**
19 * True while g1t is being built out: runs are recorded with what they
20 * cost, but nothing is charged and no credit is needed. Not forever.
21 */
22 free?: boolean;
Agents as a team: lifecycle, merge queue, billing and a new shell23};
24
25/** A workspace's standing. */
26export type BillingAccount = {
27 workspace: string;
28 /**
29 * Credit left, in millionths of a dollar. Can dip below zero by the cost
30 * of the runs that were under way when it ran out.
31 */
32 balanceMicros: number;
33 status: BillingStatus;
34 /** What is added to a run's cost, in percent. */
35 marginPercent: number;
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace36 /** The card charged near the limit and when a month closes, if one is saved. */
37 card?: { brand: string; last4: string; expMonth: number; expYear: number } | null;
Agents as a team: lifecycle, merge queue, billing and a new shell38};
39
40/** One line of a workspace's statement. */
41export type LedgerEntry = {
42 id: string;
43 /** Credit bought with a card, or an agent's run. */
44 kind: "top_up" | "usage";
45 /** Positive for credit added, negative for usage. */
46 amountMicros: number;
47 description: string;
48 /** For usage: the repository and pull request the agent worked on. */
49 repo: string | null;
50 number: number | null;
51 /** For usage: `implement`, `review` or `update`. */
52 task: string | null;
53 /** For usage: the model, by its public name. */
54 model: string | null;
Integrations: your own model provider, alerts that open issues, tickets agents read55 /** For usage: who paid the model provider. */
56 billedTo: "g1t" | "workspace";
Agents as a team: lifecycle, merge queue, billing and a new shell57 /** For a top-up: the username of whoever paid. */
58 createdBy: string | null;
59 /** RFC 3339. */
60 createdAt: string;
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace61 /** The workspace the line belongs to, which tells an enterprise's lines apart. */
62 workspace?: string | null;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look63 /** For usage: what the plan's included usage paid of it. `amountMicros` is what is left to pay. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put64 creditMicros?: number;
65 /** For usage: what the workspace's trial credit paid of it. */
66 trialMicros?: number;
67 /** For usage: what g1t's open-source pool paid of it. */
68 ossMicros?: number;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look69 /** For usage: what g1t covered itself, such as a trial's last run past its credit. */
70 givenMicros?: number;
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging71 /** For usage: what the account's discount took off its price. */
72 discountMicros?: number;
73 /** For a credit from g1t, and for what of one expired or was revoked: its kind. */
74 creditKind?: CreditKind;
Agents as a team: lifecycle, merge queue, billing and a new shell75};
76
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging77/**
78 * Why g1t gave a workspace credit. Promotional (a welcome, a referral) and
79 * goodwill (an apology) are given away when spent; a refund gives back
80 * money already paid, and never expires.
81 */
82export type CreditKind = "promotional" | "goodwill" | "refund" | "purchased";
83
84/** One credit g1t gave, with what of it was used: spent before anything paid in advance, the soonest-expiring first. */
85export type CreditGrant = {
86 /** `crd_…`, the grant's ledger reference. */
87 id: string;
88 workspace: string;
89 kind: CreditKind;
90 amountMicros: number;
91 usedMicros: number;
92 /** What can still be spent: nothing once it expired or was revoked. */
93 leftMicros: number;
94 note: string;
95 /** A refund: what it refunds, and the day of it. */
96 refundFor?: string | null;
97 refundDay?: string | null;
98 /** RFC 3339; null never expires. */
99 expiresAt: string | null;
100 createdBy: string;
101 createdAt: string;
102 state: "open" | "used" | "expired" | "revoked";
103 closedAt?: string | null;
104 closedNote?: string | null;
105 closedBy?: string | null;
106 /** What expiring or revoking took off the balance. */
107 closedMicros?: number;
108 /** What it pays for: all usage, or models only (spent first). */
109 scope?: "all" | "models";
110 /** Where it came from. */
Usage, Billing settings and prepaid AI credit; fixes from the UX audit111 source?: "staff" | "purchase" | "promo_code" | "upgrade";
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging112};
113
114/** A workspace's credits from g1t, newest first. */
115export type Credits = { grants: CreditGrant[]; leftMicros: number };
116
117/** One month's credits of one kind: given, spent that month, and taken back unused. */
118export type CreditMonth = {
119 month: string;
120 kind: CreditKind;
121 givenMicros: number;
122 grants: number;
123 usedMicros: number;
124 expiredMicros: number;
125 revokedMicros: number;
126};
127
128/** Every credit g1t gave (at most 200, filtered), the last 12 months by kind, and who gave them. */
129export type AdminCredits = { grants: CreditGrant[]; months: CreditMonth[]; staff: string[] };
130
131/** What a credit from sudo is, past its amount and note. */
132export type CreditOptions = {
133 kind: CreditKind;
134 /** RFC 3339; never for a refund. */
135 expiresAt?: string | null;
136 /** A refund: what it is for, and the day refunded (`YYYY-MM-DD`). */
137 refundFor?: string | null;
138 refundDay?: string | null;
139};
140
Agents as a team: lifecycle, merge queue, billing and a new shell141/** What lets a sandbox, and nothing else, report what its run cost. */
142export type RunTicket = { runId: string; token: string };
143
144/**
145 * What agents cost, charged to the workspace they worked for. A workspace
146 * buys credit; each run deducts its cost plus g1t's margin; with no credit,
147 * no agent starts.
148 */
A free allowance on g1t's models, so anyone can try its agents149/**
150 * The free allowance on g1t's hosted models for a workspace not otherwise
151 * open to them: a few dollars of model cost each, out of one pool, until a
152 * date. Mirrors `Trial` in `crates/contracts/src/billing.rs`.
153 */
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging154/**
155 * How an account is charged. Standard unless g1t set otherwise in sudo:
156 * custom terms are a discount (0 to 100%), a ceiling, or both. A 100%
157 * discount charges nothing and shows the usage at its price. `comped` is
158 * from before discounts and reads as 100%; billing no longer writes it.
159 */
Billing accounts, terms and enterprises; g1t is no longer free160export type Terms = {
161 kind: "standard" | "comped" | "custom";
162 discountPercent: number;
163 ceilingMicros: number | null;
164 note: string;
165 until: string | null;
166 setBy: string | null;
167 setAt: string | null;
168};
169
170/**
171 * Who pays: a workspace's own account, or an enterprise's, which pays for
172 * several workspaces with one bill and one limit.
173 */
174export type PayingAccount = {
175 id: string;
176 kind: "workspace" | "enterprise";
177 name: string;
178 terms: Terms;
179 workspaces: string[];
Stripe webhooks, enterprise invoices, and sudo for both180 /** Where an enterprise's invoices go. */
181 billingEmail?: string | null;
182 /** An enterprise's invoices, newest first. */
183 invoices?: EnterpriseInvoice[];
Billing accounts, terms and enterprises; g1t is no longer free184 createdAt: string;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put185 /** What g1t staff set for the account beyond its terms. */
186 allowances?: Allowances;
187};
188
189/** Set per account by g1t staff in sudo, on top of its terms. */
190export type Allowances = {
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look191 /** The g1t plan without its monthly price; usage is charged as usual. Comped accounts have it anyway. */
192 plan: boolean;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put193 /** Each public repository's monthly cap on g1t's open-source pool; null for the default. */
194 ossRepoMicros: number | null;
195 /** Each workspace's trial credit, outside the monthly pool; null for the default. */
196 trialMicros: number | null;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look197 /** Agents at once, in place of the plan's (2 in the first month or on the trial, then 10); null for the default. */
198 maxConcurrentAgents?: number | null;
199 /** One run's spend cap, in place of the owners' and the default $2; null for none. */
200 runCapMicros?: number | null;
201 /** What one issue's agents may spend in all, in place of the owners' and the default $10; null for none. */
202 issueCapMicros?: number | null;
Audit logs are kept by plan: a week on free, 90 days on the plan, and what staff set for an account in sudo203 /** Days of audit log its workspaces keep, in place of the plan's (7 free, 90 on the plan), longer or shorter; null for the plan's. */
204 auditRetentionDays?: number | null;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look205 /** A hold on new compute, with why; null for none. */
206 hold?: string | null;
Billing accounts, terms and enterprises; g1t is no longer free207};
208
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look209// --- Entitlements, and compute started under a reservation ------------------
210//
211// Every service that starts compute asks billing first:
212// 1. `entitlements(workspace)`: what it may do at all, its caps, and whether compute is paused.
213// 2. `reserve(...)`: holds the estimate against what may pay for it, so starts at the same moment
214// cannot overshoot together. Answers who pays first, or refuses with a stable code
215// (`not_paid`, `trial_used`, `limit`, `paused`, `oss_pool_empty`) and a message for the owner.
216// 3. `settle(reservationId, actualMicros)`: releases the hold. The charge goes on the ledger the usual way.
217// A reservation never settled lapses after `RESERVATION_HOURS`.
218
219/** A reservation that is never settled stops holding after this long. */
220export const RESERVATION_HOURS = 3;
221/** What a ceiling reads as when there is none (g1t's own workspaces). */
222export const UNLIMITED_MICROS = 1_000_000_000_000_000;
223
224/** What a workspace pays g1t on, as far as compute is concerned. Mirrors `PlanKind`. */
225export type PlanKind = "free" | "paid" | "internal" | "enterprise";
226
227// `ComputeKind` (what compute is for), `PaidBy` (who pays first: credit, trial, oss, on_demand) and
228// `Reservation` are in `./compute`, with the gate that calls `reserve` and `settle`.
229
230/** One level reached: 50, 75, 90 or 100 percent. */
231export type UsageAlert = {
232 /** `included` (the plan's included usage), `spend_limit` or `ceiling`. */
233 meter: "included" | "spend_limit" | "ceiling" | string;
234 level: number;
235 usedMicros: number;
236 limitMicros: number;
237 message: string;
238};
239
240/** An hour's spend well above the workspace's usual: new compute waits for an owner. */
241export type Spike = {
242 id: string;
243 /** `open` (waiting), `continued` (keep going) or `stopped`. */
244 status: "open" | "continued" | "stopped" | string;
245 hourMicros: number;
246 averageMicros: number;
247 detectedAt: string;
248 decidedBy?: string | null;
249 decidedAt?: string | null;
250 /** While continued: until when, unless spend doubles again first. */
251 until?: string | null;
252};
253
254/** What a workspace may do now. Mirrors `Entitlements` in `crates/contracts/src/billing.rs`. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put255export type Entitlements = {
256 workspace: string;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look257 plan: PlanKind;
258 /** May start sandboxes, models, deployments and semantic search at all: paid, internal, enterprise, or free with trial credit left. */
259 compute: boolean;
260 /** The one-time trial credit left; 0 if none or used. */
261 trialMicrosLeft: number;
262 /** A card check has been done; the trial and the open-source pool need it. */
263 trialVerified: boolean;
264 /** A paid workspace still in its first billing cycle. */
265 firstMonth: boolean;
266 /** 2 in the first month or on the trial, 10 after; staff can override it. */
267 maxConcurrentAgents: number;
268 /** 60 in the first month or on the trial; otherwise the guardrails' own caps. */
269 maxRunMinutes: number;
270 /** One run's spend cap, $2 by default; staff can override it. */
271 runCapMicros: number;
272 /** Agent spend on one issue in all, $10 by default. */
273 issueCapMicros: number;
274 /** g1t's ceiling on usage not yet paid for; `UNLIMITED_MICROS` for g1t's own; 0 for free. */
275 ceilingMicros: number;
276 /** Usage not yet paid for this month, prepayment taken off. */
277 exposureMicros: number;
278 /** Why new compute is paused, for the owner; null when it is not. */
279 paused: string | null;
280 /** What open reservations hold now. */
281 heldMicros?: number;
282 /** Paid in advance and not used yet. */
283 prepaidMicros?: number;
284 /** The plan's included usage each month, and what of it is used. */
285 includedMicros?: number;
286 includedUsedMicros?: number;
Audit logs are kept by plan: a week on free, 90 days on the plan, and what staff set for an account in sudo287 /** How far back the audit log can be read and exported, and what is kept: the plan's days, or what g1t staff set for the account. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put288 auditRetentionDays: number;
Audit logs are kept by plan: a week on free, 90 days on the plan, and what staff set for an account in sudo289 /** Whether `auditRetentionDays` is what staff set for the account rather than the plan's. */
290 auditRetentionCustom?: boolean;
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas291 /** Private repository storage free for every workspace: past it, the plan pays and a free workspace's pushes stop. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put292 freePrivateStorageBytes: number;
293 /** The last daily measure of the workspace's private repositories (a lower bound). */
294 privateStorageBytes: number;
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member295 /** On a paid plan: package storage past the free amounts is charged, never refused. */
296 hasPlan?: boolean;
297 /** Package storage free for every workspace (public, and private): past it a free workspace's pushes are refused. */
298 packagePublicFreeBytes?: number;
299 packagePrivateFreeBytes?: number;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put300 /** What g1t's open-source pool paid for the workspace this month. */
301 ossPaidMicros: number;
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas302 /** Deploy build time this month, every second of it metered. */
303 buildSecondsUsed?: number;
304 /** Git operations this month, and how many are free for every workspace. */
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look305 gitOperations?: number;
306 gitOperationsIncluded?: number;
307 /** The smallest amount a card is charged when a month closes. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put308 minChargeMicros: number;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look309 /** A spend spike waiting for an owner, or decided. */
310 spike?: Spike | null;
311 /** Where usage stands against what is included and the limits, from 50%. */
312 alerts?: UsageAlert[];
313};
314
315/** A hold on a start's estimated cost, as billing answers it (`Reservation` in `./compute`, and more). */
316export type ReservationHeld = Reservation & {
317 /** What is held, at cost; may be less than the estimate for a free workspace's last bit of trial. */
318 heldMicros?: number;
319 /** When the hold lapses if never settled. */
320 expiresAt?: string;
321};
322
323/** A request to g1t: a higher limit, or help with usage past what was meant. */
324export type LimitRequest = {
325 id: string;
326 workspace: string;
327 kind: "limit" | "overage" | string;
328 amountMicros: number;
329 reason: string;
330 expectedMonthlyMicros: number;
331 status: "open" | "approved" | "declined" | string;
332 decidedMicros?: number | null;
333 decidedBy?: string | null;
334 /** The answer, as the owner sees it. */
335 answer?: string | null;
336 createdBy: string;
337 createdAt: string;
338 decidedAt?: string | null;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put339};
340
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look341/** What staff see beside a request. */
342export type WorkspaceHistory = {
343 plan: PlanKind | null;
344 months: MonthFigures[];
345 paidClearedMicros: number;
346 payments: number;
347 disputes: number;
348 declines: number;
349 firstSeen: string | null;
350 ceilingMicros: number | null;
351 maxCeilingMicros: number | null;
352 spendLimitMicros: number | null;
353 lastHourMicros: number;
354 averageHourMicros: number;
355 lastDayMicros: number;
356};
357
358export type LimitRequestReview = { request: LimitRequest; history: WorkspaceHistory };
359
360/** What a one-time goodwill credit comes to: the margin on the overage, always, plus its cost up to the cap. */
361export type Goodwill = {
362 overageMicros: number;
363 marginMicros: number;
364 costMicros: number;
365 creditMicros: number;
366 absorbedMicros: number;
367};
368
369/** A workspace whose month went well past its usual, or hit a spike. */
370export type Overage = {
371 workspace: string;
372 plan: PlanKind;
373 typicalMonthMicros: number;
374 thisMonthMicros: number;
375 costMicros: number;
376 marginMicros: number;
377 spike: Spike | null;
378 topEntries: LedgerEntry[];
379 goodwill: Goodwill;
380 goodwillAvailable: boolean;
381 lastGoodwillAt: string | null;
382 request: LimitRequest | null;
383};
384
385/** One workspace's recent pace. */
386export type Velocity = {
387 workspace: string;
388 plan: PlanKind;
389 lastHourMicros: number;
390 averageHourMicros: number;
391 lastDayMicros: number;
392 thisMonthMicros: number;
393 ratio: number;
394 spike: Spike | null;
395 firstSeen: string | null;
396};
397
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put398/** g1t's capped budgets for free usage this month. */
399export type Pools = {
400 month: string;
401 trialGrantedMicros: number;
402 trialPoolMicros: number;
403 trialGrants: number;
404 ossUsedMicros: number;
405 ossPoolMicros: number;
406 ossRepoMicros: number;
407};
408
Billing accounts, terms and enterprises; g1t is no longer free409export type AccountSummary = {
410 account: PayingAccount;
411 limit: Limit;
412 chargedMicros: number;
413 costMicros: number;
414 paidMicros: number;
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace415 /** The same figures for each of the account's workspaces that has any. */
416 byWorkspace: WorkspaceFigures[];
Two limits, real invoices, trust that grows by itself, sales signals417 /** The last six months, oldest first. */
418 months?: MonthFigures[];
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace419};
420
421/** One workspace's share of an `AccountSummary`. */
422export type WorkspaceFigures = { workspace: string; chargedMicros: number; costMicros: number; paidMicros: number };
423
Stripe webhooks, enterprise invoices, and sudo for both424export type StripeStatus = {
425 /** `test` or `live`, from the key; `off` without one. */
426 mode: "test" | "live" | "off" | string;
Stripe's webhook secret is a Worker secret, STRIPE_WEBHOOK_SECRET, from a destination made in Stripe's dashboard427 /** Whether `STRIPE_WEBHOOK_SECRET` is set, so events can be checked. */
428 secretSet: boolean;
429 /** The destination at billing's address in Stripe, as Stripe has it. */
430 webhook: { url: string; endpointId: string; status: "enabled" | "disabled" | string; events: string[]; createdAt: string } | null;
431 /** Events billing handles that the destination does not send. */
432 missingEvents: string[];
Stripe webhooks, enterprise invoices, and sudo for both433 recentEvents: { id: string; kind: string; outcome: string; receivedAt: string }[];
434 error: string | null;
435};
436
437/** An enterprise's invoice: one line per workspace, paid on Stripe's page. */
438export type EnterpriseInvoice = {
439 invoiceId: string;
440 hostedUrl: string | null;
441 amountMicros: number;
442 status: "open" | "paid" | "overdue" | "void" | string;
443 period: string;
444 lines: { workspace: string; amountMicros: number }[];
445 createdAt: string;
446};
447
Two limits, real invoices, trust that grows by itself, sales signals448/** A workspace's invoice: monthly, or when charged near its limit. Itemised, in Stripe's billing page. */
449export type WorkspaceInvoice = {
450 invoiceId: string;
451 workspace: string;
452 reason: "month" | "threshold" | string;
453 period: string;
454 amountMicros: number;
455 status: "paid" | "open" | "failed" | "void" | string;
456 hostedUrl: string | null;
457 pdfUrl: string | null;
458 lines: { description: string; amountMicros: number }[];
459 createdAt: string;
Merge Stripe Tax, the card fee on card payments, and one free workspace per person460 /** The card processing fee on top of `amountMicros` when charged to a card, and the tax Stripe added once known. */
461 feeMicros?: number;
462 taxMicros?: number;
Two limits, real invoices, trust that grows by itself, sales signals463};
464
The statement is a month at a time, a line per kind of charge465/** A month of the ledger, grouped by day or project, a line per kind of charge. */
466export type Statement = {
467 month: string;
468 months: string[];
469 groups: {
470 key: string;
471 label: string;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look472 /** `coveredMicros`: what the plan's included usage, the trial, the open-source pool or g1t paid, not in `chargedMicros`. */
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging473 /** `priceMicros`: usage at its price; `discountMicros`: what the account's discount took off it. */
474 lines: {
475 kind: string;
476 count: number;
477 chargedMicros: number;
478 costMicros: number;
479 coveredMicros?: number;
480 priceMicros?: number;
481 discountMicros?: number;
Merge Stripe Tax, the card fee on card payments, and one free workspace per person482 /** On `Tax` and `Card processing fees` lines: what was paid with payments on top of what reached the balance. Never charged. */
483 passedMicros?: number;
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging484 }[];
The statement is a month at a time, a line per kind of charge485 chargedMicros: number;
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging486 priceMicros?: number;
487 discountMicros?: number;
The statement is a month at a time, a line per kind of charge488 }[];
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put489 totals: {
490 chargedMicros: number;
491 paidMicros: number;
492 costMicros: number;
493 entries: number;
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging494 /** Usage at price, and what the discount took off: charged is the price less the discount and what paid for it. */
495 priceMicros?: number;
496 discountMicros?: number;
497 /** The account's discount now, in percent; absent without one. */
498 discountPercent?: number | null;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put499 /** What paid for usage before it was charged, such as "Paid by g1t's open-source pool". */
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look500 covered?: { source: "included" | "trial" | "oss_pool" | "given" | string; label: string; micros: number }[];
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put501 /** Owed when the month closed but under the minimum charge: on the next invoice. */
502 carriedMicros?: number;
Merge Stripe Tax, the card fee on card payments, and one free workspace per person503 /** Tax and card processing fees paid with the month's payments, on top of `paidMicros`. */
504 taxMicros?: number;
505 cardFeeMicros?: number;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put506 };
The statement is a month at a time, a line per kind of charge507};
508
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look509export type MonthFigures = {
510 month: string;
511 /** Usage charged, after what paid for it first. */
512 chargedMicros: number;
513 /** What usage cost g1t: never a workspace's own model provider. */
514 costMicros: number;
515 paidMicros: number;
516 /** The plan's monthly price, paid. */
517 plansMicros?: number;
518 /** What g1t gave at price (internal use, trials, the open-source pool, goodwill, covered). Not margin. */
519 givenMicros?: number;
520};
521
522/** What g1t gave this month from one source. */
523export type GivenFigures = { source: "internal" | "trial" | "oss_pool" | "goodwill" | "covered" | string; label: string; micros: number; costMicros: number };
524
525/** One internal workspace's use this month, and why it is not charged. */
526export type InternalUse = { workspace: string; reason: string; costMicros: number; entries: number };
Two limits, real invoices, trust that grows by itself, sales signals527
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily528export type SignalKind = "at_limit" | "near_ceiling" | "declined" | "growing" | "established" | "first_payment" | "high_spend" | "cost_over_revenue";
Two limits, real invoices, trust that grows by itself, sales signals529
530/** Why a workspace is worth reaching out to. */
531export type Signal = {
532 workspace: string;
533 kind: SignalKind;
534 detail: string;
535 valueMicros: number;
536 stage: string | null;
537 owner: string | null;
Billing lists every invoice and every staff change; signals carry follow-ups538 nextStep?: string | null;
539 /** When the next step is due, YYYY-MM-DD. */
540 nextAt?: string | null;
541};
542
543/** One invoice g1t has sent, a workspace's or an enterprise's. */
544export type InvoiceSummary = {
545 invoiceId: string;
546 kind: "workspace" | "enterprise";
547 account: string;
548 name: string;
549 reason: string;
550 period: string;
551 amountMicros: number;
552 status: string;
553 hostedUrl: string | null;
554 createdAt: string;
555 paidAt: string | null;
Two limits, real invoices, trust that grows by itself, sales signals556};
557
558export type SalesStage = "none" | "lead" | "contacted" | "negotiating" | "won" | "lost" | "churn_risk";
559
560export type SalesRecord = {
561 workspace: string;
562 stage: SalesStage | string;
563 owner: string | null;
564 nextStep: string | null;
565 nextAt: string | null;
566 notes: { id: string; text: string; by: string; createdAt: string }[];
567 updatedAt: string | null;
568};
569
570export type Overview = {
571 month: string;
572 months: MonthFigures[];
573 byKind: { kind: string; chargedMicros: number; costMicros: number }[];
574 payingWorkspaces: number;
575 stopped: number;
576 nearCeiling: number;
577 declined: number;
578 openInvoicesMicros: number;
579 followUpsDue: number;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put580 /** g1t's capped budgets for free usage, this month. */
581 pools?: Pools | null;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look582 /** Usage charged plus the plan's price paid, this month. */
583 revenueMicros?: number;
584 activePlans?: number;
585 planMrrMicros?: number;
586 /** What g1t gave this month, by source, apart from its margin. */
587 given?: GivenFigures[];
588 /** g1t's own and Flagon's workspaces: what their use cost, and why they are not charged. */
589 internal?: InternalUse[];
590 openRequests?: number;
591 overages?: number;
592 openSpikes?: number;
Two limits, real invoices, trust that grows by itself, sales signals593};
594
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace595/** A customer's Stripe billing page, for staff to send them. */
596export type BillingLink = {
597 /** One-time and short-lived, signed in already. */
598 portalUrl: string;
599 /** The page's sign-in, which does not expire: the customer signs in by email. */
600 loginUrl: string | null;
601 customerEmail: string | null;
602 expiresNote: string;
Billing accounts, terms and enterprises; g1t is no longer free603};
604
605export type AdminAction = { id: string; account: string; action: string; detail: string; by: string; createdAt: string };
606
607export type AccountDetail = {
608 summary: AccountSummary;
609 workspaces: Limit[];
610 ledger: LedgerEntry[];
611 audit: AdminAction[];
612};
613
614/** Staff-only billing, for sudo.g1t.sh. Every change names who made it. */
615export interface BillingAdminApi {
616 accounts(query?: string): Promise<AccountSummary[]>;
617 account(id: string): Promise<Result<AccountDetail>>;
618 setTerms(id: string, terms: Terms, by: string): Promise<Result<PayingAccount>>;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put619 /** Team on or off without charge, and the account's share of the pools. Needs a note. */
620 setAllowances(id: string, allowances: Allowances, note: string, by: string): Promise<Result<PayingAccount>>;
Billing accounts, terms and enterprises; g1t is no longer free621 createEnterprise(name: string, workspaces: string[], by: string): Promise<Result<PayingAccount>>;
622 attach(workspace: string, account: string | null, by: string): Promise<Result<PayingAccount>>;
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging623 /** Credit for a workspace: promotional, goodwill or a refund; the owners are emailed. */
624 credit(workspace: string, amountMicros: number, note: string, by: string, options?: CreditOptions): Promise<Result<LedgerEntry>>;
625 /** Every credit g1t gave, filtered, with each month's totals by kind. */
626 credits(filter?: { workspace?: string | null; kind?: CreditKind | null; month?: string | null; by?: string | null }): Promise<AdminCredits>;
627 /** What is left of a credit, taken back, with why. */
628 revokeCredit(id: string, note: string, by: string): Promise<Result<CreditGrant>>;
sudo: reset a test workspace's billing so it starts again as a new customer; refused on a live Stripe key, for comped workspaces and for an enterprise's629 /** A test workspace's billing wiped, to start again as a new customer. Only on Stripe's test key; never comped or enterprise. Logged. */
630 resetBilling(workspace: string, confirm: string, note: string, by: string): Promise<Result<BillingReset>>;
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace631 /** The workspace's Stripe billing page, to send to the customer. Logged. */
632 billingLink(workspace: string, by: string): Promise<Result<BillingLink>>;
Stripe webhooks, enterprise invoices, and sudo for both633 /** Where billing stands with Stripe; with `setup`, registers the webhook first. */
Stripe's webhook secret is a Worker secret, STRIPE_WEBHOOK_SECRET, from a destination made in Stripe's dashboard634 /** Stripe's state for billing; `fix` enables the destination and adds missing events first. */
635 stripe(fix?: boolean, by?: string): Promise<StripeStatus>;
Stripe webhooks, enterprise invoices, and sudo for both636 /** Where an enterprise's invoices go; makes its Stripe customer. */
637 enterpriseBilling(id: string, email: string, by: string): Promise<Result<PayingAccount>>;
Merge Stripe Tax, the card fee on card payments, and one free workspace per person638 /** The enterprise's billing address and tax ID, on its Stripe customer: Stripe Tax works its invoices out from them. */
639 enterpriseAddress(id: string, address: PostalAddress, taxIdType: string | null, taxId: string | null, by: string): Promise<Result<boolean>>;
Stripe webhooks, enterprise invoices, and sudo for both640 /** Sends an enterprise its invoice now, for what its workspaces owe. */
641 invoiceEnterprise(id: string, by: string): Promise<Result<EnterpriseInvoice>>;
642 /** Exactly these workspaces' accounts, such as one page of the list. */
643 accountsFor(workspaces: string[]): Promise<AccountSummary[]>;
Two limits, real invoices, trust that grows by itself, sales signals644 /** Every workspace worth reaching out to, most urgent first. */
645 signals(): Promise<Signal[]>;
646 /** The business at a glance. */
647 overview(): Promise<Overview>;
648 /** A workspace's sales record. */
649 sales(workspace: string): Promise<SalesRecord>;
650 setSales(workspace: string, record: { stage: string; owner?: string | null; nextStep?: string | null; nextAt?: string | null }, by: string): Promise<Result<SalesRecord>>;
651 addNote(workspace: string, text: string, by: string): Promise<Result<SalesRecord>>;
652 /** A workspace's invoices from g1t, for staff. */
653 workspaceInvoices(workspace: string): Promise<WorkspaceInvoice[]>;
Billing lists every invoice and every staff change; signals carry follow-ups654 /** Every invoice g1t has sent, newest first. */
655 allInvoices(filter?: { status?: string; month?: string }): Promise<InvoiceSummary[]>;
656 /** Every change made in sudo and by Stripe, newest first, 100 at a time. */
657 audit(filter?: { by?: string; action?: string; before?: string }): Promise<AdminAction[]>;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look658 /** Limit and overage requests, with each workspace's history; `open` by default. */
659 limitRequests(status?: "open" | "approved" | "declined" | "all"): Promise<LimitRequestReview[]>;
660 /** Approve (at the amount asked, or another) or decline; the owner is told in the app and by email. */
661 decideLimitRequest(id: string, decision: "approve" | "decline", amountMicros: number | null, note: string, by: string): Promise<Result<LimitRequest>>;
662 /** The Overages queue. */
663 overages(): Promise<Overage[]>;
664 /** A goodwill credit; no amount is the one-click credit. Larger, or a second in 12 months, needs a reason. */
665 goodwill(workspace: string, amountMicros: number | null, reason: string, by: string, day?: string | null): Promise<Result<LedgerEntry>>;
666 /** Workspaces spending in the last day, fastest first. */
667 velocity(): Promise<Velocity[]>;
668 /** Money that reached g1t outside the card pages, such as a bank transfer: entered as a payment. */
669 recordPayment(workspace: string, amountMicros: number, reference: string, note: string, by: string): Promise<Result<LedgerEntry>>;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily670 /** Costs & margin: Cloudflare's bill against what g1t charged, over the last `days` (7 to 90, 30 by default). */
671 costs(days?: number): Promise<CostsReport>;
672 /** The open margin alerts, for the banner on every page. */
673 costAlerts(): Promise<MarginAlert[]>;
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays674 /** g1t's own spend against its caps: the daily breaker and comped budgets. */
675 spendCaps(): Promise<SpendCaps>;
676 /** Lets hosted-model runs start again for the rest of today (UTC); needs a note. */
677 liftBreaker(note: string, by: string): Promise<Result<SpendCaps>>;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily678 /** Approve or reject a price proposal; a rejection needs a note. An approved rise waits out the notice period. */
679 decideProposal(id: string, decision: "approve" | "reject", note: string, by: string): Promise<Result<PriceProposal>>;
680 setCostSettings(settings: CostSettings, by: string): Promise<Result<CostSettings>>;
681 setCostMapping(mapping: CostMappingInput, by: string): Promise<Result<CostMapping>>;
682 /** Reads Cloudflare's bill and reconciles now, as the daily run does. */
683 runCosts(by: string): Promise<Result<CostsRun>>;
Billing accounts, terms and enterprises; g1t is no longer free684}
685
Usage limits: unpaid usage can only go so far686/** How much a workspace has earned g1t's trust with money. */
Two limits, real invoices, trust that grows by itself, sales signals687export type Trust = "new" | "paid" | "established" | "reviewed" | "internal";
Usage limits: unpaid usage can only go so far688
689/**
690 * How far a workspace's unpaid usage has gone this month, and where its
691 * work stops: past `ceilingMicros`, no new sandboxes, builds or app
692 * requests. Usage counts at its cost to g1t or its charge, whichever is
693 * more, so it counts while g1t is free too.
694 */
695export type Limit = {
696 workspace: string;
Billing accounts, terms and enterprises; g1t is no longer free697 /** The account that pays: the workspace's own (`ws_<slug>`), or its enterprise's. */
698 account: string;
699 accountName: string;
Usage limits: unpaid usage can only go so far700 trust: Trust;
701 exposureMicros: number;
702 /** The lower of g1t's ceiling and the owner's spend limit; null for g1t's own. */
703 ceilingMicros: number | null;
704 trustCeilingMicros: number | null;
705 spendLimitMicros: number | null;
706 state: "ok" | "warning" | "stopped";
707 message: string | null;
Two limits, real invoices, trust that grows by itself, sales signals708 /** Charged this month: what the spend limit is measured against. */
709 spentMicros?: number;
710 /** True while the owners have not chosen a limit, so the automatic one applies: $200, or twice last month's spend. */
711 defaultSpendLimit?: boolean;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look712 /** The most owners may set their own limit to without asking: the highest ceiling ever, plus what is prepaid. */
Two limits, real invoices, trust that grows by itself, sales signals713 availableMicros?: number | null;
714 /** How the ceiling grows from here, in a sentence. */
715 growth?: string | null;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look716 /** Paid in advance and not used yet; raises what can be used before work stops by as much. */
717 prepaidMicros?: number;
718 /** The highest ceiling the workspace has had. */
719 maxCeilingMicros?: number | null;
720 /** The most owners may raise the limit to themselves, once: twice the highest ceiling. Null once used. */
721 raiseOnceMicros?: number | null;
722 /** When the one-time raise was used. */
723 raisedAt?: string | null;
724 /** A paid workspace's first billing cycle, on the starting ceiling. */
725 firstMonth?: boolean;
Usage, Billing settings and prepaid AI credit; fixes from the UX audit726 /** The budget's alerts, in percent of the spend limit: some of 50, 75, 90 and 100. */
727 alertLevels?: number[];
728 /** Whether usage pauses at the spend limit (the default); off, it only alerts. */
729 pauseAtLimit?: boolean;
730 /** An HTTPS address told of each budget alert. */
731 budgetWebhook?: string | null;
Usage limits: unpaid usage can only go so far732};
733
Prices keep themselves current with what g1t pays734/** One metered unit: what it costs g1t and what it is sold at; the price follows the cost. */
735export type Price = {
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put736 meter:
737 | "sandbox_second"
738 | "build_second"
739 | "app_requests"
740 | "app_cpu"
741 | "app_month"
742 | "custom_domain_month"
743 | "private_storage"
744 | "embedding_tokens"
745 | "scan_cpu"
746 | "scan_rows"
747 | string;
Prices keep themselves current with what g1t pays748 title: string;
749 unit: string;
750 costMicros: number;
751 markupPercent: number;
752 priceMicros: number;
753 /** `list`: Cloudflare's published price. `cloudflare`: measured from Cloudflare's bill. */
754 source: "list" | "cloudflare" | string;
755 checkedAt: string | null;
756 updatedAt: string;
757};
758
759export type PriceChange = {
760 meter: string;
761 oldCostMicros: number;
762 newCostMicros: number;
763 markupPercent: number;
Prices are what g1t pays plus 20%, from the first second764 /** The markup before, when the change was to the markup rather than the cost. */
765 oldMarkupPercent?: number;
Prices keep themselves current with what g1t pays766 reason: string;
767 createdAt: string;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily768 /** When a change still to come takes effect: a rise is announced before it is charged. */
769 effectiveAt?: string;
Prices keep themselves current with what g1t pays770};
771
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put772export type PriceBook = {
773 prices: Price[];
774 changes: PriceChange[];
775 modelMarginPercent: number;
776 /** Every plan, as sold now. */
777 plans?: FeaturePlan[];
778 /** What is free, and the capped budgets that pay for it. */
779 free?: FreeTier | null;
780};
Prices keep themselves current with what g1t pays781
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas782/** One kind of meter's usage this month, from `usage_meters`. */
783export type MeterUsage = {
784 /** `agents`, `builds`, `requests`, `domains`, `git_storage` or `search_scans`. */
785 key: string;
786 label: string;
787 /** At price (cost plus 20%, on the account's terms), before what paid for it. */
788 micros: number;
789 /** How much, when it is known: `12 runs`, `41 build minutes`. */
790 quantity?: string | null;
791};
792
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put793/** What g1t gives without a plan; each is paid for by a capped budget. */
794export type FreeTier = {
795 /** Each new workspace's trial credit, once. */
796 trialWorkspaceMicros: number;
797 /** Trial grants each month, in all; new trials wait when it is spent. */
798 trialMonthlyPoolMicros: number;
799 /** g1t's open-source pool each month, and any one repository's share. */
800 ossPoolMicros: number;
801 ossRepoMicros: number;
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas802 /** Private repository storage free for every workspace. Past it, the plan pays; a free workspace's pushes stop. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put803 freePrivateStorageBytes: number;
Audit logs are kept by plan: a week on free, 90 days on the plan, and what staff set for an account in sudo804 /** Days of audit log a free workspace keeps. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put805 auditRetentionDays: number;
Audit logs are kept by plan: a week on free, 90 days on the plan, and what staff set for an account in sudo806 /** Days of audit log the g1t plan keeps, and g1t's own and enterprise workspaces; longer by arrangement. */
807 planAuditRetentionDays?: number;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look808 /** The smallest amount a card is charged when a month closes; less carries over. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put809 minChargeMicros: number;
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas810 /** Git operations free for every workspace each month. Past it, the plan pays; a free workspace is slowed down. */
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look811 gitOperationsIncluded?: number;
812 /** A new paid workspace's ceiling in its first month. */
813 paidStartCeilingMicros?: number;
814 /** The most a one-click goodwill credit can cost g1t. */
815 overageForgiveCostMicros?: number;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put816};
817
818/**
819 * A workspace's trial credit: one grant per workspace, made the first time
820 * it uses something, out of a pool that resets each calendar month. Mirrors
821 * `Trial` in `crates/contracts/src/billing.rs`.
822 */
A free allowance on g1t's models, so anyone can try its agents823export type Trial = {
824 open: boolean;
825 usedMicros: number;
826 limitMicros: number;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put827 /** No longer used: trials do not end on a date. */
A free allowance on g1t's models, so anyone can try its agents828 endsAt: string | null;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put829 /** Why it is closed: `off`, `used` (this workspace's grant is spent) or `pool` (this month's are given out). */
A free allowance on g1t's models, so anyone can try its agents830 reason: "off" | "ended" | "used" | "pool" | null;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put831 /** Whether the workspace has its grant already. */
832 granted?: boolean;
833 /** With `pool`: when new trials start again, the first of next month. */
834 waitsUntil?: string | null;
A free allowance on g1t's models, so anyone can try its agents835};
836
Paid features: a workspace turns on Deployments with a monthly plan837/**
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar838 * What a workspace pays a monthly price for: the g1t plan (`plan`), and the
839 * Security and quality activation (`security`), sold on its own. Deployments
840 * are part of the plan; `has_feature` for `deployments` answers whether the
841 * workspace has the plan. Mirrors `Feature` in `crates/contracts/src/billing.rs`.
Paid features: a workspace turns on Deployments with a monthly plan842 */
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar843export type Feature = "plan" | "deployments" | "security";
Paid features: a workspace turns on Deployments with a monthly plan844
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas845/**
846 * What deployments cost g1t, in millionths of a dollar: fallbacks for when
847 * billing's price book cannot be read. Not an allowance: on the plan every
848 * unit is metered from the first, at cost plus 20%, and drawn from the
849 * plan's included usage first. Projects, previews and the apps behind them
850 * are not metered at all. Mirrors `deployment_costs`.
851 */
852export const DEPLOYMENT_COSTS = {
Paid features: a workspace turns on Deployments with a monthly plan853 microsPerMillionRequests: 300_000,
854 microsPerMillionCpuMs: 20_000,
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas855 /** One second of a build's sandbox: a fallback; billing charges the price book's `build_second`. */
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look856 microsPerBuildSecond: 15,
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas857 /** One custom domain for a month. */
Agents and memory, checks and conflicts, profiles, slug renames, custom domains858 microsPerDomainMonth: 100_000,
Paid features: a workspace turns on Deployments with a monthly plan859} as const;
860
861export type FeaturePlan = {
862 feature: Feature;
863 title: string;
Merge Stripe Tax, the card fee on card payments, and one free workspace per person864 /** Charged every month while the plan is on, in cents, excluding tax. */
Paid features: a workspace turns on Deployments with a monthly plan865 monthlyCents: number;
Merge Stripe Tax, the card fee on card payments, and one free workspace per person866 /** The card processing fee on top each month, in cents (0 when off), excluding tax. */
867 cardFeeCents?: number;
Paid features: a workspace turns on Deployments with a monthly plan868 /** What the price includes, one line each. */
869 includes: string[];
870 /** How usage past the allowance is charged. */
871 overage: string;
872};
873
874export type SubscriptionStatus = "active" | "canceling" | "past_due" | "canceled";
875
876export type Subscription = {
877 feature: Feature;
878 status: SubscriptionStatus;
879 /** RFC 3339: when the period paid for ends. */
880 periodEnd: string | null;
881 startedBy: string;
882 startedAt: string;
883};
884
885/** A feature as a workspace sees it. */
886export type FeatureState = {
887 plan: FeaturePlan;
888 subscription: Subscription | null;
889 /** Whether the feature works for the workspace now. */
890 on: boolean;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put891 /** On without a plan: comped terms, or given by g1t. Nothing to pay or turn off. */
892 included?: boolean;
Paid features: a workspace turns on Deployments with a monthly plan893};
894
Agents as a team: lifecycle, merge queue, billing and a new shell895export interface BillingApi {
896 status(): Promise<BillingStatus>;
897 /** Members of the workspace only. */
898 account(workspace: string, viewer: Viewer): Promise<Result<BillingAccount>>;
899 /** Newest first. Members of the workspace only. */
900 ledger(workspace: string, viewer: Viewer): Promise<Result<LedgerEntry[]>>;
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging901 /** Credits from g1t, newest first, with what is left of each. Members only. */
902 credits(workspace: string, viewer: Viewer): Promise<Result<Credits>>;
The statement is a month at a time, a line per kind of charge903 /** A month of the ledger, grouped by `day` (default) or `project`. Members only. */
904 statement(workspace: string, viewer: Viewer, month?: string | null, group?: "day" | "project"): Promise<Result<Statement>>;
905 /** One statement line's entries, 50 at a time; `before` is the last id seen. */
906 statementEntries(
907 workspace: string,
908 viewer: Viewer,
909 filter: { month: string; kind: string; day?: string | null; project?: string | null; before?: string | null },
910 ): Promise<Result<LedgerEntry[]>>;
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request911 /** What the workspace's agents cost since `since`, broken down. Members only. */
912 usage(workspace: string, viewer: Viewer, since: string): Promise<Result<Usage>>;
Agents as a team: lifecycle, merge queue, billing and a new shell913 /**
Mission control shows model usage, yours and the workspace's: tokens, cost, active days, cache share, each day, and the mix914 * The model tokens the workspace's runs used, day by day over the last
915 * `days` (42, at most 366), for everyone or for one `person`. Members
916 * only; a member may ask only for themselves, an owner for anyone.
917 */
918 tokenUsage(workspace: string, viewer: User, options?: { person?: string; days?: number }): Promise<Result<TokenUsage>>;
919 /**
920 * What one model answer used, added to its run's count for the day. The
921 * model proxy sends it; for usage views only, as runs are priced from AI
922 * Gateway. False when there was nothing to count.
923 */
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens924 /** What the AI Gateway offers on g1t's key, with prices per million tokens. */
925 gatewayModels(): Promise<GatewayModel[]>;
926 /**
927 * Whether a workspace's next AI Gateway request may go to g1t's models:
928 * fails with `payment_required` and what to do when it is over its spend
929 * limit, out of AI credit, or not on the plan.
930 */
931 gatewayAdmit(workspace: string): Promise<Result<boolean>>;
932 /** Logs one AI Gateway request, and charges it when it used tokens on g1t's models. */
933 recordGateway(record: GatewayRecord): Promise<Result<boolean>>;
934 /** A workspace's recent AI Gateway requests, newest first. Members only. */
935 gatewayRequests(workspace: string, viewer: Viewer, options?: { limit?: number; before?: string | null }): Promise<Result<GatewayRequests>>;
Mission control shows model usage, yours and the workspace's: tokens, cost, active days, cache share, each day, and the mix936 recordTokens(usage: {
937 workspace: string;
938 /** The model session's id, one per run. */
939 session: string;
940 /** The person the run is for, by username. */
941 person?: string | null;
942 model: string;
Merge branch 'model-routing'943 tier?: "small" | "large" | "frontier" | null;
Mission control shows model usage, yours and the workspace's: tokens, cost, active days, cache share, each day, and the mix944 input: number;
945 output: number;
946 cacheRead: number;
947 cacheWrite: number;
948 }): Promise<Result<boolean>>;
949 /**
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look950 * Prepays usage ($25 at least) and returns the page to send the person to:
951 * by card with 3-D Secure, or by bank transfer from $1,000. Owners only.
952 * The payment's id comes back to `returnUrl` as `session`.
Agents as a team: lifecycle, merge queue, billing and a new shell953 */
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look954 checkout(
955 actor: User,
956 workspace: string,
957 amountCents: number,
958 returnUrl: string,
959 method?: "card" | "bank_transfer",
960 ): Promise<Result<{ url: string }>>;
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace961 /**
962 * Stripe's hosted billing page for the workspace: card, invoices, billing
963 * email and address. g1t never handles card numbers. Owners only.
964 */
965 billingPortal(actor: User, workspace: string, returnUrl: string): Promise<Result<{ url: string }>>;
Agents as a team: lifecycle, merge queue, billing and a new shell966 /** Credits a payment once the processor says it was made. Safe to repeat. */
967 confirm(workspace: string, viewer: Viewer, session: string): Promise<Result<BillingAccount>>;
968 /**
969 * Whether a workspace may start an agent now, asked before anything is
970 * opened for it. A failure, with the reason to show, when it has no credit.
971 */
972 canStart(workspace: string): Promise<Result<boolean>>;
A free allowance on g1t's models, so anyone can try its agents973 /** A workspace's free allowance on g1t's hosted models; `exempt` are open to them anyway. */
974 trial(workspace: string, exempt: string[]): Promise<Trial>;
Agents as a team: lifecycle, merge queue, billing and a new shell975 /**
976 * Asks whether a workspace may start an agent and opens the run it will be
977 * charged for. Null when billing is off; a failure when there is no credit.
978 */
Paid features: a workspace turns on Deployments with a monthly plan979 /** Every paid feature and the workspace's plan for each. Members only. */
980 features(workspace: string, viewer: Viewer): Promise<Result<FeatureState[]>>;
981 /**
982 * Starts the card page for a feature's monthly plan. Owners only. The
983 * page's id comes back to `returnUrl` as `session`.
984 */
985 subscribe(actor: User, workspace: string, feature: Feature, returnUrl: string): Promise<Result<{ url: string }>>;
986 /** Turns the feature on once the plan is paid for. Safe to repeat. */
987 confirmSubscription(workspace: string, viewer: Viewer, session: string): Promise<Result<FeatureState>>;
988 /** Ends a plan at the end of its period, or (`resume`) takes that back. Owners only. */
989 cancelSubscription(actor: User, workspace: string, feature: Feature, resume?: boolean): Promise<Result<FeatureState>>;
Merge Stripe Tax, the card fee on card payments, and one free workspace per person990 /** Which of the workspaces are free (on no paid plan); none where payments are not set up. */
991 freeWorkspaces(workspaces: string[]): Promise<string[]>;
Paid features: a workspace turns on Deployments with a monthly plan992 /** Whether a feature works for a workspace now; a failure with the reason when not. */
993 hasFeature(workspace: string, feature: Feature): Promise<Result<boolean>>;
994 /**
995 * Usage past a plan's allowance, charged from credit at cost plus the
996 * margin, once per `reference`. False if it was charged before.
997 */
998 chargeFeature(charge: {
999 workspace: string;
1000 feature: Feature;
1001 costMicros: number;
1002 description: string;
1003 repo?: string | null;
1004 reference: string;
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put1005 /** For a build: how long it ran, so the plan's included build time pays for what it can. */
1006 buildSeconds?: number | null;
Paid features: a workspace turns on Deployments with a monthly plan1007 }): Promise<Result<boolean>>;
Prices keep themselves current with what g1t pays1008 /**
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put1009 * What a source cost g1t so far this month, so the workspace's limit
1010 * counts it now. Replaces the last report. Billing charges `context`
1011 * and `security` itself once the month is over; `deployments` charges
1012 * its own.
Prices keep themselves current with what g1t pays1013 */
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas1014 notePending(
1015 workspace: string,
1016 source: "deployments" | "domains" | "context" | "security",
1017 costMicros: number,
1018 /** How much of it, for the Billing page: `1.2 million requests and 3.4 million CPU ms`. */
1019 detail?: string | null,
1020 ): Promise<boolean>;
1021 /**
1022 * This month's usage, one line per kind of meter, at what it is charged
1023 * before the plan's included usage or a pool paid for it. Members only.
1024 */
1025 usageMeters(workspace: string, viewer: Viewer): Promise<Result<MeterUsage[]>>;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1026 /** What the workspace may do now: its plan, caps, pause, trial, and what the plan gives it. */
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put1027 entitlements(workspace: string): Promise<Entitlements>;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1028 /**
1029 * Holds a start's estimated cost before the work starts. A failure's code says why not:
1030 * `paused`, `limit`, `not_paid`, `trial_used` or `oss_pool_empty`, with a message for the owner.
1031 */
1032 reserve(reservation: {
1033 workspace: string;
1034 repo: RepoPath;
1035 public: boolean;
1036 kind: ComputeKind;
1037 /** The most the work is expected to cost g1t, before the margin. */
1038 estimateMicros: number;
1039 }): Promise<Result<ReservationHeld>>;
1040 /** Releases a reservation's hold with what the work cost g1t, before the margin. Safe to repeat. */
1041 settle(reservationId: string, actualMicros: number): Promise<Result<boolean>>;
1042 /** Stripe's page to save and verify a card (3-D Secure, never charged). Owners only. */
1043 cardCheck(actor: User, workspace: string, returnUrl: string): Promise<Result<{ url: string }>>;
1044 /** Records the card check once Stripe says it passed, and grants the trial if it can. Safe to repeat. */
1045 confirmCardCheck(workspace: string, viewer: Viewer, session: string): Promise<Result<Entitlements>>;
1046 /** An owner asks for a higher limit, or for help with usage past what was meant. */
1047 requestLimit(
1048 actor: User,
1049 workspace: string,
1050 request: { kind: "limit" | "overage"; amountMicros: number; reason: string; expectedMonthlyMicros: number },
1051 ): Promise<Result<LimitRequest>>;
1052 /** The workspace's requests and their answers, newest first. Members only. */
1053 limitRequests(workspace: string, viewer: Viewer): Promise<Result<LimitRequest[]>>;
1054 /**
1055 * The owners' own caps on agents: one run's spend ($0.10 to $100) and one issue's ($1 to $1,000).
1056 * Null goes back to the default ($2 and $10). A cap staff set wins. Owners only.
1057 */
1058 setCaps(actor: User, workspace: string, caps: { runCapMicros: number | null; issueCapMicros: number | null }): Promise<Result<Entitlements>>;
1059 /** An owner's answer to a spend spike: keep going for 24 hours, or stop. */
1060 confirmSpike(actor: User, workspace: string, keepGoing: boolean): Promise<Result<Entitlements>>;
Prices keep themselves current with what g1t pays1061 /** Every metered price and the recent changes. Public. */
1062 prices(): Promise<PriceBook>;
Usage limits: unpaid usage can only go so far1063 /** A workspace's limit, for its members. */
1064 limit(workspace: string, viewer: Viewer): Promise<Result<Limit>>;
1065 /** The same, for the services that enforce it. */
1066 checkLimit(workspace: string): Promise<Result<Limit>>;
Every sandbox is metered by the second1067 /**
Two limits, real invoices, trust that grows by itself, sales signals1068 * The owners' own monthly limit, up to what is available; null goes back
1069 * to the default, and `useFullLimit` uses everything available. Owners only.
1070 */
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1071 setSpendLimit(
1072 actor: User,
1073 workspace: string,
1074 spendLimitMicros: number | null,
1075 useFullLimit?: boolean,
1076 /** Use the one-time raise: up to twice the highest ceiling, once per workspace. */
1077 raiseOnce?: boolean,
1078 ): Promise<Result<Limit>>;
Two limits, real invoices, trust that grows by itself, sales signals1079 /** The workspace's invoices from g1t, newest first. Members only. */
1080 invoices(workspace: string, viewer: Viewer): Promise<Result<WorkspaceInvoice[]>>;
1081 /**
Every sandbox is metered by the second1082 * How long a sandbox ran for a workspace, reported when it stops. Its
Prices are what g1t pays plus 20%, from the first second1083 * cost is recorded and every second is charged, from the first. False if
1084 * `reference` was recorded before.
Every sandbox is metered by the second1085 */
1086 recordSandbox(usage: {
1087 workspace: string;
1088 seconds: number;
1089 description: string;
1090 repo?: string | null;
1091 reference: string;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1092 /** What ran; checks, workflows and the merge queue on public repositories may use the open-source pool. */
1093 kind?: ComputeKind | null;
1094 /** vCPU-seconds used, when the sandbox can tell: the run is priced on its own CPU. */
1095 cpuSeconds?: number | null;
1096 /** The reservation it started under, settled with this cost. */
1097 reservationId?: string | null;
Fast pages, required checks on the branch, self-hosted runners, honest incidents1098 /** It ran on one of the workspace's self-hosted runners: its minutes go on usage at $0. */
1099 selfHosted?: boolean;
1100 /** The machine it ran on, by label (`g1t-4core`); absent, the standard one. */
1101 instance?: string | null;
Every sandbox is metered by the second1102 }): Promise<Result<boolean>>;
Agents as a team: lifecycle, merge queue, billing and a new shell1103 startRun(run: {
1104 workspace: string;
1105 repo: RepoPath;
1106 number: number;
1107 task: string;
1108 model: string;
Integrations: your own model provider, alerts that open issues, tickets agents read1109 /** `workspace` when the run uses the workspace's own model provider. */
1110 billedTo?: "g1t" | "workspace";
Merge branch 'model-routing'1111 /**
1112 * The model session's id: the run is settled at AI Gateway's price by
1113 * it, and on the workspace's own provider its tokens are counted under
1114 * it for the agent rate.
1115 */
Prices keep themselves current with what g1t pays1116 session?: string | null;
Merge branch 'model-routing'1117 /** The tier g1t routed the run to: `small`, `large` or `frontier`. */
1118 tier?: "small" | "large" | "frontier" | null;
Agents as a team: lifecycle, merge queue, billing and a new shell1119 }): Promise<Result<RunTicket | null>>;
Usage, Billing settings and prepaid AI credit; fixes from the UX audit1120 /** Usage over a range of days (`YYYY-MM-DD`, both included), at price, by product, meter, project and day. Members only. */
1121 usageReport(
1122 workspace: string,
1123 viewer: Viewer,
1124 range: { from: string; until: string; products?: string[]; projects?: string[] },
1125 ): Promise<Result<UsageReport>>;
1126 /** The workspace's prepaid AI credit, auto-reload and prices. Members only. */
1127 aiCredit(workspace: string, viewer: Viewer): Promise<Result<AiCredit>>;
1128 /** Stripe's page to buy AI credit ( to ,000, the card fee on its own line). Owners only. The page's id comes back to `returnUrl` as `ai_credit`. */
1129 buyAiCredit(actor: User, workspace: string, amountCents: number, returnUrl: string): Promise<Result<{ url: string }>>;
1130 /** Credits a purchase once Stripe says it was paid, once. Safe to repeat. */
1131 confirmAiCredit(workspace: string, viewer: Viewer, session: string): Promise<Result<AiCredit>>;
1132 /** Auto-reload's settings. Owners only. */
1133 setAiReload(
1134 actor: User,
1135 workspace: string,
1136 reload: { enabled: boolean; thresholdMicros: number; targetMicros: number; monthlyMaxMicros: number },
1137 ): Promise<Result<AiCredit>>;
1138 /** The monthly budget: the spend limit, its alerts, whether usage pauses at 100%, and a webhook. Owners only. */
1139 setBudget(
1140 actor: User,
1141 workspace: string,
1142 budget: { amountMicros: number | null; alerts: number[]; pauseAtLimit: boolean; webhook: string | null; keepLimit?: boolean },
1143 ): Promise<Result<Limit>>;
1144 /** Invoice details from the Stripe customer, the default payment method, invoices and the next invoice. Members only. */
1145 billingDetails(workspace: string, viewer: Viewer): Promise<Result<BillingDetails>>;
1146 /** Saves invoice details on the Stripe customer; absent fields stay, empty clears. Owners only. */
1147 setBillingDetails(actor: User, workspace: string, details: BillingDetailsInput): Promise<Result<BillingDetails>>;
Agents as a team: lifecycle, merge queue, billing and a new shell1148}
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request1149
1150
1151/** One slice of usage: what it was for, what it cost, how many runs. */
1152export type UsageSlice = { key: string; micros: number; runs: number };
1153
Mission control shows model usage, yours and the workspace's: tokens, cost, active days, cache share, each day, and the mix1154/** The model tokens runs used over a window of days. */
1155export type TokenUsage = {
1156 /** `YYYY-MM-DD`, the first day counted. */
1157 since: string;
1158 /** The window's length: 42 unless asked, 366 at most. */
1159 days: number;
1160 /** Null for the whole workspace. */
1161 person: string | null;
1162 totalTokens: number;
1163 inputTokens: number;
1164 outputTokens: number;
1165 cacheReadTokens: number;
1166 cacheWriteTokens: number;
1167 /** What those runs were charged, as `usage` measures it. */
1168 costMicros: number;
1169 /** Days in the window with any tokens. */
1170 activeDays: number;
1171 /** Every day in the window, oldest first, zeros included. */
1172 byDay: { day: string; tokens: number }[];
1173};
1174
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens1175// --- AI Gateway -------------------------------------------------------------
1176
1177/** A model the AI Gateway offers on g1t's key, with its prices per million tokens. */
1178export type GatewayModel = {
1179 /** The id a request names, such as `claude-sonnet-5-5`. */
1180 model: string;
1181 /** For people: `Claude Sonnet 5.5`. */
1182 name: string;
1183 provider: string;
1184 inputMicros: number;
1185 outputMicros: number;
1186 cacheReadMicros: number;
1187 cacheWriteMicros: number;
1188};
1189
1190/** One AI Gateway request, as the model proxy reports it to billing. */
1191export type GatewayRecord = {
1192 /** `gw_…`, chosen by the proxy; recording it twice records it once. */
1193 id: string;
1194 workspace: string;
1195 tokenId: string;
1196 tokenName?: string | null;
1197 model: string;
1198 input: number;
1199 output: number;
1200 cacheRead: number;
1201 cacheWrite: number;
1202 /** The HTTP status the caller was answered with. */
1203 status: number;
1204 /** On the workspace's own provider key: counted, never charged. */
1205 ownKey: boolean;
1206 streamed: boolean;
1207 durationMs: number;
1208 error?: string | null;
1209};
1210
1211/** One AI Gateway request, as its log keeps it. */
1212export type GatewayRequest = {
1213 id: string;
1214 createdAt: string;
1215 model: string;
1216 tokenId: string;
1217 tokenName: string | null;
1218 input: number;
1219 output: number;
1220 cacheRead: number;
1221 cacheWrite: number;
1222 /** What the tokens cost at the model's price. */
1223 costMicros: number;
1224 /** What the workspace was charged, before included usage and credit paid for it; 0 on its own key. */
1225 chargedMicros: number;
1226 status: number;
1227 ownKey: boolean;
1228 streamed: boolean;
1229 durationMs: number;
1230 error: string | null;
1231};
1232
1233/** A page of AI Gateway requests, newest first. */
1234export type GatewayRequests = {
1235 requests: GatewayRequest[];
1236 /** The `before` for the next page, when there is one. */
1237 next: string | null;
1238 /** How many days requests are kept. */
1239 retentionDays: number;
1240};
1241
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request1242/** What a workspace's agents cost over a period. */
1243export type Usage = {
1244 since: string;
1245 /** Charged, including g1t's margin. */
1246 spentMicros: number;
Billing and Usage reconcile: own-provider runs leave Billing's at-price total, and Usage's not-charged part is at price less charged1247 /** What g1t's usage came to at price, less what was charged: the plan's included usage, the trial, a pool or a free period paid it. Usage at price is `spentMicros` plus this. */
Billing's usage total is labeled at price, and Usage says what part of it was paid for1248 coveredMicros?: number;
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging1249 /** What the account's discount took off the price; usage at price is spent + covered + this. */
1250 discountMicros?: number;
1251 /** The account's discount now, in percent; with one, the slices are at price. */
1252 discountPercent?: number | null;
Usage, Billing settings and prepaid AI credit; fixes from the UX audit1253 /** Usage at price: spent + covered + discount, from the same ledger lines. The one usage figure every page shows. */
1254 priceMicros?: number;
Integrations: your own model provider, alerts that open issues, tickets agents read1255 /** What g1t's model provider charged, before the margin. */
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request1256 costMicros: number;
Integrations: your own model provider, alerts that open issues, tickets agents read1257 /** What runs on the workspace's own provider cost there, estimated. Not charged by g1t. */
1258 providerMicros: number;
Usage while free is shown at cost; agents get rustfmt and clippy1259 /** What the runs used, at cost: g1t's models and the workspace's own provider together. */
1260 usedMicros: number;
1261 /** g1t charges nothing for now; the slices then measure usage at cost. */
1262 free: boolean;
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request1263 runs: number;
1264 /** Spend per day and task, keyed `YYYY-MM-DD/task`. */
1265 byDay: UsageSlice[];
1266 byTask: UsageSlice[];
1267 byRepo: UsageSlice[];
1268 /** Keyed `namespace/name#number`. */
1269 byPull: UsageSlice[];
1270 byModel: UsageSlice[];
1271 /** Credit bought in the period. */
1272 addedMicros: number;
1273};
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1274
1275/** One of g1t's products (a "bucket") on one day. Money in micros. */
1276export type CostDay = { day: string; bucket: string; cfCostMicros: number; ownCostMicros: number; valueMicros: number; cashMicros: number };
1277
1278/** One product over the range: what customers were charged at price against what it cost. */
1279export type ProductMargin = {
1280 bucket: string;
1281 title: string;
1282 /** Cloudflare's bill, or g1t's own figure where Cloudflare does not bill it (`costSource`). */
1283 costMicros: number;
1284 cfCostMicros: number;
1285 ownCostMicros: number;
1286 valueMicros: number;
1287 marginMicros: number;
1288 marginPercent: number | null;
1289 costSource: "cloudflare" | "ledger" | string;
1290 /** Running g1t, paid for by the plan. */
1291 overhead: boolean;
1292};
1293
1294/** All of g1t: money in (usage and the plan) against every cost. */
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it1295export type OverallMargin = {
1296 usageMicros: number;
1297 plansMicros: number;
1298 costMicros: number;
1299 marginMicros: number;
1300 marginPercent: number | null;
1301 /** Of costMicros, what went on usage g1t gave away on purpose: comped workspaces, free periods, the trial and the open-source pool. */
1302 givenMicros?: number;
1303 /** Money in against costMicros - givenMicros. */
1304 soldMarginMicros?: number;
1305 soldMarginPercent?: number | null;
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running1306 /** Usage sold: usageMicros against what that usage cost, less what was given. */
1307 usageCostMicros?: number;
1308 usageMarginMicros?: number;
1309 usageMarginPercent?: number | null;
1310 /** Running g1t: plansMicros against the platform's cost, less its given share. */
1311 runningCostMicros?: number;
1312 /** Cost no mapping names, less its given share. */
1313 unmappedCostMicros?: number;
1314 /** givenMicros by why. Free is free periods, free allowances and overruns g1t covered. */
1315 givenCompedMicros?: number;
1316 givenFreeMicros?: number;
1317 givenTrialMicros?: number;
1318 givenPoolMicros?: number;
Merge branch 'worktree-agent-a633ac0f7f66d419d'1319 /** What discounts on an account's terms took below cost plus the margin: given, not margin lost. */
1320 givenDiscountMicros?: number;
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging1321 /** Credits from g1t spent on usage, by kind: given, never money in. Refunds come off money in instead. */
1322 givenCreditPromotionalMicros?: number;
1323 givenCreditGoodwillMicros?: number;
Merge branch 'worktree-agent-a12ebea8611c42ee9'1324 /** What testing resets wiped that g1t paid for: the usage still happened, so its cost is given, never a leak. */
1325 givenResetMicros?: number;
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging1326 /** Credits over the range: given (every kind), spent on usage, and refunds' money given back. */
1327 creditsGivenMicros?: number;
1328 creditsUsedMicros?: number;
1329 creditsRefundedMicros?: number;
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running1330 /** costMicros by who g1t pays: Cloudflare's bill (billed, after included allowances) and model providers (tokens, not on Cloudflare's bill). */
Costs: the plan's included usage counts as paid for the usage it covered, out of what plans leave for running g1t; the run button shows it is running with CSS alone (sudo ships no JavaScript)1331 /** What the plan's included usage paid for, at price: money in for usage, paid out of plansMicros. */
1332 includedMicros?: number;
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running1333 cloudflareCostMicros?: number;
1334 modelsCostMicros?: number;
Merge Stripe Tax, the card fee on card payments, and one free workspace per person1335 /** Tax collected with payments over the range, net of refunds: owed to tax authorities, never cash or revenue. */
1336 taxCollectedMicros?: number;
1337 /** Card processing fees passed on with card payments, net of refunds: they pay Stripe's fee, not revenue. */
1338 cardFeesMicros?: number;
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it1339};
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1340
1341/** A count, cost or leak that does not add up. */
1342export type CostDrift = {
1343 bucket: string;
1344 title: string;
1345 kind: "count" | "cost" | "leak" | string;
1346 ours: number;
1347 cloudflare: number;
1348 deltaPercent: number | null;
1349 detail: string;
1350 foundAt: string;
1351};
1352
1353export type MarginAlert = {
1354 id: string;
1355 kind: "margin" | "overall" | "leak" | "drift" | "workspace" | string;
1356 /** The product, or the workspace. */
1357 subject: string;
1358 detail: string;
1359 since: string;
1360 openedAt: string;
1361 emailedAt: string | null;
1362};
1363
1364/** A change to a price, measured from what Cloudflare charged. */
1365export type PriceProposal = {
1366 id: string;
1367 meter: string;
1368 title: string;
1369 unit: string;
1370 currentCostMicros: number;
1371 proposedCostMicros: number;
1372 changePercent: number;
1373 markupPercent: number;
1374 reason: string;
1375 source: "keeper" | "reconciler" | string;
1376 /** Far off the current cost: look before approving. */
1377 suspect: boolean;
1378 status: "open" | "applied" | "approved" | "rejected" | "superseded" | string;
1379 createdAt: string;
1380 decidedAt: string | null;
1381 decidedBy: string | null;
1382 note: string | null;
1383 effectiveAt: string | null;
1384};
1385
1386/** One version of one meter's price; never changed once written. */
1387export type PriceVersion = {
1388 id: string;
1389 meter: string;
1390 version: number;
1391 costMicros: number;
1392 markupPercent: number;
1393 priceMicros: number;
1394 effectiveAt: string;
1395 reason: string;
1396 createdBy: string;
1397 appliedAt: string | null;
1398};
1399
sudo: reset a test workspace's billing so it starts again as a new customer; refused on a live Stripe key, for comped workspaces and for an enterprise's1400/** What `resetBilling` removed. */
sudo: a billing reset runs the costs analysis again so every figure is fresh; every submit button shows it is working (CSS only); no margin percentage on less than a cent sold1401export type BillingReset = { workspace: string; rows: number; refreshed?: boolean };
sudo: reset a test workspace's billing so it starts again as a new customer; refused on a live Stripe key, for comped workspaces and for an enterprise's1402
Costs: margin is measured on what was sold; comped workspaces, free periods, the trial and the pools are given away, a budget shown beside it1403export type WorkspaceCost = { workspace: string; costMicros: number; revenueMicros: number; givenMicros?: number; internal: boolean };
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1404
1405export type CostLineSummary = {
1406 product: string;
1407 meter: string;
1408 rawName: string;
1409 unit: string;
1410 source: string;
1411 quantity: number;
1412 costMicros: number;
1413 /** Absent when no mapping claims it. */
1414 bucket: string | null;
1415};
1416
1417export type CostMapping = {
1418 product: string;
1419 meter: string;
1420 bucket: string;
1421 priceMeter: string | null;
1422 ownMeter: string | null;
1423 scaleToOwn: boolean;
1424 driftPercent: number;
1425 note: string;
1426 updatedAt: string;
1427 updatedBy: string;
1428};
1429
1430export type CostMappingInput = {
1431 product: string;
1432 meter: string;
1433 bucket?: string;
1434 priceMeter?: string | null;
1435 ownMeter?: string | null;
1436 scaleToOwn?: boolean;
1437 driftPercent?: number | null;
1438 note?: string;
1439 remove?: boolean;
1440};
1441
1442export type CostSettings = {
1443 autoApply: boolean;
1444 autoApplyPercent: number;
1445 noticeDays: number;
1446 marginFloorPercent: number;
1447 alertDays: number;
1448 minDailyCostMicros: number;
1449 anomalyFactor: number;
1450 anomalyFloorMicros: number;
Usage, Billing settings and prepaid AI credit; fixes from the UX audit1451 /** Pass Stripe's card fee on as its own line when AI credit is bought by card. */
1452 cardFee: boolean;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1453};
1454
1455export type CostsReport = {
1456 configured: boolean;
1457 fetchedAt: string | null;
1458 since: string;
1459 until: string;
1460 days: CostDay[];
1461 products: ProductMargin[];
1462 overall: OverallMargin;
1463 drift: CostDrift[];
1464 alerts: MarginAlert[];
1465 proposals: PriceProposal[];
1466 versions: PriceVersion[];
1467 topWorkspaces: WorkspaceCost[];
1468 lines: CostLineSummary[];
1469 mappings: CostMapping[];
1470 settings: CostSettings;
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1471 /** g1t's own spend against its two caps. */
1472 caps: SpendCaps;
1473};
1474
1475/** What g1t pays for itself, at cost, against its caps (billing's `budget`). */
1476export type SpendCaps = {
1477 /** Today (UTC), YYYY-MM-DD, and this month, YYYY-MM. */
1478 day: string;
1479 month: string;
1480 /** What g1t paid for itself today across every workspace. */
1481 todayMicros: number;
1482 /** `PLATFORM_DAILY_SPEND_CAP_MICROS`; 0: no breaker. */
1483 dailyCapMicros: number;
1484 /** New hosted-model agent runs g1t would pay for are paused. */
1485 tripped: boolean;
1486 trippedAt: string | null;
1487 liftedBy: string | null;
1488 liftedAt: string | null;
1489 liftNote: string | null;
1490 /** This month so far, by what paid: comped, trial, oss, given, unpaid. */
1491 monthBuckets: { bucket: string; title: string; micros: number }[];
1492 comped: CompedBudget[];
1493 /** Free workspaces' share of reconciled costs this month (git, storage, platform). */
1494 freeTierMicros: number;
Costs: Cloudflare's subscriptions read from Cloudflare each day, the estimate only until then; sudo's costs split into Costs & margin and Bill & pricing1495 /** Cloudflare's subscriptions a month: read from Cloudflare each day, else `CLOUDFLARE_FIXED_MONTHLY_MICROS`, an estimate. */
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1496 fixedMonthlyMicros: number;
Costs: Cloudflare's subscriptions read from Cloudflare each day, the estimate only until then; sudo's costs split into Costs & margin and Bill & pricing1497 fixedSource?: "cloudflare" | "estimate" | string;
1498 fixedReadAt?: string | null;
1499 /** Each subscription, when read from Cloudflare. */
1500 fixedItems?: { name: string; monthlyMicros: number }[];
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays1501 /** Money in this month, through the last reconciled day. */
1502 revenueMicros: number;
1503};
1504
1505/** A comped account's monthly budget, at cost. */
1506export type CompedBudget = {
1507 account: string;
1508 name: string;
1509 usedMicros: number;
1510 /** 0: no budget. */
1511 ceilingMicros: number;
1512 /** `COMPED_MONTHLY_CEILING_MICROS`, not the account's own limit. */
1513 defaultCeiling: boolean;
1514 /** 50, 75, 90, 100, or 0. */
1515 level: number;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1516};
1517
1518export type CostsRun = { lines: number; days: number; proposals: number; alerts: number; problems: string[] };
Usage, Billing settings and prepaid AI credit; fixes from the UX audit1519
1520/** The product families the Usage page groups meters into, in order. */
1521export const PRODUCTS = [
1522 { key: "agent", label: "Agent" },
1523 { key: "sandboxes", label: "Sandboxes" },
1524 { key: "gateway", label: "AI Gateway" },
1525 { key: "deployments", label: "Deployments" },
1526 { key: "git_storage", label: "Git & storage" },
1527 { key: "packages", label: "Packages" },
1528 { key: "security", label: "Security & quality" },
1529 { key: "search", label: "Search" },
1530] as const;
1531
1532export type ProductKey = (typeof PRODUCTS)[number]["key"];
1533
1534/** What usage came to over a range, and what paid for it: price − discount − included − credits = charged. */
1535export type UsageTotals = {
1536 /** Usage at price, pending usage included. */
1537 priceMicros: number;
1538 discountMicros: number;
1539 /** Paid by the plan's included usage, the trial and g1t's pools. */
1540 includedMicros: number;
1541 /** Paid by AI credit and credit from g1t. */
1542 creditsMicros: number;
1543 /** Left for the workspace to pay. */
1544 chargedMicros: number;
1545 /** Metered this month, charged when it closes. */
1546 pendingMicros: number;
1547 costMicros: number;
1548};
1549
1550export type UsageDay = { day: string; product: string; micros: number };
1551
1552export type UsageAllowance = { used: number; of: number; unit: string };
1553
1554export type ProjectUsage = { project: string; micros: number; quantity: number };
1555
1556/** One meter over a range. */
1557export type MeterLine = {
1558 key: string;
1559 label: string;
1560 product: string;
1561 /** `tokens`, `seconds`, `bytes`, `operations`, `requests` or `entries`. */
1562 unit: string;
1563 quantity: number;
1564 micros: number;
1565 pendingMicros?: number;
1566 /** Every day of the range, oldest first, at price. */
1567 daily: number[];
1568 allowance?: UsageAllowance | null;
1569 byProject: ProjectUsage[];
Merge branch 'model-routing'1570 /** How the quantity is counted, when that needs saying (the agent rate's token weights). */
1571 note?: string | null;
Usage, Billing settings and prepaid AI credit; fixes from the UX audit1572};
1573
1574export type FeatureUsage = { key: string; label: string; micros: number; count: number };
1575
1576export type ProductUsage = { key: string; label: string; micros: number; meters: MeterLine[]; features?: FeatureUsage[] };
1577
Merge branch 'model-routing'1578/** The tokens one model used over a range, as the model proxy counted them. */
1579export type ModelTokens = { model: string; input: number; output: number; cacheRead: number; cacheWrite: number };
1580
Usage, Billing settings and prepaid AI credit; fixes from the UX audit1581export type UsageReport = {
1582 from: string;
1583 until: string;
1584 totals: UsageTotals;
1585 days: UsageDay[];
1586 products: ProductUsage[];
1587 projects: string[];
Merge branch 'model-routing'1588 /** Agent tokens by model over the range, most first. */
1589 models?: ModelTokens[];
Usage, Billing settings and prepaid AI credit; fixes from the UX audit1590 /** The plan's included usage this month, in micros. */
1591 included?: UsageAllowance | null;
1592 discountPercent?: number | null;
1593 aiCreditMicros: number;
1594 creditMicros: number;
1595 trialMicros?: number | null;
1596 plan: PlanKind;
1597 free: boolean;
1598};
1599
1600export type AiReload = {
1601 enabled: boolean;
1602 thresholdMicros: number;
1603 targetMicros: number;
1604 monthlyMaxMicros: number;
1605 reloadedMicros?: number;
1606 failedAt?: string | null;
1607 error?: string | null;
1608};
1609
1610export type CardFee = { on: boolean; percentMicros: number; fixedCents: number };
1611
1612/** Prepaid AI credit: what Agent and AI Gateway usage draws on. */
1613export type AiCredit = {
1614 balanceMicros: number;
1615 purchasedMicros: number;
1616 givenMicros: number;
1617 grants: CreditGrant[];
1618 /** A 100% discount pays for AI usage: nothing to buy. */
1619 freeViaDiscount: boolean;
1620 /** Invoiced after use (an enterprise). */
1621 postpaid: boolean;
1622 /** New runs on g1t's models are refused for want of credit. */
1623 blocked: boolean;
1624 canBuy: boolean;
1625 presetsCents: number[];
1626 minCents: number;
1627 maxCents: number;
1628 cardFee: CardFee;
1629 reload: AiReload;
1630 /** The agent rate per million tokens, at price. */
1631 agentRateMicros: number;
1632 modelMarkupPercent: number;
1633 gatewayMarkupPercent: number;
1634 upgradeCreditMicros: number;
1635 expiresDays: number;
1636};
1637
1638export type PostalAddress = { line1: string; line2: string; city: string; state: string; postalCode: string; country: string };
1639
1640export type PaymentMethod = {
1641 kind: string;
1642 brand?: string | null;
1643 last4?: string | null;
1644 expMonth?: number | null;
1645 expYear?: number | null;
1646};
1647
1648export type StripeInvoice = {
1649 id: string;
1650 number?: string | null;
1651 status: string;
1652 totalCents: number;
1653 currency: string;
1654 createdAt: string;
1655 description?: string | null;
1656 hostedUrl?: string | null;
1657 pdfUrl?: string | null;
1658};
1659
1660export type UpcomingInvoice = { closesAt: string; subscriptionsMicros: number; usageMicros: number; totalMicros: number };
1661
1662export type BillingDetails = {
1663 customer: boolean;
1664 email: string | null;
1665 name: string | null;
1666 address: PostalAddress | null;
1667 taxIdType: string | null;
1668 taxId: string | null;
1669 poNumber: string | null;
1670 language: string | null;
1671 paymentMethod: PaymentMethod | null;
1672 invoices: StripeInvoice[];
1673 upcoming: UpcomingInvoice;
1674 unavailable?: string | null;
Merge Stripe Tax, the card fee on card payments, and one free workspace per person1675 /** Whether Stripe Tax can place the customer from the address; without it nothing is charged. */
1676 taxLocation?: boolean;
1677 /** Set when g1t did not charge for want of a billing address. */
1678 taxAddressNeededAt?: string | null;
1679 /** Stripe's check of the tax ID: pending, verified, unverified or unavailable. */
1680 taxIdStatus?: string | null;
1681 /** none, exempt or reverse, as set at Stripe. */
1682 taxExempt?: string | null;
Usage, Billing settings and prepaid AI credit; fixes from the UX audit1683};
1684
1685export type BillingDetailsInput = {
1686 email?: string;
1687 name?: string;
1688 address?: PostalAddress;
1689 taxIdType?: string;
1690 taxId?: string;
1691 poNumber?: string;
1692 language?: string;
1693};

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