Blog Post

FinOps Blog
12 MIN READ

Cap it with GitHub, make it count with Azure: governing GitHub Copilot spend

tonimontez's avatar
tonimontez
Icon for Microsoft rankMicrosoft
Jul 27, 2026

When GitHub Copilot moved to usage-based billing, a predictable per-seat cost became a variable one, and teams now have to answer two questions: how do we control this spend, and how do we make it count on infrastructure we already own? GitHub's native budgets are the right first move. This post shows the next layer for teams that need it: route Copilot's bring-your-own-key through an Azure API Management gateway in front of Azure AI Foundry, and you get real-time per-developer token quotas, per-developer metrics in Azure Monitor, and the token consumption on your own Azure meters. It ships with a one-command azd sample you can deploy and try.

The good news is that GitHub gives you real native controls, and you should turn them on first. The part worth writing down is where those native controls stop, and what an Azure API Management gateway plus GitHub Copilot bring-your-own-key adds on top. This is a two-layer story, not a replacement story.

A companion note: for reducing the consumption itself (choosing the right model, leaning on completions, scoping tools and context, plan-first prompts), see the recent guide "Optimizing GitHub Copilot Cost in the Usage-Based Billing Era" by Gaurav Bhardwaj and Dustin Ellis. This piece is the other half: not how to use fewer tokens, but how to govern the spend you do have and decide which meter it lands on.

What changed

GitHub Copilot usage is priced in AI credits at one cent each. Existing Business and Enterprise seats got a promotional credit uplift for June, July, and August that ends on September 1, 2026:

  • GitHub Copilot Enterprise: 7,000 included credits per user per month during the promo, reverting to 3,900.
  • GitHub Copilot Business: 3,000 included credits per user per month during the promo, reverting to 1,900.

After the cushion ends, everything past the included allowance is metered overage. Code completions remain included and unmetered, so this is specifically about chat, CLI, and agent usage.

Layer 1: the native controls, and their limits

Turn these on before you build anything. They require no infrastructure and, importantly, they cover every GitHub Copilot surface including GitHub.com.

Budgets that can hard-stop. GitHub provides budget controls at up to four levels (all four on enterprise accounts):

  • User-level budgets (ULBs). A per-user cap on AI credits per billing cycle, covering both pooled and metered usage. ULBs are always a hard stop: when a user hits the cap, credit-consuming GitHub Copilot features are blocked until the next cycle. A $0 budget blocks a user entirely.
  • Cost-center budgets for a team or business unit, organization budgets, and an enterprise spending limit on total metered charges once the pool is exhausted.

One nuance worth knowing: user-level budgets are always hard stops, but the higher-level spending limits only notify by default. To make them block, enable "Stop usage when budget limit is reached" on each one.

Per-user usage metrics. The GitHub Copilot usage metrics API exposes a per-user ai_credits_used field (in the single-day and 28-day user reports), which you can export as NDJSON for chargeback or BI. Two caveats: it is an aggregate per user, not broken down by feature, model, or surface, and the telemetry runs on roughly a two-day lag, so it is not real-time.

Where native controls stop. They are excellent guardrails, but note what they are not:

  • They are monthly financial caps in credits or dollars, not token-count quotas, and not time-windowed rate limits. You cannot natively say "500,000 tokens per developer per week."
  • Budget alerts are fixed thresholds (75%, 90%, 100%) on a lagging financial meter — useful, but not real-time token telemetry, and the per-user metrics themselves run about two days behind.
  • The consumption itself stays on GitHub's models and GitHub's meter. You can route the billing to Azure (GitHub supports paying for Copilot through a connected Azure subscription, and GitHub's billing docs state that GitHub products on an Azure invoice are MACC-eligible — confirm on your own agreement), but the tokens are still GitHub-hosted consumption: no token-level control, no choice of deployment, no Azure-native telemetry.

If none of those limits matter to you, stop here. The native controls are enough. The next layer is for the teams they do not cover.

Layer 2: the APIM + BYOK upgrade

GitHub Copilot supports bring-your-own-key (BYOK): pointing GitHub Copilot at your own model endpoint instead of GitHub's hosted models. If that endpoint is an Azure AI Foundry (Azure OpenAI) deployment fronted by Azure API Management, three things become possible that native controls cannot do:

  1. Real-time, token-granular quotas. APIM can enforce a weekly per-developer token budget and cut off live, rather than a monthly financial cap reconciled after the fact.
  2. The consumption becomes your own Azure consumption. Tokens run against your Foundry deployment on your Azure meters — first-party Azure spend, with Azure-native telemetry, alerting, and the standard commitment treatment of any Foundry usage (confirm MACC specifics on your agreement). Billing GitHub through Azure routes the charges; BYOK moves the consumption.
  3. Your provider and your policies. Useful for an alternate model, data-residency needs, or governance that goes beyond what GitHub exposes.

The trade-off is that this only applies to the surfaces that support a custom endpoint, and it opts those surfaces out of GitHub's billing (you pay the Azure meter instead).

Which surfaces support it

  • VS Code: yes. The Custom Endpoint provider is stable as of VS Code 1.122. It sends the key as an Authorization: Bearer token, and the gateway accepts that — its policy authenticates on either Authorization: Bearer (VS Code) or api-key (the CLI), and we tested both against the gateway. Set the model's full endpoint URL (ending in /chat/completions — VS Code does not append it) in chatLanguageModels.json. Two client-side details will save you an afternoon: enter the key through the Add Models wizard rather than pasting it into the JSON (a raw key string makes VS Code send an empty Bearer and the gateway returns 401), and configure a utility model for BYOK — set chat.byokUtilityModelDefault to mainAgent, or point the utility models at Copilot's default — or Copilot stops with "No utility model is configured." Pin 1.122 as a hard floor: earlier builds chose the wrong auth header for a gateway host and failed with 401 (vscode #317810). For Business and Enterprise, the org's "Bring Your Own Language Model Key" policy must be enabled.
  • JetBrains IDEs: documented for BYOK, but we have not tested the gateway hop there — and there is at least one open community report of the plugin ignoring a custom base URL. Validate in your pilot before promising it.
  • GitHub Copilot CLI: yes — we verified this client live through the gateway (the CLI's own token count matched the gateway's per-developer meter to within rounding). The configuration is below.
  • GitHub Copilot on GitHub.com (web chat, PR features): no custom endpoint. GitHub.com always runs through GitHub's service. Enterprise BYOK there is a tenant-level provider-key configuration, not an arbitrary URL, so you cannot put your APIM gateway in front of it. Govern these surfaces with the native budgets from Layer 1.

The CLI configuration we verified uses the azure provider type pointed at the bare gateway host:

export COPILOT_PROVIDER_TYPE=azure
export COPILOT_PROVIDER_BASE_URL=https://your-gateway.azure-api.net
export COPILOT_PROVIDER_API_KEY=YOUR-APIM-SUBSCRIPTION-KEY
export COPILOT_MODEL=your-deployment
copilot

The azure type ignores any path in the base URL and requests {host}/openai/v1/chat/completions, so mount the gateway API at the root. It sends the key as the api-key header; VS Code's Custom Endpoint sends it as Authorization: Bearer; the gateway accepts both. Give each developer their own APIM subscription key so the gateway meters per person, and size the model deployment's TPM capacity for agentic clients — the CLI carries a system prompt of roughly 17,000 tokens per turn.

One gotcha to route around

If you configure BYOK using the built-in "Microsoft Foundry" provider, it validates the endpoint hostname against a pattern such as *.services.ai.azure.com or *.openai.azure.com, and it rejects an APIM gateway URL before any request is sent (this is the subject of GitHub community discussion #198472). The way around it is to not use the Foundry provider type. Register your gateway as an OpenAI-compatible custom endpoint instead. APIM's LLM policies already speak the OpenAI Chat Completions schema that a Foundry deployment exposes, so the request shapes line up.

The constraint here is on the GitHub Copilot side only. Azure fully supports and documents putting APIM in front of a Foundry deployment as an AI gateway; what is not yet officially endorsed is GitHub Copilot BYOK pointing at that gateway, which is why the pilot matters.

The APIM policies

Two generally available policies do the governance work.

A per-developer weekly token budget. The llm-token-limit policy enforces a token quota over a period (including weekly) per caller, and returns 403 Forbidden when the quota is spent. Key it with counter-key to whatever identifies a developer:

<policies>
  <inbound>
    <base />
    <llm-token-limit
        counter-key="@(context.Subscription.Id)"
        token-quota="500000"
        token-quota-period="Weekly"
        estimate-prompt-tokens="false"
        remaining-quota-tokens-header-name="x-remaining-token-quota" />
  </inbound>
  <outbound>
    <base />
  </outbound>
</policies>

That is a 500,000-token weekly budget per developer (the companion repo defaults to 1,000,000 — it is a parameter), with the remaining balance returned on a response header. This is the real-time, token-granular control native budgets do not offer. When the quota is spent, the gateway returns 403 with the time remaining until the weekly window resets (and a Retry-After header). Streaming responses pass through and are counted against the quota too — APIM estimates token counts for streamed responses, so the arithmetic is approximate but the cap holds. We verified both behaviors on a live deployment, along with the OpenAI-compatible /models and /responses routes that BYOK clients probe. One detail worth flagging, because it bit us: VS Code and the CLI send the key in different headers — VS Code an Authorization: Bearer token, the CLI an api-key header — so the companion repo authenticates in policy, accepts either, and keys the quota and metric on a developer id it resolves from the caller's key rather than on an APIM subscription. Note the consequence for the two snippets: once you accept both headers, subscriptionRequired is off and context.Subscription.Id is null, so keying on it would collapse every developer into a single bucket. Resolve a developer id from the caller's key and use that for both the counter-key and the metric dimension (the repo names that dimension Developer). The snippets below show the simplest subscription-keyed case; the repo shows the dual-header version.

Per-developer token metrics in Azure Monitor. The llm-emit-token-metric policy sends token counts to Application Insights, where Azure Monitor can alert on them. Add a dimension to slice by developer; Subscription ID is a built-in dimension:

<policies>
  <inbound>
    <base />
    <llm-emit-token-metric namespace="llm">
      <dimension name="Subscription ID" />
    </llm-emit-token-metric>
  </inbound>
  <outbound>
    <base />
  </outbound>
</policies>

The core policy (total, prompt, and completion token metrics) is generally available; the expanded categories such as cached and reasoning tokens are in preview. It requires APIM integrated with Application Insights with custom metrics enabled (custom metrics with dimensions is itself an Azure Monitor preview capability). One honest note on alerting: Azure Monitor metric alerts evaluate over at most a one-day window, so you cannot alert on "80 percent of the weekly quota" directly — the companion repo instead ships a burn-rate alert that fires when a developer's 24-hour consumption reaches the weekly budget's daily pace. Between the hard 403 and that early warning, the governance loop is closed, and the consumption itself is standard Foundry usage on your Azure meters.

 

Per-developer token metering in Azure Monitor: two developers running GitHub Copilot through the same APIM gateway in front of Foundry, each metered and quota-governed separately.

How to choose

  • Start with native budgets and metrics. They cover every surface, need no infrastructure, and are the right control for GitHub.com.
  • Add the APIM + BYOK upgrade only where its specific gains matter: you need real-time token-granular quotas or alerts, you want the consumption itself on your own Azure meters, or you need an alternate provider. It applies to IDE and CLI, not GitHub.com.
  • Most enterprises will run both side by side: native budgets everywhere as the floor, and the Azure upgrade for the IDE and CLI usage where real-time control and Azure-meter consolidation pay off.

A pilot before the cliff

We deployed this architecture and verified it end to end — including with a real GitHub Copilot client: the Copilot CLI completed through APIM to the Foundry deployment on a per-developer key, and the gateway's token meter matched the CLI's own token count. OpenAI-compatible requests (including streaming) flow through on a managed identity, the weekly per-developer quota enforces with a 403 when spent, and per-developer token metrics land in Application Insights. The companion repo (linked in Sources) stands the whole Azure side up with a single azd up.

What a short pilot in your own tenant still validates — because these are yours, not ours:

  1. The IDE client wiring on the editors your developers actually use (we verified the CLI and VS Code against the gateway; JetBrains is a documented path we have not tested. Business and Enterprise need the org BYOK policy enabled).
  2. The spend drawing down your MACC, confirmed on your own agreement.
  3. Native budgets still holding the line on GitHub.com and any non-BYOK usage.

The reason to do it now is the calendar: the promotional cushion ends September 1. Turn native budgets on today, and have the Azure upgrade proven and in place before the real overage begins.

What to confirm before production

  • Know which "BYOK" is preview. "BYOK is public preview" is too broad. The enterprise-governed BYOK program — connecting a provider key in org or enterprise settings — is public preview (GitHub, 2025-11-20). The VS Code Custom Endpoint mechanism this uses is stable as of VS Code 1.122, and the Copilot SDK has its own separate BYOK. So the mechanism is shippable today while the tenant-wide governed rollout is still preview. Re-check the client support matrix and org policy names against current docs before you roll out — the pre-1.122 auth-header bug is a concrete example of an edge that moved within weeks.
  • MACC treatment: confirm both paths on your own agreement. BYOK-to-Foundry token spend is standard Azure consumption, and Microsoft documents that Azure consumption counts toward a MACC — but there is no GitHub Copilot-BYOK-specific MACC statement, so treat the composition as an inference. Meanwhile, on the native side, GitHub documents that Copilot can be billed through a connected Azure subscription and that GitHub products on an Azure invoice are MACC-eligible — also without naming Copilot credits in the MACC sentence. Neither path should anchor a burn-down plan until your account team confirms it in writing.
  • Do not confuse GitHub Copilot BYOK with GitHub Models. GitHub Models (a separate model catalog, playground, and inference API, with its own BYOK endpoints) is being retired on July 30, 2026. That retirement does not affect GitHub Copilot's BYOK, which is a distinct feature and the one this piece uses.
  • Billing GitHub through Azure is a different mechanism from BYOK. Microsoft documents a GitHub Pre-Purchase plan (commit units purchased through Azure that cover GitHub Copilot and AI overage), and GitHub documents pay-as-you-go Copilot billing through a connected Azure subscription. Both route GitHub charges onto your Azure invoice; neither moves the token consumption — the models, telemetry, and controls stay GitHub's. BYOK is the path that moves the consumption itself.
  • Surface support varies by client and version. Check the current matrix for the clients your developers actually use.

The short version

GitHub Copilot spend is now variable, and after September 1 the included cushion shrinks. GitHub's native budgets and metrics are real and should be your first move, on every surface. Where you need real-time token-granular control, or you want the consumption itself on your own Azure meters, route BYOK through an APIM gateway in front of a Foundry deployment, on IDE and CLI. Prove that upgrade in a short pilot before the cliff, and let native controls carry the floor from day one.

Sources

Related reading: to reduce the consumption itself (model choice, leaning on completions, scoping tools and context), see "Optimizing GitHub Copilot Cost in the Usage-Based Billing Era" by Gaurav Bhardwaj and Dustin Ellis on the Microsoft Tech Community. That piece is about using fewer tokens; this one is about governing the spend you do have and choosing which meter it lands on.

Updated Jul 21, 2026
Version 1.0

3 Comments

  • Monanton's avatar
    Monanton
    Copper Contributor

    Awesome article!  I appreciate the effort required to produce it and it should be helpful for anyone/org trying to get their spend under control…. Thanks