Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens
models.g1t.sh/anthropic answers a workspace access token with the models scope, charges each request at list price (markup 0) from included usage and AI credit, refuses one it cannot pay for, and only counts requests on the workspace's own key. Logs page, REST, MCP and a guide. Conflict: Op::ALL is 219 (the rulesets and the gateway's operation). The docs' OpenAPI copy is regenerated.
| 269 | 269 | token_id: "tok_1".to_owned(), | |
| 270 | 270 | scopes: scopes.map(|scopes| scopes.iter().map(|scope| scope.as_str().to_owned()).collect()), | |
| 271 | 271 | legacy, | |
| 272 | + | name: None, | |
| 272 | 273 | })), | |
| 273 | 274 | ..User::default() | |
| 274 | 275 | } |
| 412 | 412 | }) | |
| 413 | 413 | } | |
| 414 | 414 | 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 | + | } | |
| 415 | 434 | _ => failed(FailureCode::Invalid, "Not a billing operation."), | |
| 416 | 435 | } | |
| 417 | 436 | } | |
| 559 | 578 | assert!(shown.get("invoices").is_none() && shown.get("upcoming").is_none()); | |
| 560 | 579 | } | |
| 561 | 580 | ||
| 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 | + | ]; | |
| 564 | 591 | ||
| 565 | 592 | /// Billing belongs to a workspace, needs someone signed in, and is one | |
| 566 | 593 | /// MCP tool whose writes no preset but full access reaches. | |
| 579 | 606 | token_id: "tok_1".into(), | |
| 580 | 607 | scopes: preset.scopes().map(|scopes| scopes.iter().map(|scope| scope.as_str().to_owned()).collect()), | |
| 581 | 608 | legacy: false, | |
| 609 | + | name: None, | |
| 582 | 610 | }; | |
| 583 | 611 | for preset in [Preset::ReadOnly, Preset::Agent] { | |
| 584 | 612 | let access = token(preset); | |
| 585 | 613 | 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()); | |
| 587 | 615 | } | |
| 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"]); | |
| 588 | 620 | let full = TokenAccess::full(); | |
| 589 | 621 | assert_eq!(tool.visible(&Gate::Token(&full)).len(), OPS.len()); | |
| 590 | 622 | } |
| 64 | 64 | ), | |
| 65 | 65 | ( | |
| 66 | 66 | "Billing", | |
| 67 | − | "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.", | |
| 67 | + | "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.", | |
| 68 | 68 | &[ | |
| 69 | 69 | Op::GetUsage, | |
| 70 | 70 | Op::GetBudget, | |
| 73 | 73 | Op::BuyAiCredit, | |
| 74 | 74 | Op::ListInvoices, | |
| 75 | 75 | Op::GetBillingDetails, | |
| 76 | + | Op::ListGatewayRequests, | |
| 76 | 77 | ], | |
| 77 | 78 | ), | |
| 78 | 79 | ( | |
| 533 | 534 | Op::BuyAiCredit => "Buy AI credit", | |
| 534 | 535 | Op::ListInvoices => "List a workspace's invoices", | |
| 535 | 536 | Op::GetBillingDetails => "Get a workspace's billing details", | |
| 537 | + | Op::ListGatewayRequests => "List a workspace's AI Gateway requests", | |
| 536 | 538 | Op::PinProject => "Pin a project", | |
| 537 | 539 | Op::UnpinProject => "Unpin a project", | |
| 538 | 540 | Op::ReorderPinnedProjects => "Reorder your pinned projects", |
| 259 | 259 | BuyAiCredit, | |
| 260 | 260 | ListInvoices, | |
| 261 | 261 | GetBillingDetails, | |
| 262 | + | ListGatewayRequests, | |
| 262 | 263 | RequestReviewers, | |
| 263 | 264 | RemoveRequestedReviewers, | |
| 264 | 265 | GetCodeownersErrors, | |
| 628 | 629 | } | |
| 629 | 630 | ||
| 630 | 631 | impl Op { | |
| 631 | − | pub const ALL: [Op; 218] = [ | |
| 632 | + | pub const ALL: [Op; 219] = [ | |
| 632 | 633 | Op::Whoami, | |
| 633 | 634 | Op::GetWorkspace, | |
| 634 | 635 | Op::CreateWorkspace, | |
| 800 | 801 | Op::BuyAiCredit, | |
| 801 | 802 | Op::ListInvoices, | |
| 802 | 803 | Op::GetBillingDetails, | |
| 804 | + | Op::ListGatewayRequests, | |
| 803 | 805 | Op::RequestReviewers, | |
| 804 | 806 | Op::RemoveRequestedReviewers, | |
| 805 | 807 | Op::GetCodeownersErrors, | |
| 1027 | 1029 | Op::BuyAiCredit => "buy_ai_credit", | |
| 1028 | 1030 | Op::ListInvoices => "list_invoices", | |
| 1029 | 1031 | Op::GetBillingDetails => "get_billing_details", | |
| 1032 | + | Op::ListGatewayRequests => "list_gateway_requests", | |
| 1030 | 1033 | Op::RequestReviewers => "request_reviewers", | |
| 1031 | 1034 | Op::RemoveRequestedReviewers => "remove_requested_reviewers", | |
| 1032 | 1035 | Op::GetCodeownersErrors => "get_codeowners_errors", | |
| 1513 | 1516 | Op::GetBillingDetails => { | |
| 1514 | 1517 | "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." | |
| 1515 | 1518 | } | |
| 1519 | + | Op::ListGatewayRequests => { | |
| 1520 | + | "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." | |
| 1521 | + | } | |
| 1516 | 1522 | Op::ListUserTeams => { | |
| 1517 | 1523 | "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." | |
| 1518 | 1524 | } | |
| 2776 | 2782 | Op::GetBudget | Op::GetAiCredit | Op::ListInvoices | Op::GetBillingDetails => { | |
| 2777 | 2783 | object(json!({ "workspace": workspace_schema() }), &["workspace"]) | |
| 2778 | 2784 | } | |
| 2785 | + | Op::ListGatewayRequests => object( | |
| 2786 | + | json!({ | |
| 2787 | + | "workspace": workspace_schema(), | |
| 2788 | + | "limit": { "type": "integer", "minimum": 1, "maximum": 200, "description": "How many requests, newest first. 50 if not given." }, | |
| 2789 | + | "before": { "type": "string", "description": "Only requests older than this one: the `next` of the page before." }, | |
| 2790 | + | }), | |
| 2791 | + | &["workspace"], | |
| 2792 | + | ), | |
| 2779 | 2793 | Op::SetBudget => object( | |
| 2780 | 2794 | json!({ | |
| 2781 | 2795 | "workspace": workspace_schema(), | |
| 2963 | 2977 | | Op::BuyAiCredit | |
| 2964 | 2978 | | Op::ListInvoices | |
| 2965 | 2979 | | Op::GetBillingDetails | |
| 2980 | + | | Op::ListGatewayRequests | |
| 2966 | 2981 | ) | |
| 2967 | 2982 | } | |
| 2968 | 2983 | ||
| 4759 | 4774 | | Op::GetAiCredit | |
| 4760 | 4775 | | Op::BuyAiCredit | |
| 4761 | 4776 | | Op::ListInvoices | |
| 4762 | − | | Op::GetBillingDetails => crate::billing::run(self, services, viewer, input).await, | |
| 4777 | + | | Op::GetBillingDetails | |
| 4778 | + | | Op::ListGatewayRequests => crate::billing::run(self, services, viewer, input).await, | |
| 4763 | 4779 | Op::ListUserTeams => { | |
| 4764 | 4780 | pass( | |
| 4765 | 4781 | identity, |
| 5961 | 5961 | }, | |
| 5962 | 5962 | "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`." | |
| 5963 | 5963 | }, | |
| 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 | + | }, | |
| 5964 | 6015 | "list_invoices": { | |
| 5965 | 6016 | "params": { | |
| 5966 | 6017 | "workspace": "flagon-io" |
| 135 | 135 | route("POST", "/workspaces/:workspace/ai_credit/checkout", Op::BuyAiCredit, &[]), | |
| 136 | 136 | route("GET", "/workspaces/:workspace/invoices", Op::ListInvoices, &[]), | |
| 137 | 137 | route("GET", "/workspaces/:workspace/billing_details", Op::GetBillingDetails, &[]), | |
| 138 | + | // The AI Gateway's log of a workspace's requests. | |
| 139 | + | route("GET", "/workspaces/:workspace/gateway/requests", Op::ListGatewayRequests, &[("limit", "limit"), ("before", "before")]), | |
| 138 | 140 | // Code owners: the CODEOWNERS file, checked. | |
| 139 | 141 | route("GET", "/repos/:owner/:name/codeowners/errors", Op::GetCodeownersErrors, &[("ref", "ref")]), | |
| 140 | 142 | // Security alerts: secrets and vulnerable dependencies. | |
| 1057 | 1059 | assert_eq!(op("POST", "/workspaces/acme/ai_credit/checkout"), Op::BuyAiCredit); | |
| 1058 | 1060 | assert_eq!(op("GET", "/workspaces/acme/invoices"), Op::ListInvoices); | |
| 1059 | 1061 | assert_eq!(op("GET", "/workspaces/acme/billing_details"), Op::GetBillingDetails); | |
| 1062 | + | assert_eq!(op("GET", "/workspaces/acme/gateway/requests"), Op::ListGatewayRequests); | |
| 1060 | 1063 | } | |
| 1061 | 1064 | ||
| 1062 | 1065 | #[test] |
| 306 | 306 | Tool { | |
| 307 | 307 | name: "billing", | |
| 308 | 308 | title: "Billing", | |
| 309 | − | 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.", | |
| 309 | + | 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.", | |
| 310 | 310 | default_action: Some("usage"), | |
| 311 | 311 | actions: &[ | |
| 312 | 312 | a("usage", Op::GetUsage, "Usage over a range of days, by product, meter, project and day, and what paid for it"), | |
| 316 | 316 | a("buy_ai_credit", Op::BuyAiCredit, "A payment page to buy AI credit, for a person to open"), | |
| 317 | 317 | a("invoices", Op::ListInvoices, "Every invoice, the itemised usage invoices, and the next one so far"), | |
| 318 | 318 | a("billing_details", Op::GetBillingDetails, "Who invoices are made out to and the payment method on file"), | |
| 319 | + | a("gateway_requests", Op::ListGatewayRequests, "Recent AI Gateway requests: model, tokens, cost, status and token"), | |
| 319 | 320 | ], | |
| 320 | 321 | }, | |
| 321 | 322 | Tool { | |
| 655 | 656 | token_id: "tok_1".to_owned(), | |
| 656 | 657 | scopes: scopes.map(|scopes| scopes.iter().map(|scope| scope.as_str().to_owned()).collect()), | |
| 657 | 658 | legacy: false, | |
| 659 | + | name: None, | |
| 658 | 660 | } | |
| 659 | 661 | } | |
| 660 | 662 |
| 115 | 115 | items: [ | |
| 116 | 116 | { label: 'Integrations', slug: 'guides/integrations' }, | |
| 117 | 117 | { label: 'Model providers', slug: 'guides/models' }, | |
| 118 | + | { label: 'AI Gateway', slug: 'guides/ai-gateway' }, | |
| 118 | 119 | { label: 'Webhooks', slug: 'guides/webhooks' }, | |
| 119 | 120 | { label: 'GitHub Actions', slug: 'guides/actions' }, | |
| 120 | 121 | { label: 'Self-hosted runners', slug: 'guides/self-hosted-runners' }, |
| 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. |
| 328 | 328 | | Workspace | `workspace:read`, `access:read`, `webhooks:read`, `secrets:read` | | |
| 329 | 329 | | Billing | `billing:read`, `billing:write` | | |
| 330 | 330 | | Runners | `runners:read` | | |
| 331 | + | | AI Gateway | `models:read`, `models:write` | | |
| 331 | 332 | | Dangerous | `repo:admin`, `packages:delete`, `workspace:admin`, `access:admin`, `webhooks:admin`, `secrets:admin`, `runners:admin` | | |
| 332 | 333 | ||
| 333 | 334 | Ticking a higher level ticks the lower ones of its resource and greys | |
| 371 | 372 | | `secrets:admin` | Set and delete secrets and variables | | |
| 372 | 373 | | `runners:read` | See [self-hosted runners](/guides/self-hosted-runners/), their groups and where agents run. Not in the Agent preset. | | |
| 373 | 374 | | `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. | | |
| 374 | 377 | ||
| 375 | 378 | Every operation of the API and the MCP server needs exactly one of these, | |
| 376 | 379 | except `whoami` (`GET /user`), which any token may use. Each endpoint's page |
| 18 | 18 | kind of work, which provider and model it runs on. Each provider bills | |
| 19 | 19 | you for the model directly. Open to every workspace now. | |
| 20 | 20 | ||
| 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 | + | ||
| 21 | 24 | ## Auto | |
| 22 | 25 | ||
| 23 | 26 | On g1t's models you do not have to pick a model. **Auto**, the default, |
| 123 | 123 | | Agent models | A run | What the provider charged | The provider's price, from [AI credit](#ai-credit) | | |
| 124 | 124 | | g1t agent rate | Million tokens a run uses (input, output and cached), [weighted by kind](#the-agent-rate) | — | $0.25, from Oct 22, 2026 | | |
| 125 | 125 | | 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 | | |
| 127 | 127 | | Sandbox time (agents, workflows, the merge queue) | Second | About $0.001 a minute | About $0.0012 a minute | | |
| 128 | 128 | | [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% | | |
| 129 | 129 | | Deploy builds | Second | About $0.001 a minute | About $0.0012 a minute | |
| 63 | 63 | gets a [pull request that upgrades it](/guides/security/). | |
| 64 | 64 | </Card> | |
| 65 | 65 | <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 | |
| 67 | 68 | from [Sentry, Jira and Linear](/guides/integrations/). | |
| 68 | 69 | </Card> | |
| 69 | 70 | <Card title="Everything has an API" icon="book-open"> |
| 197 | 197 | | [Accounts](/reference/api/accounts/whoami/) | Signing in from a tool, and who a token acts as. | | |
| 198 | 198 | | [Workspaces](/reference/api/workspaces/create-workspace/) | Creating a workspace. | | |
| 199 | 199 | | [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/). | | |
| 201 | 201 | | [Invites](/reference/api/invites/list-invites/) | Your invites while g1t is invite-only, and inviting people into a workspace by email. | | |
| 202 | 202 | | [Repositories](/reference/api/repositories/list-repos/) | A repository, how it handles pull requests, and its timeline. | | |
| 203 | 203 | | [Access](/reference/api/access/list-collaborators/) | Who has which role on a repository, invitations, outside collaborators, and a workspace's base permission. | |
| 565 | 565 | ||
| 566 | 566 | ## `billing` | |
| 567 | 567 | ||
| 568 | − | A workspace's billing: its usage, its budget, its AI credit and its | |
| 569 | − | invoices. `usage` is the default action. Amounts are whole millionths of a | |
| 568 | + | A workspace's billing: its usage, its budget, its AI credit, its | |
| 569 | + | invoices and its [AI Gateway](/guides/ai-gateway/) requests. `usage` is the default action. Amounts are whole millionths of a | |
| 570 | 570 | dollar (`_micros`), or cents where a field says `_cents`. Members of the | |
| 571 | 571 | workspace read it, a workspace's own token included. Changing the budget | |
| 572 | 572 | and buying AI credit are for its owners, as people: signed in or with a | |
| 583 | 583 | | [`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` | | |
| 584 | 584 | | [`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` | | |
| 585 | 585 | | [`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` | | |
| 586 | + | | [`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` | | |
| 586 | 587 | ||
| 587 | 588 | ## `notifications` | |
| 588 | 589 |
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
This change is too large to show in full.