Skip to content
1,641 linesCodeBlameRaw
1import type { ComputeKind, Reservation } from "./compute";
2import type { PauseLevel } from "./platform";
3import type { User, Viewer } from "./identity";
4import type { RepoPath } from "./repos";
5import type { Result } from "./result";
6
7/** Millionths of a US dollar in one dollar: the unit money is held in. */
8export const MICROS_PER_DOLLAR = 1_000_000;
9
10/** Whether workspaces are charged for agents at all, and with real money. */
11export type BillingStatus = {
12 /**
13 * False when no card processor is configured: nothing is charged, and who
14 * may run agents is decided some other way.
15 */
16 enabled: boolean;
17 /** False while the card processor is in its test mode, where cards are not real. */
18 live: boolean;
19 /**
20 * True while g1t is being built out: runs are recorded with what they
21 * cost, but nothing is charged and no credit is needed. Not forever.
22 */
23 free?: boolean;
24};
25
26/** A workspace's standing. */
27export type BillingAccount = {
28 workspace: string;
29 /**
30 * Credit left, in millionths of a dollar. Can dip below zero by the cost
31 * of the runs that were under way when it ran out.
32 */
33 balanceMicros: number;
34 status: BillingStatus;
35 /** What is added to a run's cost, in percent. */
36 marginPercent: number;
37 /** The card charged near the limit and when a month closes, if one is saved. */
38 card?: { brand: string; last4: string; expMonth: number; expYear: number } | null;
39};
40
41/** One line of a workspace's statement. */
42export type LedgerEntry = {
43 id: string;
44 /** Credit bought with a card, or an agent's run. */
45 kind: "top_up" | "usage";
46 /** Positive for credit added, negative for usage. */
47 amountMicros: number;
48 description: string;
49 /** For usage: the repository and pull request the agent worked on. */
50 repo: string | null;
51 number: number | null;
52 /** For usage: `implement`, `review` or `update`. */
53 task: string | null;
54 /** For usage: the model, by its public name. */
55 model: string | null;
56 /** For usage: who paid the model provider. */
57 billedTo: "g1t" | "workspace";
58 /** For a top-up: the username of whoever paid. */
59 createdBy: string | null;
60 /** RFC 3339. */
61 createdAt: string;
62 /** The workspace the line belongs to, which tells an enterprise's lines apart. */
63 workspace?: string | null;
64 /** For usage: what the plan's included usage paid of it. `amountMicros` is what is left to pay. */
65 creditMicros?: number;
66 /** For usage: what the workspace's trial credit paid of it. */
67 trialMicros?: number;
68 /** For usage: what g1t's open-source pool paid of it. */
69 ossMicros?: number;
70 /** For usage: what g1t covered itself, such as a trial's last run past its credit. */
71 givenMicros?: number;
72 /** For usage: what the account's discount took off its price. */
73 discountMicros?: number;
74 /** For a credit from g1t, and for what of one expired or was revoked: its kind. */
75 creditKind?: CreditKind;
76};
77
78/**
79 * Why g1t gave a workspace credit. Promotional (a welcome, a referral) and
80 * goodwill (an apology) are given away when spent; a refund gives back
81 * money already paid, and never expires.
82 */
83export type CreditKind = "promotional" | "goodwill" | "refund" | "purchased";
84
85/** One credit g1t gave, with what of it was used: spent before anything paid in advance, the soonest-expiring first. */
86export type CreditGrant = {
87 /** `crd_…`, the grant's ledger reference. */
88 id: string;
89 workspace: string;
90 kind: CreditKind;
91 amountMicros: number;
92 usedMicros: number;
93 /** What can still be spent: nothing once it expired or was revoked. */
94 leftMicros: number;
95 note: string;
96 /** A refund: what it refunds, and the day of it. */
97 refundFor?: string | null;
98 refundDay?: string | null;
99 /** RFC 3339; null never expires. */
100 expiresAt: string | null;
101 createdBy: string;
102 createdAt: string;
103 state: "open" | "used" | "expired" | "revoked";
104 closedAt?: string | null;
105 closedNote?: string | null;
106 closedBy?: string | null;
107 /** What expiring or revoking took off the balance. */
108 closedMicros?: number;
109 /** What it pays for: all usage, or models only (spent first). */
110 scope?: "all" | "models";
111 /** Where it came from. */
112 source?: "staff" | "purchase" | "promo_code" | "upgrade";
113};
114
115/** A workspace's credits from g1t, newest first. */
116export type Credits = { grants: CreditGrant[]; leftMicros: number };
117
118/** One month's credits of one kind: given, spent that month, and taken back unused. */
119export type CreditMonth = {
120 month: string;
121 kind: CreditKind;
122 givenMicros: number;
123 grants: number;
124 usedMicros: number;
125 expiredMicros: number;
126 revokedMicros: number;
127};
128
129/** Every credit g1t gave (at most 200, filtered), the last 12 months by kind, and who gave them. */
130export type AdminCredits = { grants: CreditGrant[]; months: CreditMonth[]; staff: string[] };
131
132/** What a credit from sudo is, past its amount and note. */
133export type CreditOptions = {
134 kind: CreditKind;
135 /** RFC 3339; never for a refund. */
136 expiresAt?: string | null;
137 /** A refund: what it is for, and the day refunded (`YYYY-MM-DD`). */
138 refundFor?: string | null;
139 refundDay?: string | null;
140};
141
142/**
143 * How an account is charged. Standard unless g1t set otherwise in sudo:
144 * custom terms are a discount (0 to 100%), a ceiling, or both. A 100%
145 * discount charges nothing and shows the usage at its price. `comped` is
146 * from before discounts and reads as 100%; billing no longer writes it.
147 */
148export type Terms = {
149 kind: "standard" | "comped" | "custom";
150 discountPercent: number;
151 ceilingMicros: number | null;
152 note: string;
153 until: string | null;
154 setBy: string | null;
155 setAt: string | null;
156};
157
158/**
159 * Who pays: a workspace's own account, or an enterprise's, which pays for
160 * several workspaces with one bill and one limit.
161 */
162export type PayingAccount = {
163 id: string;
164 kind: "workspace" | "enterprise";
165 name: string;
166 terms: Terms;
167 workspaces: string[];
168 /** Where an enterprise's invoices go. */
169 billingEmail?: string | null;
170 /** An enterprise's invoices, newest first. */
171 invoices?: EnterpriseInvoice[];
172 createdAt: string;
173 /** What g1t staff set for the account beyond its terms. */
174 allowances?: Allowances;
175};
176
177/** Set per account by g1t staff in sudo, on top of its terms. */
178export type Allowances = {
179 /** The g1t plan without its monthly price; usage is charged as usual. Comped accounts have it anyway. */
180 plan: boolean;
181 /** Each public repository's monthly cap on g1t's open-source pool; null for the default. */
182 ossRepoMicros: number | null;
183 /** Each workspace's trial credit, outside the monthly pool; null for the default. */
184 trialMicros: number | null;
185 /** Agents at once, in place of the plan's (2 in the first month or on the trial, then 10); null for the default. */
186 maxConcurrentAgents?: number | null;
187 /** One run's spend cap, in place of the owners' and the default $2; null for none. */
188 runCapMicros?: number | null;
189 /** What one issue's agents may spend in all, in place of the owners' and the default $10; null for none. */
190 issueCapMicros?: number | null;
191 /** 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. */
192 auditRetentionDays?: number | null;
193 /** A hold on new compute, with why; null for none. */
194 hold?: string | null;
195};
196
197// --- Entitlements, and compute started under a reservation ------------------
198//
199// Every service that starts compute asks billing first:
200// 1. `entitlements(workspace)`: what it may do at all, its caps, and whether compute is paused.
201// 2. `reserve(...)`: holds the estimate against what may pay for it, so starts at the same moment
202// cannot overshoot together. Answers who pays first, or refuses with a stable code
203// (`not_paid`, `trial_used`, `limit`, `paused`, `oss_pool_empty`) and a message for the owner.
204// 3. `settle(reservationId, actualMicros)`: releases the hold. The charge goes on the ledger the usual way.
205// A reservation never settled lapses after `RESERVATION_HOURS`.
206
207/** A reservation that is never settled stops holding after this long. */
208export const RESERVATION_HOURS = 3;
209/** What a ceiling reads as when there is none (g1t's own workspaces). */
210export const UNLIMITED_MICROS = 1_000_000_000_000_000;
211
212/** What a workspace pays g1t on, as far as compute is concerned. Mirrors `PlanKind`. */
213export type PlanKind = "free" | "paid" | "internal" | "enterprise";
214
215// `ComputeKind` (what compute is for), `PaidBy` (who pays first: credit, trial, oss, on_demand) and
216// `Reservation` are in `./compute`, with the gate that calls `reserve` and `settle`.
217
218/** One level reached: 50, 75, 90 or 100 percent. */
219export type UsageAlert = {
220 /** `included` (the plan's included usage), `spend_limit` or `ceiling`. */
221 meter: "included" | "spend_limit" | "ceiling" | string;
222 level: number;
223 usedMicros: number;
224 limitMicros: number;
225 message: string;
226};
227
228/** An hour's spend well above the workspace's usual: new compute waits for an owner. */
229export type Spike = {
230 id: string;
231 /** `open` (waiting), `continued` (keep going) or `stopped`. */
232 status: "open" | "continued" | "stopped" | string;
233 hourMicros: number;
234 averageMicros: number;
235 detectedAt: string;
236 decidedBy?: string | null;
237 decidedAt?: string | null;
238 /** While continued: until when, unless spend doubles again first. */
239 until?: string | null;
240};
241
242/** What a workspace may do now. Mirrors `Entitlements` in `crates/contracts/src/billing.rs`. */
243export type Entitlements = {
244 workspace: string;
245 plan: PlanKind;
246 /** May start sandboxes, models, deployments and semantic search at all: paid, internal, enterprise, or free with trial credit left. */
247 compute: boolean;
248 /** The one-time trial credit left; 0 if none or used. */
249 trialMicrosLeft: number;
250 /** A card check has been done; the trial and the open-source pool need it. */
251 trialVerified: boolean;
252 /** A paid workspace still in its first billing cycle. */
253 firstMonth: boolean;
254 /** 2 in the first month or on the trial, 10 after; staff can override it. */
255 maxConcurrentAgents: number;
256 /** 60 in the first month or on the trial; otherwise the guardrails' own caps. */
257 maxRunMinutes: number;
258 /** One run's spend cap, $2 by default; staff can override it. */
259 runCapMicros: number;
260 /** Agent spend on one issue in all, $10 by default. */
261 issueCapMicros: number;
262 /** g1t's ceiling on usage not yet paid for; `UNLIMITED_MICROS` for g1t's own; 0 for free. */
263 ceilingMicros: number;
264 /** Usage not yet paid for this month, prepayment taken off. */
265 exposureMicros: number;
266 /** Why new compute is paused, for the owner; null when it is not. */
267 paused: string | null;
268 /** g1t staff put a hold on the account: nothing new is set up for it, such as a self-hosted runner. */
269 held?: boolean;
270 /** What open reservations hold now. */
271 heldMicros?: number;
272 /** Paid in advance and not used yet. */
273 prepaidMicros?: number;
274 /** The plan's included usage each month, and what of it is used. */
275 includedMicros?: number;
276 includedUsedMicros?: number;
277 /** 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. */
278 auditRetentionDays: number;
279 /** Whether `auditRetentionDays` is what staff set for the account rather than the plan's. */
280 auditRetentionCustom?: boolean;
281 /** Private repository storage free for every workspace: past it, the plan pays and a free workspace's pushes stop. */
282 freePrivateStorageBytes: number;
283 /** The last daily measure of the workspace's private repositories (a lower bound). */
284 privateStorageBytes: number;
285 /** On a paid plan: package storage past the free amounts is charged, never refused. */
286 hasPlan?: boolean;
287 /** Package storage free for every workspace (public, and private): past it a free workspace's pushes are refused. */
288 packagePublicFreeBytes?: number;
289 packagePrivateFreeBytes?: number;
290 /** What g1t's open-source pool paid for the workspace this month. */
291 ossPaidMicros: number;
292 /** Deploy build time this month, every second of it metered. */
293 buildSecondsUsed?: number;
294 /** Git operations this month, and how many are free for every workspace. */
295 gitOperations?: number;
296 gitOperationsIncluded?: number;
297 /** The smallest amount a card is charged when a month closes. */
298 minChargeMicros: number;
299 /** A spend spike waiting for an owner, or decided. */
300 spike?: Spike | null;
301 /** Where usage stands against what is included and the limits, from 50%. */
302 alerts?: UsageAlert[];
303};
304
305/** A hold on a start's estimated cost, as billing answers it (`Reservation` in `./compute`, and more). */
306export type ReservationHeld = Reservation & {
307 /** What is held, at cost; may be less than the estimate for a free workspace's last bit of trial. */
308 heldMicros?: number;
309 /** When the hold lapses if never settled. */
310 expiresAt?: string;
311};
312
313/** A request to g1t: a higher limit, or help with usage past what was meant. */
314export type LimitRequest = {
315 id: string;
316 workspace: string;
317 kind: "limit" | "overage" | string;
318 amountMicros: number;
319 reason: string;
320 expectedMonthlyMicros: number;
321 status: "open" | "approved" | "declined" | string;
322 decidedMicros?: number | null;
323 decidedBy?: string | null;
324 /** The answer, as the owner sees it. */
325 answer?: string | null;
326 createdBy: string;
327 createdAt: string;
328 decidedAt?: string | null;
329};
330
331/** What staff see beside a request. */
332export type WorkspaceHistory = {
333 plan: PlanKind | null;
334 months: MonthFigures[];
335 paidClearedMicros: number;
336 payments: number;
337 disputes: number;
338 declines: number;
339 firstSeen: string | null;
340 ceilingMicros: number | null;
341 maxCeilingMicros: number | null;
342 spendLimitMicros: number | null;
343 lastHourMicros: number;
344 averageHourMicros: number;
345 lastDayMicros: number;
346};
347
348export type LimitRequestReview = { request: LimitRequest; history: WorkspaceHistory };
349
350/** What a one-time goodwill credit comes to: the margin on the overage, always, plus its cost up to the cap. */
351export type Goodwill = {
352 overageMicros: number;
353 marginMicros: number;
354 costMicros: number;
355 creditMicros: number;
356 absorbedMicros: number;
357};
358
359/** A workspace whose month went well past its usual, or hit a spike. */
360export type Overage = {
361 workspace: string;
362 plan: PlanKind;
363 typicalMonthMicros: number;
364 thisMonthMicros: number;
365 costMicros: number;
366 marginMicros: number;
367 spike: Spike | null;
368 topEntries: LedgerEntry[];
369 goodwill: Goodwill;
370 goodwillAvailable: boolean;
371 lastGoodwillAt: string | null;
372 request: LimitRequest | null;
373};
374
375/** One workspace's recent pace. */
376export type Velocity = {
377 workspace: string;
378 plan: PlanKind;
379 lastHourMicros: number;
380 averageHourMicros: number;
381 lastDayMicros: number;
382 thisMonthMicros: number;
383 ratio: number;
384 spike: Spike | null;
385 firstSeen: string | null;
386};
387
388/** g1t's capped budgets for free usage this month. */
389export type Pools = {
390 month: string;
391 trialGrantedMicros: number;
392 trialPoolMicros: number;
393 trialGrants: number;
394 ossUsedMicros: number;
395 ossPoolMicros: number;
396 ossRepoMicros: number;
397};
398
399export type AccountSummary = {
400 account: PayingAccount;
401 limit: Limit;
402 chargedMicros: number;
403 costMicros: number;
404 paidMicros: number;
405 /** The same figures for each of the account's workspaces that has any. */
406 byWorkspace: WorkspaceFigures[];
407 /** The last six months, oldest first. */
408 months?: MonthFigures[];
409};
410
411/** One workspace's share of an `AccountSummary`. */
412export type WorkspaceFigures = { workspace: string; chargedMicros: number; costMicros: number; paidMicros: number };
413
414export type StripeStatus = {
415 /** `test` or `live`, from the key; `off` without one. */
416 mode: "test" | "live" | "off" | string;
417 /** Whether `STRIPE_WEBHOOK_SECRET` is set, so events can be checked. */
418 secretSet: boolean;
419 /** The destination at billing's address in Stripe, as Stripe has it. */
420 webhook: { url: string; endpointId: string; status: "enabled" | "disabled" | string; events: string[]; createdAt: string } | null;
421 /** Events billing handles that the destination does not send. */
422 missingEvents: string[];
423 recentEvents: { id: string; kind: string; outcome: string; receivedAt: string }[];
424 error: string | null;
425};
426
427/** An enterprise's invoice: one line per workspace, paid on Stripe's page. */
428export type EnterpriseInvoice = {
429 invoiceId: string;
430 hostedUrl: string | null;
431 amountMicros: number;
432 status: "open" | "paid" | "overdue" | "void" | string;
433 period: string;
434 lines: { workspace: string; amountMicros: number }[];
435 createdAt: string;
436};
437
438/** A workspace's invoice: monthly, or when charged near its limit. Itemised, in Stripe's billing page. */
439export type WorkspaceInvoice = {
440 invoiceId: string;
441 workspace: string;
442 reason: "month" | "threshold" | string;
443 period: string;
444 amountMicros: number;
445 status: "paid" | "open" | "failed" | "void" | string;
446 hostedUrl: string | null;
447 pdfUrl: string | null;
448 lines: { description: string; amountMicros: number }[];
449 createdAt: string;
450 /** The card processing fee on top of `amountMicros` when charged to a card, and the tax Stripe added once known. */
451 feeMicros?: number;
452 taxMicros?: number;
453};
454
455/** A month of the ledger, grouped by day or project, a line per kind of charge. */
456export type Statement = {
457 month: string;
458 months: string[];
459 groups: {
460 key: string;
461 label: string;
462 /** `coveredMicros`: what the plan's included usage, the trial, the open-source pool or g1t paid, not in `chargedMicros`. */
463 /** `priceMicros`: usage at its price; `discountMicros`: what the account's discount took off it. */
464 lines: {
465 kind: string;
466 count: number;
467 chargedMicros: number;
468 costMicros: number;
469 coveredMicros?: number;
470 priceMicros?: number;
471 discountMicros?: number;
472 /** On `Tax` and `Card processing fees` lines: what was paid with payments on top of what reached the balance. Never charged. */
473 passedMicros?: number;
474 /** On a `Runner minutes, <machine>` line: the minutes charged, each job's time rounded up to the minute. */
475 minutes?: number;
476 }[];
477 chargedMicros: number;
478 priceMicros?: number;
479 discountMicros?: number;
480 }[];
481 totals: {
482 chargedMicros: number;
483 paidMicros: number;
484 costMicros: number;
485 entries: number;
486 /** Usage at price, and what the discount took off: charged is the price less the discount and what paid for it. */
487 priceMicros?: number;
488 discountMicros?: number;
489 /** The account's discount now, in percent; absent without one. */
490 discountPercent?: number | null;
491 /** What paid for usage before it was charged, such as "Paid by g1t's open-source pool". */
492 covered?: { source: "included" | "trial" | "oss_pool" | "given" | string; label: string; micros: number }[];
493 /** Owed when the month closed but under the minimum charge: on the next invoice. */
494 carriedMicros?: number;
495 /** Tax and card processing fees paid with the month's payments, on top of `paidMicros`. */
496 taxMicros?: number;
497 cardFeeMicros?: number;
498 };
499};
500
501export type MonthFigures = {
502 month: string;
503 /** Usage charged, after what paid for it first. */
504 chargedMicros: number;
505 /** What usage cost g1t: never a workspace's own model provider. */
506 costMicros: number;
507 paidMicros: number;
508 /** The plan's monthly price, paid. */
509 plansMicros?: number;
510 /** What g1t gave at price (internal use, trials, the open-source pool, goodwill, covered). Not margin. */
511 givenMicros?: number;
512};
513
514/** What g1t gave this month from one source. */
515export type GivenFigures = { source: "internal" | "trial" | "oss_pool" | "goodwill" | "covered" | string; label: string; micros: number; costMicros: number };
516
517/** One internal workspace's use this month, and why it is not charged. */
518export type InternalUse = { workspace: string; reason: string; costMicros: number; entries: number };
519
520export type SignalKind = "at_limit" | "near_ceiling" | "declined" | "growing" | "established" | "first_payment" | "high_spend" | "cost_over_revenue";
521
522/** Why a workspace is worth reaching out to. */
523export type Signal = {
524 workspace: string;
525 kind: SignalKind;
526 detail: string;
527 valueMicros: number;
528 stage: string | null;
529 owner: string | null;
530 nextStep?: string | null;
531 /** When the next step is due, YYYY-MM-DD. */
532 nextAt?: string | null;
533};
534
535/** One invoice g1t has sent, a workspace's or an enterprise's. */
536export type InvoiceSummary = {
537 invoiceId: string;
538 kind: "workspace" | "enterprise";
539 account: string;
540 name: string;
541 reason: string;
542 period: string;
543 amountMicros: number;
544 status: string;
545 hostedUrl: string | null;
546 createdAt: string;
547 paidAt: string | null;
548};
549
550export type SalesStage = "none" | "lead" | "contacted" | "negotiating" | "won" | "lost" | "churn_risk";
551
552export type SalesRecord = {
553 workspace: string;
554 stage: SalesStage | string;
555 owner: string | null;
556 nextStep: string | null;
557 nextAt: string | null;
558 notes: { id: string; text: string; by: string; createdAt: string }[];
559 updatedAt: string | null;
560};
561
562export type Overview = {
563 month: string;
564 months: MonthFigures[];
565 byKind: { kind: string; chargedMicros: number; costMicros: number }[];
566 payingWorkspaces: number;
567 stopped: number;
568 nearCeiling: number;
569 declined: number;
570 openInvoicesMicros: number;
571 followUpsDue: number;
572 /** g1t's capped budgets for free usage, this month. */
573 pools?: Pools | null;
574 /** Usage charged plus the plan's price paid, this month. */
575 revenueMicros?: number;
576 activePlans?: number;
577 planMrrMicros?: number;
578 /** What g1t gave this month, by source, apart from its margin. */
579 given?: GivenFigures[];
580 /** g1t's own and Flagon's workspaces: what their use cost, and why they are not charged. */
581 internal?: InternalUse[];
582 openRequests?: number;
583 overages?: number;
584 openSpikes?: number;
585};
586
587/** A customer's Stripe billing page, for staff to send them. */
588export type BillingLink = {
589 /** One-time and short-lived, signed in already. */
590 portalUrl: string;
591 /** The page's sign-in, which does not expire: the customer signs in by email. */
592 loginUrl: string | null;
593 customerEmail: string | null;
594 expiresNote: string;
595};
596
597export type AdminAction = { id: string; account: string; action: string; detail: string; by: string; createdAt: string };
598
599export type AccountDetail = {
600 summary: AccountSummary;
601 workspaces: Limit[];
602 ledger: LedgerEntry[];
603 audit: AdminAction[];
604};
605
606/** Staff-only billing, for sudo.g1t.sh. Every change names who made it. */
607export interface BillingAdminApi {
608 accounts(query?: string): Promise<AccountSummary[]>;
609 account(id: string): Promise<Result<AccountDetail>>;
610 setTerms(id: string, terms: Terms, by: string): Promise<Result<PayingAccount>>;
611 /** Team on or off without charge, and the account's share of the pools. Needs a note. */
612 setAllowances(id: string, allowances: Allowances, note: string, by: string): Promise<Result<PayingAccount>>;
613 createEnterprise(name: string, workspaces: string[], by: string): Promise<Result<PayingAccount>>;
614 attach(workspace: string, account: string | null, by: string): Promise<Result<PayingAccount>>;
615 /** Credit for a workspace: promotional, goodwill or a refund; the owners are emailed. */
616 credit(workspace: string, amountMicros: number, note: string, by: string, options?: CreditOptions): Promise<Result<LedgerEntry>>;
617 /** Every credit g1t gave, filtered, with each month's totals by kind. */
618 credits(filter?: { workspace?: string | null; kind?: CreditKind | null; month?: string | null; by?: string | null }): Promise<AdminCredits>;
619 /** What is left of a credit, taken back, with why. */
620 revokeCredit(id: string, note: string, by: string): Promise<Result<CreditGrant>>;
621 /** A test workspace's billing wiped, to start again as a new customer. Only on Stripe's test key; never comped or enterprise. Logged. */
622 resetBilling(workspace: string, confirm: string, note: string, by: string): Promise<Result<BillingReset>>;
623 /** The workspace's Stripe billing page, to send to the customer. Logged. */
624 billingLink(workspace: string, by: string): Promise<Result<BillingLink>>;
625 /** Where billing stands with Stripe; with `setup`, registers the webhook first. */
626 /** Stripe's state for billing; `fix` enables the destination and adds missing events first. */
627 stripe(fix?: boolean, by?: string): Promise<StripeStatus>;
628 /** Where an enterprise's invoices go; makes its Stripe customer. */
629 enterpriseBilling(id: string, email: string, by: string): Promise<Result<PayingAccount>>;
630 /** The enterprise's billing address and tax ID, on its Stripe customer: Stripe Tax works its invoices out from them. */
631 enterpriseAddress(id: string, address: PostalAddress, taxIdType: string | null, taxId: string | null, by: string): Promise<Result<boolean>>;
632 /** Sends an enterprise its invoice now, for what its workspaces owe. */
633 invoiceEnterprise(id: string, by: string): Promise<Result<EnterpriseInvoice>>;
634 /** Exactly these workspaces' accounts, such as one page of the list. */
635 accountsFor(workspaces: string[]): Promise<AccountSummary[]>;
636 /** Every workspace worth reaching out to, most urgent first. */
637 signals(): Promise<Signal[]>;
638 /** The business at a glance. */
639 overview(): Promise<Overview>;
640 /** A workspace's sales record. */
641 sales(workspace: string): Promise<SalesRecord>;
642 setSales(workspace: string, record: { stage: string; owner?: string | null; nextStep?: string | null; nextAt?: string | null }, by: string): Promise<Result<SalesRecord>>;
643 addNote(workspace: string, text: string, by: string): Promise<Result<SalesRecord>>;
644 /** A workspace's invoices from g1t, for staff. */
645 workspaceInvoices(workspace: string): Promise<WorkspaceInvoice[]>;
646 /** Every invoice g1t has sent, newest first. */
647 allInvoices(filter?: { status?: string; month?: string }): Promise<InvoiceSummary[]>;
648 /** Every change made in sudo and by Stripe, newest first, 100 at a time. */
649 audit(filter?: { by?: string; action?: string; before?: string }): Promise<AdminAction[]>;
650 /** Limit and overage requests, with each workspace's history; `open` by default. */
651 limitRequests(status?: "open" | "approved" | "declined" | "all"): Promise<LimitRequestReview[]>;
652 /** Approve (at the amount asked, or another) or decline; the owner is told in the app and by email. */
653 decideLimitRequest(id: string, decision: "approve" | "decline", amountMicros: number | null, note: string, by: string): Promise<Result<LimitRequest>>;
654 /** The Overages queue. */
655 overages(): Promise<Overage[]>;
656 /** A goodwill credit; no amount is the one-click credit. Larger, or a second in 12 months, needs a reason. */
657 goodwill(workspace: string, amountMicros: number | null, reason: string, by: string, day?: string | null): Promise<Result<LedgerEntry>>;
658 /** Workspaces spending in the last day, fastest first. */
659 velocity(): Promise<Velocity[]>;
660 /** Money that reached g1t outside the card pages, such as a bank transfer: entered as a payment. */
661 recordPayment(workspace: string, amountMicros: number, reference: string, note: string, by: string): Promise<Result<LedgerEntry>>;
662 /** Costs & margin: Cloudflare's bill against what g1t charged, over the last `days` (7 to 90, 30 by default). */
663 costs(days?: number): Promise<CostsReport>;
664 /** The open margin alerts, for the banner on every page. */
665 costAlerts(): Promise<MarginAlert[]>;
666 /** g1t's own spend against its caps: the daily breaker and comped budgets. */
667 spendCaps(): Promise<SpendCaps>;
668 /** Lets compute start again for the rest of today (UTC) after the daily breaker; needs a note. */
669 liftBreaker(note: string, by: string): Promise<Result<SpendCaps>>;
670 /** Platform pauses, the last hour of platform usage, the month so far and the last day's breaches (billing's platform.rs). */
671 platformGuard(): Promise<PlatformGuard>;
672 /** Pauses or resumes one level across g1t; needs a note, recorded in the audit log. */
673 setPause(level: PauseLevel, paused: boolean, note: string, by: string): Promise<Result<PlatformGuard>>;
674 /** Approve or reject a price proposal; a rejection needs a note. An approved rise waits out the notice period. */
675 decideProposal(id: string, decision: "approve" | "reject", note: string, by: string): Promise<Result<PriceProposal>>;
676 setCostSettings(settings: CostSettings, by: string): Promise<Result<CostSettings>>;
677 setCostMapping(mapping: CostMappingInput, by: string): Promise<Result<CostMapping>>;
678 /** Reads Cloudflare's bill and reconciles now, as the daily run does. */
679 runCosts(by: string): Promise<Result<CostsRun>>;
680}
681
682/** How much a workspace has earned g1t's trust with money. */
683export type Trust = "new" | "paid" | "established" | "reviewed" | "internal";
684
685/**
686 * How far a workspace's unpaid usage has gone this month, and where its
687 * work stops: past `ceilingMicros`, no new sandboxes, builds or app
688 * requests. Usage counts at its cost to g1t or its charge, whichever is
689 * more, so it counts while g1t is free too.
690 */
691export type Limit = {
692 workspace: string;
693 /** The account that pays: the workspace's own (`ws_<slug>`), or its enterprise's. */
694 account: string;
695 accountName: string;
696 trust: Trust;
697 exposureMicros: number;
698 /** The lower of g1t's ceiling and the owner's spend limit; null for g1t's own. */
699 ceilingMicros: number | null;
700 trustCeilingMicros: number | null;
701 spendLimitMicros: number | null;
702 state: "ok" | "warning" | "stopped";
703 message: string | null;
704 /**
705 * Charged this month, which the spend limit is measured against: usage at
706 * price less the discount, included usage, the trial, pools and credit,
707 * with usage metered through the month counted on the same terms. The
708 * same number as the month's `UsageTotals.chargedMicros`.
709 */
710 spentMicros?: number;
711 /** True while the owners have not chosen a limit, so the automatic one applies: $200, or twice last month's spend. */
712 defaultSpendLimit?: boolean;
713 /** The most owners may set their own limit to without asking: the highest ceiling ever, plus what is prepaid. */
714 availableMicros?: number | null;
715 /** How the ceiling grows from here, in a sentence. */
716 growth?: string | null;
717 /** Paid in advance and not used yet; raises what can be used before work stops by as much. */
718 prepaidMicros?: number;
719 /** The highest ceiling the workspace has had. */
720 maxCeilingMicros?: number | null;
721 /** The most owners may raise the limit to themselves, once: twice the highest ceiling. Null once used. */
722 raiseOnceMicros?: number | null;
723 /** When the one-time raise was used. */
724 raisedAt?: string | null;
725 /** A paid workspace's first billing cycle, on the starting ceiling. */
726 firstMonth?: boolean;
727 /** The budget's alerts, in percent of the spend limit: some of 50, 75, 90 and 100. */
728 alertLevels?: number[];
729 /** Whether usage pauses at the spend limit (the default); off, it only alerts. */
730 pauseAtLimit?: boolean;
731 /** An HTTPS address told of each budget alert. */
732 budgetWebhook?: string | null;
733};
734
735/** One metered unit: what it costs g1t and what it is sold at; the price follows the cost. */
736export type Price = {
737 meter:
738 | "sandbox_second"
739 | "build_second"
740 | "app_requests"
741 | "app_cpu"
742 | "app_month"
743 | "custom_domain_month"
744 | "private_storage"
745 | "embedding_tokens"
746 | "scan_cpu"
747 | "scan_rows"
748 | string;
749 title: string;
750 unit: string;
751 costMicros: number;
752 markupPercent: number;
753 priceMicros: number;
754 /** `list`: Cloudflare's published price. `cloudflare`: measured from Cloudflare's bill. */
755 source: "list" | "cloudflare" | string;
756 checkedAt: string | null;
757 updatedAt: string;
758};
759
760export type PriceChange = {
761 meter: string;
762 oldCostMicros: number;
763 newCostMicros: number;
764 markupPercent: number;
765 /** The markup before, when the change was to the markup rather than the cost. */
766 oldMarkupPercent?: number;
767 reason: string;
768 createdAt: string;
769 /** When a change still to come takes effect: a rise is announced before it is charged. */
770 effectiveAt?: string;
771};
772
773export type PriceBook = {
774 prices: Price[];
775 changes: PriceChange[];
776 modelMarginPercent: number;
777 /** Every plan, as sold now. */
778 plans?: FeaturePlan[];
779 /** What is free, and the capped budgets that pay for it. */
780 free?: FreeTier | null;
781};
782
783/** One kind of meter's usage this month, from `usage_meters`. */
784export type MeterUsage = {
785 /** `agents`, `builds`, `requests`, `domains`, `git_storage` or `search_scans`. */
786 key: string;
787 label: string;
788 /** At price (cost plus 20%, on the account's terms), before what paid for it. */
789 micros: number;
790 /** How much, when it is known: `12 runs`, `41 build minutes`. */
791 quantity?: string | null;
792};
793
794/** What g1t gives without a plan; each is paid for by a capped budget. */
795export type FreeTier = {
796 /** Each new workspace's trial credit, once. */
797 trialWorkspaceMicros: number;
798 /** Trial grants each month, in all; new trials wait when it is spent. */
799 trialMonthlyPoolMicros: number;
800 /** g1t's open-source pool each month, and any one repository's share. */
801 ossPoolMicros: number;
802 ossRepoMicros: number;
803 /** Private repository storage free for every workspace. Past it, the plan pays; a free workspace's pushes stop. */
804 freePrivateStorageBytes: number;
805 /** Days of audit log a free workspace keeps. */
806 auditRetentionDays: number;
807 /** Days of audit log the g1t plan keeps, and g1t's own and enterprise workspaces; longer by arrangement. */
808 planAuditRetentionDays?: number;
809 /** The smallest amount a card is charged when a month closes; less carries over. */
810 minChargeMicros: number;
811 /** Git operations free for every workspace each month. Past it, the plan pays; a free workspace is slowed down. */
812 gitOperationsIncluded?: number;
813 /** A new paid workspace's ceiling in its first month. */
814 paidStartCeilingMicros?: number;
815 /** The most a one-click goodwill credit can cost g1t. */
816 overageForgiveCostMicros?: number;
817};
818
819/**
820 * A workspace's trial credit: one grant per workspace, made the first time
821 * it uses something, out of a pool that resets each calendar month. Mirrors
822 * `Trial` in `crates/contracts/src/billing.rs`.
823 */
824export type Trial = {
825 open: boolean;
826 usedMicros: number;
827 limitMicros: number;
828 /** No longer used: trials do not end on a date. */
829 endsAt: string | null;
830 /** Why it is closed: `off`, `used` (this workspace's grant is spent) or `pool` (this month's are given out). */
831 reason: "off" | "ended" | "used" | "pool" | null;
832 /** Whether the workspace has its grant already. */
833 granted?: boolean;
834 /** With `pool`: when new trials start again, the first of next month. */
835 waitsUntil?: string | null;
836};
837
838/**
839 * What a workspace has: the g1t plan (`plan`), and Security and quality
840 * (`security`), which comes with the plan at no price of its own. Deployments
841 * are part of the plan too; `has_feature` for either answers whether the
842 * workspace has the plan. Mirrors `Feature` in `crates/contracts/src/billing.rs`.
843 */
844export type Feature = "plan" | "deployments" | "security";
845
846/**
847 * What deployments cost g1t, in millionths of a dollar: fallbacks for when
848 * billing's price book cannot be read. Not an allowance: on the plan every
849 * unit is metered from the first, at cost plus 20%, and drawn from the
850 * plan's included usage first. Projects, previews and the apps behind them
851 * are not metered at all. Mirrors `deployment_costs`.
852 */
853export const DEPLOYMENT_COSTS = {
854 microsPerMillionRequests: 300_000,
855 microsPerMillionCpuMs: 20_000,
856 /** One second of a build's sandbox: a fallback; billing charges the price book's `build_second`. */
857 microsPerBuildSecond: 15,
858 /** One custom domain for a month. */
859 microsPerDomainMonth: 100_000,
860 /**
861 * Container apps, at Cloudflare Containers' list prices: a vCPU-second
862 * $0.00002, a GiB-second of memory $0.0000025, a GB-second of disk
863 * $0.00000007, the Durable Object in front of each instance while it
864 * runs (128 MB at $12.50 per million GB-seconds), and a GB of egress
865 * at $0.05, the most Cloudflare charges for one anywhere (Oceania, Korea
866 * and Taiwan; $0.025 in North America and Europe), since g1t cannot
867 * tell where a container's traffic went.
868 */
869 container: {
870 vcpuSecond: 20,
871 memoryGibSecond: 2.5,
872 diskGbSecond: 0.07,
873 instanceSecond: 1.5625,
874 egressGb: 50_000,
875 },
876} as const;
877
878export type FeaturePlan = {
879 feature: Feature;
880 title: string;
881 /** Charged every month while the plan is on, in cents, excluding tax. */
882 monthlyCents: number;
883 /** The card processing fee on top each month, in cents (0 when off), excluding tax. */
884 cardFeeCents?: number;
885 /** What the price includes, one line each. */
886 includes: string[];
887 /** How usage past the allowance is charged. */
888 overage: string;
889};
890
891export type SubscriptionStatus = "active" | "canceling" | "past_due" | "canceled";
892
893export type Subscription = {
894 feature: Feature;
895 status: SubscriptionStatus;
896 /** RFC 3339: when the period paid for ends. */
897 periodEnd: string | null;
898 startedBy: string;
899 startedAt: string;
900};
901
902/** A feature as a workspace sees it. */
903export type FeatureState = {
904 plan: FeaturePlan;
905 subscription: Subscription | null;
906 /** Whether the feature works for the workspace now. */
907 on: boolean;
908 /** On without a plan: comped terms, or given by g1t. Nothing to pay or turn off. */
909 included?: boolean;
910};
911
912export interface BillingApi {
913 status(): Promise<BillingStatus>;
914 /** Members of the workspace only. */
915 account(workspace: string, viewer: Viewer): Promise<Result<BillingAccount>>;
916 /** Newest first. Members of the workspace only. */
917 ledger(workspace: string, viewer: Viewer): Promise<Result<LedgerEntry[]>>;
918 /** Credits from g1t, newest first, with what is left of each. Members only. */
919 credits(workspace: string, viewer: Viewer): Promise<Result<Credits>>;
920 /** A month of the ledger, grouped by `day` (default) or `project`. Members only. */
921 statement(workspace: string, viewer: Viewer, month?: string | null, group?: "day" | "project"): Promise<Result<Statement>>;
922 /** One statement line's entries, 50 at a time; `before` is the last id seen. */
923 statementEntries(
924 workspace: string,
925 viewer: Viewer,
926 filter: { month: string; kind: string; day?: string | null; project?: string | null; before?: string | null },
927 ): Promise<Result<LedgerEntry[]>>;
928 /** What the workspace's agents cost since `since`, broken down. Members only. */
929 usage(workspace: string, viewer: Viewer, since: string): Promise<Result<Usage>>;
930 /**
931 * Prepays usage ($25 at least) and returns the page to send the person to:
932 * by card with 3-D Secure, or by bank transfer from $1,000. Owners only.
933 * The payment's id comes back to `returnUrl` as `session`.
934 */
935 checkout(
936 actor: User,
937 workspace: string,
938 amountCents: number,
939 returnUrl: string,
940 method?: "card" | "bank_transfer",
941 ): Promise<Result<{ url: string }>>;
942 /**
943 * Stripe's hosted billing page for the workspace: card, invoices, billing
944 * email and address. g1t never handles card numbers. Owners only.
945 */
946 billingPortal(actor: User, workspace: string, returnUrl: string): Promise<Result<{ url: string }>>;
947 /** Credits a payment once the processor says it was made. Safe to repeat. */
948 confirm(workspace: string, viewer: Viewer, session: string): Promise<Result<BillingAccount>>;
949 /** A workspace's free trial allowance; `exempt` workspaces are open anyway. */
950 trial(workspace: string, exempt: string[]): Promise<Trial>;
951 /** Every paid feature and the workspace's plan for each. Members only. */
952 features(workspace: string, viewer: Viewer): Promise<Result<FeatureState[]>>;
953 /**
954 * Starts the card page for a feature's monthly plan. Owners only. The
955 * page's id comes back to `returnUrl` as `session`.
956 */
957 subscribe(actor: User, workspace: string, feature: Feature, returnUrl: string): Promise<Result<{ url: string }>>;
958 /** Turns the feature on once the plan is paid for. Safe to repeat. */
959 confirmSubscription(workspace: string, viewer: Viewer, session: string): Promise<Result<FeatureState>>;
960 /** Ends a plan at the end of its period, or (`resume`) takes that back. Owners only. */
961 cancelSubscription(actor: User, workspace: string, feature: Feature, resume?: boolean): Promise<Result<FeatureState>>;
962 /** Which of the workspaces are free (on no paid plan); none where payments are not set up. */
963 freeWorkspaces(workspaces: string[]): Promise<string[]>;
964 /** Whether a feature works for a workspace now; a failure with the reason when not. */
965 hasFeature(workspace: string, feature: Feature): Promise<Result<boolean>>;
966 /**
967 * Usage past a plan's allowance, charged from credit at cost plus the
968 * margin, once per `reference`. False if it was charged before.
969 */
970 chargeFeature(charge: {
971 workspace: string;
972 feature: Feature;
973 costMicros: number;
974 description: string;
975 repo?: string | null;
976 reference: string;
977 /** For a build: how long it ran, so the plan's included build time pays for what it can. */
978 buildSeconds?: number | null;
979 }): Promise<Result<boolean>>;
980 /**
981 * What a source cost g1t so far this month, so the workspace's limit
982 * counts it now. Replaces the last report. Billing charges `context`
983 * and `security` itself once the month is over; `deployments` charges
984 * its own.
985 */
986 notePending(
987 workspace: string,
988 source: "deployments" | "domains" | "context" | "security",
989 costMicros: number,
990 /** How much of it, for the Billing page: `1.2 million requests and 3.4 million CPU ms`. */
991 detail?: string | null,
992 ): Promise<boolean>;
993 /**
994 * This month's usage, one line per kind of meter, at what it is charged
995 * before the plan's included usage or a pool paid for it. Members only.
996 */
997 usageMeters(workspace: string, viewer: Viewer): Promise<Result<MeterUsage[]>>;
998 /** What the workspace may do now: its plan, caps, pause, trial, and what the plan gives it. */
999 entitlements(workspace: string): Promise<Entitlements>;
1000 /**
1001 * Holds a start's estimated cost before the work starts. A failure's code says why not:
1002 * `paused`, `limit`, `not_paid`, `trial_used` or `oss_pool_empty`, with a message for the owner.
1003 */
1004 reserve(reservation: {
1005 workspace: string;
1006 repo: RepoPath;
1007 public: boolean;
1008 kind: ComputeKind;
1009 /** The most the work is expected to cost g1t, before the margin. */
1010 estimateMicros: number;
1011 }): Promise<Result<ReservationHeld>>;
1012 /** Releases a reservation's hold with what the work cost g1t, before the margin. Safe to repeat. */
1013 settle(reservationId: string, actualMicros: number): Promise<Result<boolean>>;
1014 /** Stripe's page to save and verify a card (3-D Secure, never charged). Owners only. */
1015 cardCheck(actor: User, workspace: string, returnUrl: string): Promise<Result<{ url: string }>>;
1016 /** Records the card check once Stripe says it passed, and grants the trial if it can. Safe to repeat. */
1017 confirmCardCheck(workspace: string, viewer: Viewer, session: string): Promise<Result<Entitlements>>;
1018 /** An owner asks for a higher limit, or for help with usage past what was meant. */
1019 requestLimit(
1020 actor: User,
1021 workspace: string,
1022 request: { kind: "limit" | "overage"; amountMicros: number; reason: string; expectedMonthlyMicros: number },
1023 ): Promise<Result<LimitRequest>>;
1024 /** The workspace's requests and their answers, newest first. Members only. */
1025 limitRequests(workspace: string, viewer: Viewer): Promise<Result<LimitRequest[]>>;
1026 /**
1027 * The owners' own caps on agents: one run's spend ($0.10 to $100) and one issue's ($1 to $1,000).
1028 * Null goes back to the default ($2 and $10). A cap staff set wins. Owners only.
1029 */
1030 setCaps(actor: User, workspace: string, caps: { runCapMicros: number | null; issueCapMicros: number | null }): Promise<Result<Entitlements>>;
1031 /** An owner's answer to a spend spike: keep going for 24 hours, or stop. */
1032 confirmSpike(actor: User, workspace: string, keepGoing: boolean): Promise<Result<Entitlements>>;
1033 /** Every metered price and the recent changes. Public. */
1034 prices(): Promise<PriceBook>;
1035 /** A workspace's limit, for its members. */
1036 limit(workspace: string, viewer: Viewer): Promise<Result<Limit>>;
1037 /** The same, for the services that enforce it. */
1038 checkLimit(workspace: string): Promise<Result<Limit>>;
1039 /**
1040 * The owners' own monthly limit, up to what is available; null goes back
1041 * to the default, and `useFullLimit` uses everything available. Owners only.
1042 */
1043 setSpendLimit(
1044 actor: User,
1045 workspace: string,
1046 spendLimitMicros: number | null,
1047 useFullLimit?: boolean,
1048 /** Use the one-time raise: up to twice the highest ceiling, once per workspace. */
1049 raiseOnce?: boolean,
1050 ): Promise<Result<Limit>>;
1051 /** The workspace's invoices from g1t, newest first. Members only. */
1052 invoices(workspace: string, viewer: Viewer): Promise<Result<WorkspaceInvoice[]>>;
1053 /**
1054 * How long a sandbox ran for a workspace, reported when it stops. Its
1055 * cost is recorded and every second is charged, from the first. False if
1056 * `reference` was recorded before.
1057 */
1058 recordSandbox(usage: {
1059 workspace: string;
1060 seconds: number;
1061 description: string;
1062 repo?: string | null;
1063 reference: string;
1064 /** What ran; checks, workflows and the merge queue on public repositories may use the open-source pool. */
1065 kind?: ComputeKind | null;
1066 /** vCPU-seconds used, when the sandbox can tell: the run is priced on its own CPU. */
1067 cpuSeconds?: number | null;
1068 /** The reservation it started under, settled with this cost. */
1069 reservationId?: string | null;
1070 /** It ran on one of the workspace's self-hosted runners: its minutes go on usage at $0. */
1071 selfHosted?: boolean;
1072 /** The machine it ran on, by label (`g1t-4core`); absent, the standard one. */
1073 instance?: string | null;
1074 }): Promise<Result<boolean>>;
1075 /** Usage over a range of days (`YYYY-MM-DD`, both included), at price, by product, meter, project and day. Members only. */
1076 usageReport(
1077 workspace: string,
1078 viewer: Viewer,
1079 range: { from: string; until: string; products?: string[]; projects?: string[] },
1080 ): Promise<Result<UsageReport>>;
1081 /** The monthly budget: the spend limit, its alerts, whether usage pauses at 100%, and a webhook. Owners only. */
1082 setBudget(
1083 actor: User,
1084 workspace: string,
1085 budget: { amountMicros: number | null; alerts: number[]; pauseAtLimit: boolean; webhook: string | null; keepLimit?: boolean },
1086 ): Promise<Result<Limit>>;
1087 /** Invoice details from the Stripe customer, the default payment method, invoices and the next invoice. Members only. */
1088 billingDetails(workspace: string, viewer: Viewer): Promise<Result<BillingDetails>>;
1089 /** Saves invoice details on the Stripe customer; absent fields stay, empty clears. Owners only. */
1090 setBillingDetails(actor: User, workspace: string, details: BillingDetailsInput): Promise<Result<BillingDetails>>;
1091}
1092
1093
1094/** One slice of usage: what it was for, what it cost, how many runs. */
1095export type UsageSlice = { key: string; micros: number; runs: number };
1096
1097/** What a workspace's agents cost over a period. */
1098export type Usage = {
1099 since: string;
1100 /** Charged, including g1t's margin. */
1101 spentMicros: number;
1102 /** 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. */
1103 coveredMicros?: number;
1104 /** What the account's discount took off the price; usage at price is spent + covered + this. */
1105 discountMicros?: number;
1106 /** The account's discount now, in percent; with one, the slices are at price. */
1107 discountPercent?: number | null;
1108 /** Usage at price: spent + covered + discount, from the same ledger lines. The one usage figure every page shows. */
1109 priceMicros?: number;
1110 /** What g1t's model provider charged, before the margin. */
1111 costMicros: number;
1112 /** What runs on the workspace's own provider cost there, estimated. Not charged by g1t. */
1113 providerMicros: number;
1114 /** What the runs used, at cost: g1t's models and the workspace's own provider together. */
1115 usedMicros: number;
1116 /** g1t charges nothing for now; the slices then measure usage at cost. */
1117 free: boolean;
1118 runs: number;
1119 /** Spend per day and task, keyed `YYYY-MM-DD/task`. */
1120 byDay: UsageSlice[];
1121 byTask: UsageSlice[];
1122 byRepo: UsageSlice[];
1123 /** Keyed `namespace/name#number`. */
1124 byPull: UsageSlice[];
1125 byModel: UsageSlice[];
1126 /** Credit bought in the period. */
1127 addedMicros: number;
1128};
1129
1130/** One of g1t's products (a "bucket") on one day. Money in micros. */
1131export type CostDay = { day: string; bucket: string; cfCostMicros: number; ownCostMicros: number; valueMicros: number; cashMicros: number };
1132
1133/** One product over the range: what customers were charged at price against what it cost. */
1134export type ProductMargin = {
1135 bucket: string;
1136 title: string;
1137 /** Cloudflare's bill, or g1t's own figure where Cloudflare does not bill it (`costSource`). */
1138 costMicros: number;
1139 cfCostMicros: number;
1140 ownCostMicros: number;
1141 valueMicros: number;
1142 marginMicros: number;
1143 marginPercent: number | null;
1144 costSource: "cloudflare" | "ledger" | string;
1145 /** Running g1t, paid for by the plan. */
1146 overhead: boolean;
1147};
1148
1149/** All of g1t: money in (usage and the plan) against every cost. */
1150export type OverallMargin = {
1151 usageMicros: number;
1152 plansMicros: number;
1153 costMicros: number;
1154 marginMicros: number;
1155 marginPercent: number | null;
1156 /** Of costMicros, what went on usage g1t gave away on purpose: comped workspaces, free periods, the trial and the open-source pool. */
1157 givenMicros?: number;
1158 /** Money in against costMicros - givenMicros. */
1159 soldMarginMicros?: number;
1160 soldMarginPercent?: number | null;
1161 /** Usage sold: usageMicros against what that usage cost, less what was given. */
1162 usageCostMicros?: number;
1163 usageMarginMicros?: number;
1164 usageMarginPercent?: number | null;
1165 /** Running g1t: plansMicros against the platform's cost, less its given share. */
1166 runningCostMicros?: number;
1167 /** Cost no mapping names, less its given share. */
1168 unmappedCostMicros?: number;
1169 /** givenMicros by why. Free is free periods, free allowances and overruns g1t covered. */
1170 givenCompedMicros?: number;
1171 givenFreeMicros?: number;
1172 givenTrialMicros?: number;
1173 givenPoolMicros?: number;
1174 /** What discounts on an account's terms took below cost plus the margin: given, not margin lost. */
1175 givenDiscountMicros?: number;
1176 /** Credits from g1t spent on usage, by kind: given, never money in. Refunds come off money in instead. */
1177 givenCreditPromotionalMicros?: number;
1178 givenCreditGoodwillMicros?: number;
1179 /** What testing resets wiped that g1t paid for: the usage still happened, so its cost is given, never a leak. */
1180 givenResetMicros?: number;
1181 /** Credits over the range: given (every kind), spent on usage, and refunds' money given back. */
1182 creditsGivenMicros?: number;
1183 creditsUsedMicros?: number;
1184 creditsRefundedMicros?: number;
1185 /** costMicros by who g1t pays: Cloudflare's bill (billed, after included allowances) and model providers (tokens, not on Cloudflare's bill). */
1186 /** What the plan's included usage paid for, at price: money in for usage, paid out of plansMicros. */
1187 includedMicros?: number;
1188 cloudflareCostMicros?: number;
1189 modelsCostMicros?: number;
1190 /** Tax collected with payments over the range, net of refunds: owed to tax authorities, never cash or revenue. */
1191 taxCollectedMicros?: number;
1192 /** Card processing fees passed on with card payments, net of refunds: they pay Stripe's fee, not revenue. */
1193 cardFeesMicros?: number;
1194 /** What workspaces were charged while payments were not live (Stripe's test mode): given, never money in. */
1195 givenUnpaidMicros?: number;
1196 /** Cloudflare's subscriptions over the range: each day's share of the billing cycle it is in. */
1197 subscriptionsMicros?: number;
1198 /** What AI Gateway priced g1t's own provider traffic at over the range, beside the ledger's model cost. */
1199 gatewayCostMicros?: number;
1200};
1201
1202/** A count, cost or leak that does not add up. */
1203export type CostDrift = {
1204 bucket: string;
1205 title: string;
1206 kind: "count" | "cost" | "leak" | string;
1207 ours: number;
1208 cloudflare: number;
1209 deltaPercent: number | null;
1210 detail: string;
1211 foundAt: string;
1212};
1213
1214export type MarginAlert = {
1215 id: string;
1216 kind: "margin" | "overall" | "leak" | "drift" | "workspace" | string;
1217 /** The product, or the workspace. */
1218 subject: string;
1219 detail: string;
1220 since: string;
1221 openedAt: string;
1222 emailedAt: string | null;
1223};
1224
1225/** A change to a price, measured from what Cloudflare charged. */
1226export type PriceProposal = {
1227 id: string;
1228 meter: string;
1229 title: string;
1230 unit: string;
1231 currentCostMicros: number;
1232 proposedCostMicros: number;
1233 changePercent: number;
1234 markupPercent: number;
1235 reason: string;
1236 source: "keeper" | "reconciler" | string;
1237 /** Far off the current cost: look before approving. */
1238 suspect: boolean;
1239 status: "open" | "applied" | "approved" | "rejected" | "superseded" | string;
1240 createdAt: string;
1241 decidedAt: string | null;
1242 decidedBy: string | null;
1243 note: string | null;
1244 effectiveAt: string | null;
1245};
1246
1247/** One version of one meter's price; never changed once written. */
1248export type PriceVersion = {
1249 id: string;
1250 meter: string;
1251 version: number;
1252 costMicros: number;
1253 markupPercent: number;
1254 priceMicros: number;
1255 effectiveAt: string;
1256 reason: string;
1257 createdBy: string;
1258 appliedAt: string | null;
1259 /**
1260 * What `costMicros` is: `cost`, what g1t pays for a unit; `rate`, a price
1261 * g1t sets with no cost behind it (the agent rate), so it is no cost;
1262 * `weight`, a multiplier in millionths, not money. Absent from older
1263 * billing: read as `cost`.
1264 */
1265 basis?: "cost" | "rate" | "weight" | "";
1266};
1267
1268/** What `resetBilling` removed. */
1269export type BillingReset = { workspace: string; rows: number; refreshed?: boolean };
1270
1271export type WorkspaceCost = { workspace: string; costMicros: number; revenueMicros: number; givenMicros?: number; internal: boolean };
1272
1273export type CostLineSummary = {
1274 product: string;
1275 meter: string;
1276 rawName: string;
1277 unit: string;
1278 source: string;
1279 quantity: number;
1280 costMicros: number;
1281 /** Absent when no mapping claims it. */
1282 bucket: string | null;
1283};
1284
1285export type CostMapping = {
1286 product: string;
1287 meter: string;
1288 bucket: string;
1289 priceMeter: string | null;
1290 ownMeter: string | null;
1291 scaleToOwn: boolean;
1292 driftPercent: number;
1293 note: string;
1294 updatedAt: string;
1295 updatedBy: string;
1296};
1297
1298export type CostMappingInput = {
1299 product: string;
1300 meter: string;
1301 bucket?: string;
1302 priceMeter?: string | null;
1303 ownMeter?: string | null;
1304 scaleToOwn?: boolean;
1305 driftPercent?: number | null;
1306 note?: string;
1307 remove?: boolean;
1308};
1309
1310export type CostSettings = {
1311 autoApply: boolean;
1312 autoApplyPercent: number;
1313 noticeDays: number;
1314 marginFloorPercent: number;
1315 alertDays: number;
1316 minDailyCostMicros: number;
1317 anomalyFactor: number;
1318 anomalyFloorMicros: number;
1319 /** Pass Stripe's card fee on as its own line when AI credit is bought by card. */
1320 cardFee: boolean;
1321};
1322
1323export type CostsReport = {
1324 configured: boolean;
1325 fetchedAt: string | null;
1326 since: string;
1327 until: string;
1328 days: CostDay[];
1329 products: ProductMargin[];
1330 overall: OverallMargin;
1331 drift: CostDrift[];
1332 alerts: MarginAlert[];
1333 proposals: PriceProposal[];
1334 versions: PriceVersion[];
1335 topWorkspaces: WorkspaceCost[];
1336 lines: CostLineSummary[];
1337 mappings: CostMapping[];
1338 settings: CostSettings;
1339 /** g1t's own spend against its two caps. */
1340 caps: SpendCaps;
1341 /** Cloudflare's current billing cycle: usage cost so far by meter, and the projection. Absent until the bill is read. */
1342 cycle?: CloudflareCycle | null;
1343 /** The last read of Cloudflare's billable usage: what came back. */
1344 billRead?: BillRead | null;
1345 /** Of the range's cost, what no workspace's usage could carry: running g1t, attributed to no one. */
1346 unattributedMicros?: number;
1347};
1348
1349/** Cloudflare's billing cycle, as its Billable usage page shows it. */
1350export type CloudflareCycle = {
1351 /** First and last days, YYYY-MM-DD, UTC. */
1352 start: string;
1353 end: string;
1354 days: number;
1355 /** Days from its start to today, today included. */
1356 daysElapsed: number;
1357 /** Usage cost so far, after the included allowances. */
1358 usageMicros: number;
1359 /** usageMicros over the days elapsed, times the cycle's days. */
1360 projectedMicros: number;
1361 averageDailyMicros: number;
1362 /** Cloudflare's subscriptions for the cycle (not on the usage bill). */
1363 subscriptionsMicros: number;
1364 meters: CycleMeter[];
1365};
1366
1367/** One of Cloudflare's meters over the cycle so far. */
1368export type CycleMeter = {
1369 product: string;
1370 meter: string;
1371 rawName: string;
1372 unit: string;
1373 quantity: number;
1374 /** What the cycle includes; null without a list price. */
1375 included: number | null;
1376 billableQuantity: number;
1377 costMicros: number;
1378 /** cloudflare: Cloudflare's own cost; list: the list price past the included amount; none: no list price known. */
1379 basis: "cloudflare" | "list" | "none" | string;
1380};
1381
1382/** What the last read of Cloudflare's billable usage got back. */
1383export type BillRead = {
1384 readAt: string;
1385 since: string;
1386 until: string;
1387 rows: number;
1388 pages: number;
1389 consumedRows: number;
1390 pricingOnlyRows: number;
1391 costedRows: number;
1392};
1393
1394/** One level of the platform pause, as sudo shows it. Snake case, as billing sends it. */
1395export type PauseState = {
1396 level: PauseLevel;
1397 paused: boolean;
1398 note: string | null;
1399 set_by: string | null;
1400 set_at: string | null;
1401 /** Set by billing's usage watcher, not a person. */
1402 auto: boolean;
1403};
1404
1405/** One platform metric over an hour or the month so far. */
1406export type PlatformMetric = {
1407 metric: string;
1408 title: string;
1409 value: number;
1410 /** Its hourly threshold (`PLATFORM_HOURLY_*`); 0: none. */
1411 threshold: number;
1412 /** The script, queue, database or namespace that counted most. */
1413 top_name: string | null;
1414 top_value: number | null;
1415};
1416
1417/** A breach billing's usage watcher found. */
1418export type PlatformBreach = {
1419 id: string;
1420 metric: string;
1421 hour: string;
1422 rule: "threshold" | "spike";
1423 value: number;
1424 threshold: number;
1425 severe: boolean;
1426 top_name: string | null;
1427 detail: string;
1428 /** Levels it paused. */
1429 paused: PauseLevel[];
1430 opened_at: string;
1431 emailed_at: string | null;
1432};
1433
1434/** Billing's `admin_platform_guard`: the platform pause and usage watcher
1435 * (docs.g1t.sh/guides/deploy-to-cloudflare/#spend-guardrails). */
1436export type PlatformGuard = {
1437 levels: PauseState[];
1438 /** The last hour read, `YYYY-MM-DDTHH:00:00Z`. */
1439 hour: string | null;
1440 last_hour: PlatformMetric[];
1441 month: string;
1442 month_to_date: PlatformMetric[];
1443 breaches: PlatformBreach[];
1444 /** Whether billing can read Cloudflare's analytics. */
1445 can_read: boolean;
1446 /** `AUTO_PAUSE`: the levels a severe breach may pause. */
1447 auto_pause: PauseLevel[];
1448 /** What the latest run could not see: each query that failed, with its error. */
1449 blind?: { key: string; dataset: string; error: string }[];
1450 /** The latest run found every dataset empty: the wrong account, or a token that cannot see it. */
1451 empty?: boolean;
1452 /** The hour the latest run read. */
1453 last_run?: string | null;
1454};
1455
1456/** What g1t pays for itself, at cost, against its caps (billing's `budget`). */
1457export type SpendCaps = {
1458 /** Today (UTC), YYYY-MM-DD, and this month, YYYY-MM. */
1459 day: string;
1460 month: string;
1461 /** What g1t paid for itself today across every workspace. */
1462 todayMicros: number;
1463 /** `PLATFORM_DAILY_SPEND_CAP_MICROS`; 0: no breaker. */
1464 dailyCapMicros: number;
1465 /** New hosted-model agent runs g1t would pay for are paused. */
1466 tripped: boolean;
1467 trippedAt: string | null;
1468 liftedBy: string | null;
1469 liftedAt: string | null;
1470 liftNote: string | null;
1471 /** This month so far, by what paid: comped, trial, oss, given, unpaid. */
1472 monthBuckets: { bucket: string; title: string; micros: number }[];
1473 comped: CompedBudget[];
1474 /** Free workspaces' share of reconciled costs this month (git, storage, platform). */
1475 freeTierMicros: number;
1476 /** Cloudflare's subscriptions a month: read from Cloudflare each day, else `CLOUDFLARE_FIXED_MONTHLY_MICROS`, an estimate. */
1477 fixedMonthlyMicros: number;
1478 fixedSource?: "cloudflare" | "estimate" | string;
1479 fixedReadAt?: string | null;
1480 /** Each subscription, when read from Cloudflare. */
1481 fixedItems?: { name: string; monthlyMicros: number }[];
1482 /** Of fixedMonthlyMicros, this calendar month's days so far, each at its billing cycle's daily share. */
1483 fixedMonthMicros?: number;
1484 /** Money in this month, through the last reconciled day. */
1485 revenueMicros: number;
1486 /**
1487 * Of this month's buckets, what was spent on workspaces whose billing a
1488 * testing reset later wiped (still g1t's spend; the reconciled figures
1489 * have it only where the reset kept it), and those workspaces.
1490 */
1491 resetMicros?: number;
1492 resetWorkspaces?: string[];
1493};
1494
1495/** A comped account's monthly budget, at cost. */
1496export type CompedBudget = {
1497 account: string;
1498 name: string;
1499 usedMicros: number;
1500 /** 0: no budget. */
1501 ceilingMicros: number;
1502 /** `COMPED_MONTHLY_CEILING_MICROS`, not the account's own limit. */
1503 defaultCeiling: boolean;
1504 /** 50, 75, 90, 100, or 0. */
1505 level: number;
1506};
1507
1508export type CostsRun = { lines: number; days: number; proposals: number; alerts: number; problems: string[] };
1509
1510/** The product families the Usage page groups meters into, in order. */
1511export const PRODUCTS = [
1512 { key: "sandboxes", label: "Sandboxes" },
1513 { key: "deployments", label: "Deployments" },
1514 { key: "git_storage", label: "Git & storage" },
1515 { key: "packages", label: "Packages" },
1516 { key: "security", label: "Security & quality" },
1517 { key: "search", label: "Search" },
1518] as const;
1519
1520export type ProductKey = (typeof PRODUCTS)[number]["key"];
1521
1522/** What usage came to over a range, and what paid for it: price − discount − included − credits = charged. */
1523export type UsageTotals = {
1524 /** Usage at price, pending usage included. */
1525 priceMicros: number;
1526 discountMicros: number;
1527 /** Paid by the plan's included usage, the trial and g1t's pools. */
1528 includedMicros: number;
1529 /** Paid by AI credit and credit from g1t. */
1530 creditsMicros: number;
1531 /** Left for the workspace to pay. */
1532 chargedMicros: number;
1533 /** Metered this month, charged when it closes. */
1534 pendingMicros: number;
1535 /** What of `pendingMicros` will be charged at the close, after the discount and what g1t covers; absent from an older billing. */
1536 pendingChargedMicros?: number;
1537 costMicros: number;
1538};
1539
1540export type UsageDay = { day: string; product: string; micros: number };
1541
1542/** One agent's (by handle) or one person's (by username) share of the agent product, at price; an empty key for lines attributed to no one. */
1543
1544export type UsageAllowance = { used: number; of: number; unit: string };
1545
1546export type ProjectUsage = { project: string; micros: number; quantity: number };
1547
1548/** One meter over a range. */
1549export type MeterLine = {
1550 key: string;
1551 label: string;
1552 product: string;
1553 /** `tokens`, `seconds`, `bytes`, `operations`, `requests` or `entries`. */
1554 unit: string;
1555 quantity: number;
1556 micros: number;
1557 pendingMicros?: number;
1558 /** Every day of the range, oldest first, at price. */
1559 daily: number[];
1560 allowance?: UsageAllowance | null;
1561 byProject: ProjectUsage[];
1562 /** How the quantity is counted, when that needs saying (the agent rate's token weights). */
1563 note?: string | null;
1564};
1565
1566export type ProductUsage = { key: string; label: string; micros: number; meters: MeterLine[] };
1567
1568export type UsageReport = {
1569 from: string;
1570 until: string;
1571 totals: UsageTotals;
1572 days: UsageDay[];
1573 products: ProductUsage[];
1574 projects: string[];
1575 /** The plan's included usage this month, in micros. */
1576 included?: UsageAllowance | null;
1577 discountPercent?: number | null;
1578 /** AI credit bought before g1t stopped selling it, left now; kept apart from credit for everything. */
1579 aiCreditMicros: number;
1580 creditMicros: number;
1581 trialMicros?: number | null;
1582 plan: PlanKind;
1583 free: boolean;
1584};
1585
1586export type PostalAddress = { line1: string; line2: string; city: string; state: string; postalCode: string; country: string };
1587
1588export type PaymentMethod = {
1589 kind: string;
1590 brand?: string | null;
1591 last4?: string | null;
1592 expMonth?: number | null;
1593 expYear?: number | null;
1594};
1595
1596export type StripeInvoice = {
1597 id: string;
1598 number?: string | null;
1599 status: string;
1600 totalCents: number;
1601 currency: string;
1602 createdAt: string;
1603 description?: string | null;
1604 hostedUrl?: string | null;
1605 pdfUrl?: string | null;
1606};
1607
1608export type UpcomingInvoice = { closesAt: string; subscriptionsMicros: number; usageMicros: number; totalMicros: number };
1609
1610export type BillingDetails = {
1611 customer: boolean;
1612 email: string | null;
1613 name: string | null;
1614 address: PostalAddress | null;
1615 taxIdType: string | null;
1616 taxId: string | null;
1617 poNumber: string | null;
1618 language: string | null;
1619 paymentMethod: PaymentMethod | null;
1620 invoices: StripeInvoice[];
1621 upcoming: UpcomingInvoice;
1622 unavailable?: string | null;
1623 /** Whether Stripe Tax can place the customer from the address; without it nothing is charged. */
1624 taxLocation?: boolean;
1625 /** Set when g1t did not charge for want of a billing address. */
1626 taxAddressNeededAt?: string | null;
1627 /** Stripe's check of the tax ID: pending, verified, unverified or unavailable. */
1628 taxIdStatus?: string | null;
1629 /** none, exempt or reverse, as set at Stripe. */
1630 taxExempt?: string | null;
1631};
1632
1633export type BillingDetailsInput = {
1634 email?: string;
1635 name?: string;
1636 address?: PostalAddress;
1637 taxIdType?: string;
1638 taxId?: string;
1639 poNumber?: string;
1640 language?: string;
1641};