Skip to content

Commit

AI Gateway: your own code calls models with a workspace token

models.g1t.sh/anthropic now takes a workspace's access token with the new models:write scope as well as a run's token, and serves Anthropic's POST /v1/messages (streamed or not) and /v1/messages/count_tokens. - On g1t's models, billing admits each request first (spend limit, AI credit or included usage, the plan) and refuses with an Anthropic-shaped 402 billing_error; afterwards it is charged its tokens at the model's list price (gateway_models table, migration 0045) plus the gateway_models markup (0 in beta), as a ledger line with task gateway. Included usage then AI credit pay; never trial credit, pools or the agent rate. Requests billed other than by tokens (fast mode, inference_geo, fallbacks, server tools, containers) are refused. - On the workspace's own Anthropic key under Integrations, requests go there and are only counted. - Every request is logged 30 days (never prompts): the workspace's AI Gateway page, GET /workspaces/{workspace}/gateway/requests and the billing MCP tool's gateway_requests action, with models:read. - The proxy drops every cf-aig- header a caller sends, runs' included. - Docs: the AI Gateway guide, scopes, MCP and API reference, OpenAPI, llms.txt, pricing wording and billing operations.

syntaqxcommitted Parent7ea9b9bBrowse files
51 files+369−120/51 viewed
+1−0
269269 token_id: "tok_1".to_owned(),
270270 scopes: scopes.map(|scopes| scopes.iter().map(|scope| scope.as_str().to_owned()).collect()),
271271 legacy,
272+ name: None,
272273 })),
273274 ..User::default()
274275 }
+35−3
412412 })
413413 }
414414 Op::GetBillingDetails => shaped(g1t_kit::call(billing, "billing_details", &account).await?, &details_json),
415+ Op::ListGatewayRequests => {
416+ let limit = match &input["limit"] {
417+ Value::Null => None,
418+ Value::Number(number) => number.as_u64(),
419+ Value::String(digits) => digits.trim().parse().ok(),
420+ _ => Some(0),
421+ };
422+ if limit.is_some_and(|limit| !(1..=200).contains(&limit)) {
423+ return failed(FailureCode::Invalid, "limit is a number from 1 to 200.");
424+ }
425+ let before = input["before"].as_str().map(str::trim).filter(|id| !id.is_empty());
426+ let page: Outcome<Value> = g1t_kit::call(
427+ billing,
428+ "gateway_requests",
429+ &json!({ "workspace": workspace, "viewer": viewer, "limit": limit, "before": before }),
430+ )
431+ .await?;
432+ shaped(page, &snake)
433+ }
415434 _ => failed(FailureCode::Invalid, "Not a billing operation."),
416435 }
417436 }
559578 assert!(shown.get("invoices").is_none() && shown.get("upcoming").is_none());
560579 }
561580
562− const OPS: [Op; 7] =
563− [Op::GetUsage, Op::GetBudget, Op::SetBudget, Op::GetAiCredit, Op::BuyAiCredit, Op::ListInvoices, Op::GetBillingDetails];
581+ const OPS: [Op; 8] = [
582+ Op::GetUsage,
583+ Op::GetBudget,
584+ Op::SetBudget,
585+ Op::GetAiCredit,
586+ Op::BuyAiCredit,
587+ Op::ListInvoices,
588+ Op::GetBillingDetails,
589+ Op::ListGatewayRequests,
590+ ];
564591
565592 /// Billing belongs to a workspace, needs someone signed in, and is one
566593 /// MCP tool whose writes no preset but full access reaches.
579606 token_id: "tok_1".into(),
580607 scopes: preset.scopes().map(|scopes| scopes.iter().map(|scope| scope.as_str().to_owned()).collect()),
581608 legacy: false,
609+ name: None,
582610 };
583611 for preset in [Preset::ReadOnly, Preset::Agent] {
584612 let access = token(preset);
585613 let seen: Vec<&str> = tool.visible(&Gate::Token(&access)).iter().map(|action| action.name).collect();
586− assert_eq!(seen, ["usage", "budget", "ai_credit", "invoices", "billing_details"], "{}", preset.as_str());
614+ assert_eq!(seen, ["usage", "budget", "ai_credit", "invoices", "billing_details", "gateway_requests"], "{}", preset.as_str());
587615 }
616+ // The AI Gateway's log needs models:read, and nothing of billing's.
617+ let models = TokenAccess { scopes: Some(vec!["models:read".into()]), ..token(Preset::Ci) };
618+ let seen: Vec<&str> = tool.visible(&Gate::Token(&models)).iter().map(|action| action.name).collect();
619+ assert_eq!(seen, ["gateway_requests"]);
588620 let full = TokenAccess::full();
589621 assert_eq!(tool.visible(&Gate::Token(&full)).len(), OPS.len());
590622 }
+3−1
6363 ),
6464 (
6565 "Billing",
66− "A workspace's usage, its budget, its AI credit and its invoices. Members read them; owners change the budget and buy credit, as people. g1t's agents never change billing.",
66+ "A workspace's usage, its budget, its AI credit, its invoices and its AI Gateway requests. Members read them; owners change the budget and buy credit, as people. g1t's agents never change billing.",
6767 &[
6868 Op::GetUsage,
6969 Op::GetBudget,
7272 Op::BuyAiCredit,
7373 Op::ListInvoices,
7474 Op::GetBillingDetails,
75+ Op::ListGatewayRequests,
7576 ],
7677 ),
7778 (
513514 Op::BuyAiCredit => "Buy AI credit",
514515 Op::ListInvoices => "List a workspace's invoices",
515516 Op::GetBillingDetails => "Get a workspace's billing details",
517+ Op::ListGatewayRequests => "List a workspace's AI Gateway requests",
516518 Op::PinProject => "Pin a project",
517519 Op::UnpinProject => "Unpin a project",
518520 Op::ReorderPinnedProjects => "Reorder your pinned projects",
+18−2
258258 BuyAiCredit,
259259 ListInvoices,
260260 GetBillingDetails,
261+ ListGatewayRequests,
261262 RequestReviewers,
262263 RemoveRequestedReviewers,
263264 GetCodeownersErrors,
625626 }
626627
627628 impl Op {
628− pub const ALL: [Op; 205] = [
629+ pub const ALL: [Op; 206] = [
629630 Op::Whoami,
630631 Op::GetWorkspace,
631632 Op::CreateWorkspace,
797798 Op::BuyAiCredit,
798799 Op::ListInvoices,
799800 Op::GetBillingDetails,
801+ Op::ListGatewayRequests,
800802 Op::RequestReviewers,
801803 Op::RemoveRequestedReviewers,
802804 Op::GetCodeownersErrors,
10111013 Op::BuyAiCredit => "buy_ai_credit",
10121014 Op::ListInvoices => "list_invoices",
10131015 Op::GetBillingDetails => "get_billing_details",
1016+ Op::ListGatewayRequests => "list_gateway_requests",
10141017 Op::RequestReviewers => "request_reviewers",
10151018 Op::RemoveRequestedReviewers => "remove_requested_reviewers",
10161019 Op::GetCodeownersErrors => "get_codeowners_errors",
14961499 Op::GetBillingDetails => {
14971500 "Who a workspace's invoices are made out to: the billing `email`, `name`, `address`, tax ID (`tax_id_type`, `tax_id`), `po_number` and the invoices' `language`, with the default `payment_method` as far as it is safe to show (its kind, brand, last four digits and expiry). `customer` is false until the workspace has been set up to pay. Tax is worked out from the address: `tax_location` says whether it is enough for that (a country, and in the US a ZIP code), `tax_address_needed_at` is set while g1t is holding a charge for want of one, `tax_id_status` is Stripe's check of the tax ID (`pending`, `verified`, `unverified` or `unavailable`), and `tax_exempt` is `none`, `exempt` or `reverse`. Members of the workspace only."
14981501 }
1502+ Op::ListGatewayRequests => {
1503+ "A workspace's recent AI Gateway requests, newest first: each with its `id`, `created_at`, `model`, the access token that sent it (`token_id`, `token_name`), its tokens by kind (`input`, `output`, `cache_read`, `cache_write`), what they cost at the model's price (`cost_micros`) and what the workspace was charged (`charged_micros`, before included usage and AI credit paid for it; 0 on the workspace's own provider key, `own_key`), the HTTP `status` it was answered with, whether it was `streamed`, `duration_ms`, and `error` for one that was refused or failed. Prompts and answers are never kept. `limit` is how many, 50 unless given and 200 at most; pass `next` from one page as `before` for the next. Requests are kept `retention_days` (30). Members of the workspace only."
1504+ }
14991505 Op::ListUserTeams => {
15001506 "The teams someone is in within a workspace, as list_teams describes them, leaving out secret teams you cannot see. Members of the workspace only."
15011507 }
27542760 Op::GetBudget | Op::GetAiCredit | Op::ListInvoices | Op::GetBillingDetails => {
27552761 object(json!({ "workspace": workspace_schema() }), &["workspace"])
27562762 }
2763+ Op::ListGatewayRequests => object(
2764+ json!({
2765+ "workspace": workspace_schema(),
2766+ "limit": { "type": "integer", "minimum": 1, "maximum": 200, "description": "How many requests, newest first. 50 if not given." },
2767+ "before": { "type": "string", "description": "Only requests older than this one: the `next` of the page before." },
2768+ }),
2769+ &["workspace"],
2770+ ),
27572771 Op::SetBudget => object(
27582772 json!({
27592773 "workspace": workspace_schema(),
29362950 | Op::BuyAiCredit
29372951 | Op::ListInvoices
29382952 | Op::GetBillingDetails
2953+ | Op::ListGatewayRequests
29392954 )
29402955 }
29412956
47294744 | Op::GetAiCredit
47304745 | Op::BuyAiCredit
47314746 | Op::ListInvoices
4732− | Op::GetBillingDetails => crate::billing::run(self, services, viewer, input).await,
4747+ | Op::GetBillingDetails
4748+ | Op::ListGatewayRequests => crate::billing::run(self, services, viewer, input).await,
47334749 Op::ListUserTeams => {
47344750 pass(
47354751 identity,
+51−0
59615961 },
59625962 "notes": "Open `url` in a browser to pay. Nothing is charged until the payment is made there; the credit then shows in get_ai_credit. An amount outside `min_cents` to `max_cents`, or not in whole dollars, is refused with `invalid`; a workspace that cannot buy credit (see `can_buy`) gets `conflict` or `payment_required`."
59635963 },
5964+ "list_gateway_requests": {
5965+ "params": {
5966+ "workspace": "flagon-io"
5967+ },
5968+ "query": {
5969+ "limit": 2
5970+ },
5971+ "response": {
5972+ "requests": [
5973+ {
5974+ "id": "gw_5f0c2a9e7b1d4c3a8e6f0b12",
5975+ "created_at": "2026-10-07T14:02:11.000Z",
5976+ "model": "claude-sonnet-5-5",
5977+ "token_id": "tok_01kkr4w7d2c9e5f8h1j3m6n0p2",
5978+ "token_name": "release-notes",
5979+ "input": 1840,
5980+ "output": 512,
5981+ "cache_read": 12000,
5982+ "cache_write": 0,
5983+ "cost_micros": 11200,
5984+ "charged_micros": 11200,
5985+ "status": 200,
5986+ "own_key": false,
5987+ "streamed": true,
5988+ "duration_ms": 4210,
5989+ "error": null
5990+ },
5991+ {
5992+ "id": "gw_1a7e3c5b9d2f4e6a8c0b2d41",
5993+ "created_at": "2026-10-07T13:58:40.000Z",
5994+ "model": "claude-opus-5-5",
5995+ "token_id": "tok_01kkr4w7d2c9e5f8h1j3m6n0p2",
5996+ "token_name": "release-notes",
5997+ "input": 0,
5998+ "output": 0,
5999+ "cache_read": 0,
6000+ "cache_write": 0,
6001+ "cost_micros": 0,
6002+ "charged_micros": 0,
6003+ "status": 402,
6004+ "own_key": false,
6005+ "streamed": false,
6006+ "duration_ms": 38,
6007+ "error": "The flagon-io workspace is out of AI credit and has used this month's included usage, so the AI Gateway refuses requests to g1t's models. An owner can buy AI credit or turn on auto-reload at /flagon-io/-/billing#ai-credit."
6008+ }
6009+ ],
6010+ "next": "gw_1a7e3c5b9d2f4e6a8c0b2d41",
6011+ "retention_days": 30
6012+ },
6013+ "notes": "To send requests, see the AI Gateway guide: POST https://models.g1t.sh/anthropic/v1/messages with a workspace access token that has `models:write`. `charged_micros` is what the request was charged before included usage and AI credit paid for it; the payment itself is on the statement as AI Gateway. Pass `next` as `before` for the next page; it is null on the last."
6014+ },
59646015 "list_invoices": {
59656016 "params": {
59666017 "workspace": "flagon-io"
+3−0
134134 route("POST", "/workspaces/:workspace/ai_credit/checkout", Op::BuyAiCredit, &[]),
135135 route("GET", "/workspaces/:workspace/invoices", Op::ListInvoices, &[]),
136136 route("GET", "/workspaces/:workspace/billing_details", Op::GetBillingDetails, &[]),
137+ // The AI Gateway's log of a workspace's requests.
138+ route("GET", "/workspaces/:workspace/gateway/requests", Op::ListGatewayRequests, &[("limit", "limit"), ("before", "before")]),
137139 // Code owners: the CODEOWNERS file, checked.
138140 route("GET", "/repos/:owner/:name/codeowners/errors", Op::GetCodeownersErrors, &[("ref", "ref")]),
139141 // Security alerts: secrets and vulnerable dependencies.
10311033 assert_eq!(op("POST", "/workspaces/acme/ai_credit/checkout"), Op::BuyAiCredit);
10321034 assert_eq!(op("GET", "/workspaces/acme/invoices"), Op::ListInvoices);
10331035 assert_eq!(op("GET", "/workspaces/acme/billing_details"), Op::GetBillingDetails);
1036+ assert_eq!(op("GET", "/workspaces/acme/gateway/requests"), Op::ListGatewayRequests);
10341037 }
10351038
10361039 #[test]
+3−1
292292 Tool {
293293 name: "billing",
294294 title: "Billing",
295− description: "A workspace's billing: its usage by product, project and day, its budget (the monthly spend limit, alerts and whether usage pauses at it), its AI credit, and its invoices. Amounts are whole millionths of a dollar (`_micros`), or cents (`_cents`) where named. Members read it; changing the budget and buying credit are for owners, as people, and never for g1t's agents.",
295+ description: "A workspace's billing: its usage by product, project and day, its budget (the monthly spend limit, alerts and whether usage pauses at it), its AI credit, its invoices, and its AI Gateway requests. Amounts are whole millionths of a dollar (`_micros`), or cents (`_cents`) where named. Members read it; changing the budget and buying credit are for owners, as people, and never for g1t's agents.",
296296 default_action: Some("usage"),
297297 actions: &[
298298 a("usage", Op::GetUsage, "Usage over a range of days, by product, meter, project and day, and what paid for it"),
302302 a("buy_ai_credit", Op::BuyAiCredit, "A payment page to buy AI credit, for a person to open"),
303303 a("invoices", Op::ListInvoices, "Every invoice, the itemised usage invoices, and the next one so far"),
304304 a("billing_details", Op::GetBillingDetails, "Who invoices are made out to and the payment method on file"),
305+ a("gateway_requests", Op::ListGatewayRequests, "Recent AI Gateway requests: model, tokens, cost, status and token"),
305306 ],
306307 },
307308 Tool {
640641 token_id: "tok_1".to_owned(),
641642 scopes: scopes.map(|scopes| scopes.iter().map(|scope| scope.as_str().to_owned()).collect()),
642643 legacy: false,
644+ name: None,
643645 }
644646 }
645647
+1−0
115115 items: [
116116 { label: 'Integrations', slug: 'guides/integrations' },
117117 { label: 'Model providers', slug: 'guides/models' },
118+ { label: 'AI Gateway', slug: 'guides/ai-gateway' },
118119 { label: 'Webhooks', slug: 'guides/webhooks' },
119120 { label: 'GitHub Actions', slug: 'guides/actions' },
120121 { label: 'Self-hosted runners', slug: 'guides/self-hosted-runners' },
+241−0
1+---
2+title: AI Gateway
3+description: Send your own code's model requests through g1t with a workspace access token, paid from AI credit at the model's price, with a log of every request.
4+---
5+
6+The AI Gateway takes model requests from your own code, in Anthropic's
7+Messages format, and sends them to the model. You point an Anthropic SDK,
8+Claude Code or anything else that speaks that format at one base URL and
9+give it a workspace access token as its API key:
10+
11+| | |
12+| --- | --- |
13+| Base URL | `https://models.g1t.sh/anthropic` |
14+| API key | A workspace access token (`g1t_…`) with the `models:write` scope |
15+
16+Each request is charged to the workspace at the model's price and paid from
17+the plan's included usage and [AI credit](/guides/usage-and-billing/#ai-credit).
18+While the gateway is in beta there is no markup. If the workspace has
19+connected its own Anthropic key, requests go there instead and cost
20+nothing on g1t. Every request is logged with its model, tokens, cost and
21+status. Prompts and answers are never kept.
22+
23+## Before you start
24+
25+You need one of these:
26+
27+- **The workspace on the g1t plan**, with AI credit or this month's
28+ included usage left. See [AI credit](/guides/usage-and-billing/#ai-credit).
29+- **The workspace's own Anthropic key**, connected under
30+ [Integrations](/guides/models/#connect-a-provider). Then the plan is not
31+ needed and nothing is charged.
32+
33+## Make a token
34+
35+The gateway takes a workspace's own token, so its usage is the workspace's
36+and keeps working when the person who set it up leaves. Only owners make
37+them.
38+
39+1. Open the workspace's **Settings → Access tokens**.
40+2. Under **New token**, give it a name, such as `release-notes`. The log
41+ shows each request's token by this name.
42+3. The scopes start on the CI preset. Untick what the code does not need,
43+ and under **AI Gateway** tick `models:write`. A token with only
44+ `models:write` can send model requests and nothing else.
45+4. Choose an expiry and select **Create token**. Copy the token now: it is
46+ not shown again.
47+
48+A personal access token is refused, even with `models:write`: the gateway
49+has to know which workspace to charge. A token with full access has every
50+scope, `models:write` included. See [scopes](/guides/authentication/#scopes).
51+
52+## Send a request
53+
54+The gateway answers the same routes as Anthropic's API, below the base URL:
55+
56+| Route | What it does |
57+| --- | --- |
58+| `POST /anthropic/v1/messages` | A message, streamed (`"stream": true`) or whole. Logged and charged. |
59+| `POST /anthropic/v1/messages/count_tokens` | Counts a request's input tokens. Not logged, and costs nothing. |
60+
61+The token goes in `x-api-key`, or in `Authorization: Bearer`. Request and
62+answer bodies are Anthropic's, unchanged, and so are streamed events.
63+
64+With curl:
65+
66+```sh
67+curl https://models.g1t.sh/anthropic/v1/messages \
68+ -H "x-api-key: $G1T_TOKEN" \
69+ -H "anthropic-version: 2023-06-01" \
70+ -H "content-type: application/json" \
71+ -d '{
72+ "model": "claude-sonnet-5-5",
73+ "max_tokens": 1024,
74+ "messages": [{ "role": "user", "content": "Write a commit message for: fix the login redirect" }]
75+ }'
76+```
77+
78+With Anthropic's TypeScript SDK:
79+
80+```ts
81+import Anthropic from "@anthropic-ai/sdk";
82+
83+const client = new Anthropic({
84+ baseURL: "https://models.g1t.sh/anthropic",
85+ apiKey: process.env.G1T_TOKEN,
86+});
87+
88+const message = await client.messages.create({
89+ model: "claude-sonnet-5-5",
90+ max_tokens: 1024,
91+ messages: [{ role: "user", content: "Write a commit message for: fix the login redirect" }],
92+});
93+```
94+
95+With Anthropic's Python SDK:
96+
97+```python
98+import os
99+
100+import anthropic
101+
102+client = anthropic.Anthropic(
103+ base_url="https://models.g1t.sh/anthropic",
104+ api_key=os.environ["G1T_TOKEN"],
105+)
106+
107+message = client.messages.create(
108+ model="claude-sonnet-5-5",
109+ max_tokens=1024,
110+ messages=[{"role": "user", "content": "Write a commit message for: fix the login redirect"}],
111+)
112+```
113+
114+### Claude Code
115+
116+Set two environment variables before you start it:
117+
118+```sh
119+export ANTHROPIC_BASE_URL=https://models.g1t.sh/anthropic
120+export ANTHROPIC_AUTH_TOKEN=g1t_…
121+claude
122+```
123+
124+Claude Code's own small requests go to Claude Haiku 4.5, which the gateway
125+offers. To choose the main model, also set `ANTHROPIC_MODEL`, such as
126+`claude-opus-5-5`.
127+
128+## Models
129+
130+On g1t's models the gateway offers these. Prices are per million tokens,
131+the provider's list price; cache writes are five-minute ones.
132+
133+| Model | `model` | Input | Output | Cache reads | Cache writes |
134+| --- | --- | --- | --- | --- | --- |
135+| Claude Opus 5.5 | `claude-opus-5-5` | $4.00 | $20.00 | $0.20 | $5.00 |
136+| Claude Sonnet 5.5 | `claude-sonnet-5-5` | $2.00 | $10.00 | $0.20 | $2.50 |
137+| Claude Haiku 4.5 | `claude-haiku-4-5`, `claude-haiku-4-5-20251001` | $1.00 | $5.00 | $0.10 | $1.25 |
138+
139+A request for any other model is refused with `400` before it reaches the
140+provider, and the error names the models offered. On the workspace's own
141+key, a request can name any model that key can use.
142+
143+On g1t's models a request is charged only by its tokens, so what the
144+provider bills some other way is refused with `400` for now:
145+
146+| Not offered on g1t's models yet | In the request |
147+| --- | --- |
148+| Fast mode | `speed` other than `standard` |
149+| Inference in one region | `inference_geo` other than `global` |
150+| Server-side fallbacks | `fallbacks` |
151+| Server tools, such as web search, web fetch and code execution | A tool whose `type` is not your own (`custom` or none) or a client tool (`bash_…`, `text_editor_…`, `computer_…`, `memory_…`) |
152+| Containers and skills | `container` |
153+
154+All of them work on the workspace's own key, which the provider bills. In
155+Claude Code on g1t's models, its web search fails for this reason; the
156+rest of Claude Code works.
157+
158+Anthropic's format is the one served today. OpenAI's format and open
159+models are coming later.
160+
161+## What it costs
162+
163+| Where it goes | You pay |
164+| --- | --- |
165+| g1t's models | Its tokens at the model's price above, with no markup while the gateway is in beta |
166+| The workspace's own Anthropic key | Nothing on g1t. The provider bills you for the model. |
167+
168+On g1t's models:
169+
170+- Each request that used tokens is one line on the statement, under
171+ **AI Gateway**, such as *AI Gateway: Claude Sonnet 5.5, 14,352 tokens,
172+ token release-notes*.
173+- The plan's included usage pays first, then AI credit. Trial credit and
174+ g1t's open-source pool never pay for gateway requests.
175+- It is not an agent run, so the [agent rate](/guides/usage-and-billing/#the-agent-rate)
176+ does not apply.
177+- It counts toward the workspace's [spend limit](/guides/usage-and-billing/#your-spend-limit)
178+ like any other usage, and shows on **Usage** under the AI Gateway product.
179+- A workspace with a 100% discount gets it free through the discount; an
180+ enterprise is invoiced for it after use.
181+
182+### Your own key
183+
184+When the workspace has an Anthropic or Anthropic-compatible model provider
185+under [Integrations](/guides/models/), the gateway sends every request to
186+the first one connected, with its key. Those requests are logged with their
187+tokens and marked **Own key**, and g1t charges nothing for them. Remove the
188+provider and requests go to g1t's models again within a few seconds.
189+
190+## Limits and errors
191+
192+A request on g1t's models is refused before it reaches the model when:
193+
194+- The workspace is over its spend limit.
195+- It is on the plan, and has no AI credit and none of this month's included
196+ usage left. If auto-reload is on, g1t tries it first.
197+- It is not on the g1t plan.
198+
199+Errors are Anthropic's shape, so SDKs raise their usual errors:
200+
201+```json
202+{ "type": "error", "error": { "type": "billing_error", "message": "The acme workspace is out of AI credit …" } }
203+```
204+
205+| Status | `error.type` | Why |
206+| --- | --- | --- |
207+| `400` | `invalid_request_error` | The body is not JSON, the model is not offered, or the request asks for something [not offered on g1t's models yet](#models). |
208+| `401` | `authentication_error` | The token is unknown, expired or deleted. |
209+| `402` | `billing_error` | Out of AI credit, over the spend limit, or not on the plan. The message says what an owner can do. |
210+| `403` | `permission_error` | Not a workspace's token, or it lacks `models:write`. |
211+| `404` | `not_found_error` | A route the gateway does not answer. |
212+
213+An error from the model provider, such as `429` or `529`, comes back as
214+the provider sent it. Refused and failed requests are logged with their
215+status and why, and cost nothing.
216+
217+A deleted token, a provider added under Integrations, or AI credit just
218+bought takes effect within about ten seconds.
219+
220+## See every request
221+
222+The **AI Gateway** page lists the workspace's requests, newest first. Open
223+it from the link under **Usage**, or at `g1t.sh/<workspace>/-/gateway`.
224+Every member can see it.
225+
226+| Column | |
227+| --- | --- |
228+| Time | When it was sent. Hover for the exact time, how long it took and whether it streamed. |
229+| Model | The model it named. On the workspace's own key, the one that answered. |
230+| Input, Output, Cache read, Cache write | Its tokens by kind. |
231+| Cost | What it was charged, before included usage and AI credit paid for it, or **Own key**. |
232+| Status | The status it was answered with. Hover a refusal or failure for why. |
233+| Token | The name of the token that sent it. |
234+
235+Requests are kept 30 days.
236+
237+From code, list them with
238+[`GET /workspaces/{workspace}/gateway/requests`](/reference/api/billing/list-gateway-requests/),
239+or the `billing` MCP tool's
240+[`gateway_requests`](/reference/mcp/#billing) action. Both need
241+`models:read`, which the Read only and Agent presets include.
+3−0
328328 | Workspace | `workspace:read`, `access:read`, `webhooks:read`, `secrets:read` |
329329 | Billing | `billing:read`, `billing:write` |
330330 | Runners | `runners:read` |
331+| AI Gateway | `models:read`, `models:write` |
331332 | Dangerous | `repo:admin`, `packages:delete`, `workspace:admin`, `access:admin`, `webhooks:admin`, `secrets:admin`, `runners:admin` |
332333
333334 Ticking a higher level ticks the lower ones of its resource and greys
371372 | `secrets:admin` | Set and delete secrets and variables |
372373 | `runners:read` | See [self-hosted runners](/guides/self-hosted-runners/), their groups and where agents run. Not in the Agent preset. |
373374 | `runners:admin` | Register and remove self-hosted runners, change their groups and settings |
375+| `models:read` | See the workspace's [AI Gateway](/guides/ai-gateway/) requests: their models, tokens, cost and status |
376+| `models:write` | Send model requests through the [AI Gateway](/guides/ai-gateway/), which uses the workspace's AI credit. Only a workspace's own token can send them. Not in any preset but full access. |
374377
375378 Every operation of the API and the MCP server needs exactly one of these,
376379 except `whoami` (`GET /user`), which any token may use. Each endpoint's page
+3−0
1818 kind of work, which provider and model it runs on. Each provider bills
1919 you for the model directly. Open to every workspace now.
2020
21+To call models from your own code with a workspace token, paid from the
22+same AI credit, use the [AI Gateway](/guides/ai-gateway/).
23+
2124 ## Auto
2225
2326 On g1t's models you do not have to pick a model. **Auto**, the default,
+1−1
123123 | Agent models | A run | What the provider charged | The provider's price, from [AI credit](#ai-credit) |
124124 | g1t agent rate | Million tokens a run uses (input, output and cached), [weighted by kind](#the-agent-rate) | — | $0.25, from Oct 22, 2026 |
125125 | g1t agent rate, your own model key | The same, on runs that use [your own provider](/guides/models/) | — | $0.25, from Oct 22, 2026 |
126−| AI Gateway | A request | What the provider charged | The provider's price: free of markup during beta |
126+| [AI Gateway](/guides/ai-gateway/) | A request | What the provider charged | The model's list price per token: free of markup during beta |
127127 | Sandbox time (agents, workflows, the merge queue) | Second | About $0.001 a minute | About $0.0012 a minute |
128128 | [Larger machines](#workflow-jobs-on-larger-machines) for workflow jobs (`g1t-2core`, `g1t-4core`) | Second | About 2.8 and 5.1 times a sandbox second | Cost + 20% |
129129 | Deploy builds | Second | About $0.001 a minute | About $0.0012 a minute |
+2−1
6363 gets a [pull request that upgrades it](/guides/security/).
6464 </Card>
6565 <Card title="Your models, your tools" icon="plug">
66− Use g1t's models or [your own providers](/guides/models/), and pull context
66+ Use g1t's models or [your own providers](/guides/models/), call the same
67+ models from your own code through the [AI Gateway](/guides/ai-gateway/), and pull context
6768 from [Sentry, Jira and Linear](/guides/integrations/).
6869 </Card>
6970 <Card title="Everything has an API" icon="book-open">
+1−1
197197 | [Accounts](/reference/api/accounts/whoami/) | Signing in from a tool, and who a token acts as. |
198198 | [Workspaces](/reference/api/workspaces/create-workspace/) | Creating a workspace. |
199199 | [Notifications](/reference/api/notifications/list-notifications/) | Your inbox: its threads, why you were told of each, marking them read, done, saved or snoozed, and what you subscribe to and watch. See [your inbox](/guides/inbox/). |
200−| [Billing](/reference/api/billing/get-usage/) | A workspace's usage by product, project and day, its budget, its AI credit and its invoices. See [usage and billing](/guides/usage-and-billing/). |
200+| [Billing](/reference/api/billing/get-usage/) | A workspace's usage by product, project and day, its budget, its AI credit, its invoices and its [AI Gateway](/guides/ai-gateway/) requests. See [usage and billing](/guides/usage-and-billing/). |
201201 | [Invites](/reference/api/invites/list-invites/) | Your invites while g1t is invite-only, and inviting people into a workspace by email. |
202202 | [Repositories](/reference/api/repositories/list-repos/) | A repository, how it handles pull requests, and its timeline. |
203203 | [Access](/reference/api/access/list-collaborators/) | Who has which role on a repository, invitations, outside collaborators, and a workspace's base permission. |
+3−2
552552
553553 ## `billing`
554554
555−A workspace's billing: its usage, its budget, its AI credit and its
556−invoices. `usage` is the default action. Amounts are whole millionths of a
555+A workspace's billing: its usage, its budget, its AI credit, its
556+invoices and its [AI Gateway](/guides/ai-gateway/) requests. `usage` is the default action. Amounts are whole millionths of a
557557 dollar (`_micros`), or cents where a field says `_cents`. Members of the
558558 workspace read it, a workspace's own token included. Changing the budget
559559 and buying AI credit are for its owners, as people: signed in or with a
570570 | [`buy_ai_credit`](/reference/api/billing/buy-ai-credit/) | A payment page (`url`) to buy `amount_cents` of credit, in whole dollars from $10 to $1,000, for a person to open and pay; it returns to the workspace's billing page. Owners, as people. | `workspace`, `amount_cents` | `billing:write` |
571571 | [`invoices`](/reference/api/billing/list-invoices/) | Every invoice (`invoices`, in cents), g1t's itemised usage invoices (`usage_invoices`), and what the next one comes to so far (`upcoming`). | `workspace` | `billing:read` |
572572 | [`billing_details`](/reference/api/billing/get-billing-details/) | Who invoices are made out to, and the payment method on file as far as it is safe to show. | `workspace` | `billing:read` |
573+| [`gateway_requests`](/reference/api/billing/list-gateway-requests/) | The workspace's recent [AI Gateway](/guides/ai-gateway/) requests, newest first: model, tokens by kind, `cost_micros`, `charged_micros`, `status`, `own_key` and the token that sent each. `limit` (50, at most 200) and `before` (the last page's `next`) page through them. Kept 30 days. | `workspace` | `models:read` |
573574
574575 ## `notifications`
575576
+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

This change is too large to show in full.