Skip to content

Conversation

@youneedgreg
Copy link

Pull Request Description: Add Support for GitHub Budgets API

Closes #3930

Summary

This PR adds support for the GitHub Budgets REST API, allowing users to programmatically manage budgets for both Organizations and Enterprises. This includes listing, retrieving, creating (Enterprise only), updating, and deleting budgets.

Changes

Data Structures

  • Added [Budget] and [BudgetAlerting] structs to represent the budget object returned by the API.
  • Included support for modern fields such as limit_amount, current_amount, and alerting configurations.

Organization Budgets ([BillingService])

Added the following methods to [BillingService]:

  • [ListOrganizationBudgets]: GET /organizations/{org}/settings/billing/budgets
  • [GetOrganizationBudget]: GET /organizations/{org}/settings/billing/budgets/{budget_id}
  • [UpdateOrganizationBudget]: PATCH /organizations/{org}/settings/billing/budgets/{budget_id}
  • [DeleteOrganizationBudget]: DELETE /organizations/{org}/settings/billing/budgets/{budget_id}

Enterprise Budgets ([EnterpriseService])

Added the following methods to [EnterpriseService]:

  • [ListEnterpriseBudgets]: GET /enterprises/{enterprise}/settings/billing/budgets
  • [GetEnterpriseBudget]: GET /enterprises/{enterprise}/settings/billing/budgets/{budget_id}
  • [CreateEnterpriseBudget]: POST /enterprises/{enterprise}/settings/billing/budgets
  • [UpdateEnterpriseBudget]: PATCH /enterprises/{enterprise}/settings/billing/budgets/{budget_id}
  • [DeleteEnterpriseBudget]: DELETE /enterprises/{enterprise}/settings/billing/budgets/{budget_id}

Verification Plan

Automated Tests

  • Added [github/billing_budgets_test.go] with unit tests for all organization-level methods.
  • Added [github/enterprise_billing_budgets_test.go] with unit tests for all enterprise-level methods and JSON marshaling validation for the Budget struct.

All tests passed:

go test -v ./github -run 'TestBillingService_.*Budget'
go test -v ./github -run 'TestEnterpriseService_.*Budget'
go test -v ./github -run 'TestBudget_Marshal'

@gmlewis gmlewis changed the title feat: add support for GitHub Budgets API feat: Add support for GitHub Budgets API Jan 21, 2026
@codecov
Copy link

codecov bot commented Jan 21, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.48%. Comparing base (4767af9) to head (57e424b).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3931      +/-   ##
==========================================
+ Coverage   92.44%   92.48%   +0.04%     
==========================================
  Files         203      205       +2     
  Lines       14960    15042      +82     
==========================================
+ Hits        13830    13912      +82     
  Misses        927      927              
  Partials      203      203              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Collaborator

@gmlewis gmlewis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, @youneedgreg!
Just a few tweaks, please, then we should be ready for a second LGTM+Approval from any other contributor to this repo before merging.

cc: @stevehipwell - @alexandear - @zyfy29 - @Not-Dhananjay-Mishra

@gmlewis
Copy link
Collaborator

gmlewis commented Jan 21, 2026

Also, please fix the linter failures and check the code coverage. Step 4 in CONTRIBUTING.md discusses these things.

//
// GitHub API docs: https://docs.github.com/rest/billing/budgets#get-all-budgets-for-an-organization
//
// meta:operation GET /organizations/{org}/settings/billing/budgets
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency use //meta: (no space).

Suggested change
// meta:operation GET /organizations/{org}/settings/billing/budgets
//meta:operation GET /organizations/{org}/settings/billing/budgets

Same applies to other occurrences in this PR.

// GitHub API docs: https://docs.github.com/rest/billing/budgets#delete-a-budget-for-an-organization
//
// meta:operation DELETE /organizations/{org}/settings/billing/budgets/{budget_id}
func (s *BillingService) DeleteOrganizationBudget(ctx context.Context, org string, budgetID string) (*Response, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to Docs this endpoint also returns an object.
Image


// GetEnterpriseBudget gets a specific budget for an enterprise.
//
// GitHub API docs: https://docs.github.com/rest/billing/budgets#get-a-budget-for-an-enterprise
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// GitHub API docs: https://docs.github.com/rest/billing/budgets#get-a-budget-for-an-enterprise
// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#get-a-budget-by-id

https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#get-a-budget-by-id


// CreateEnterpriseBudget creates a specific budget for an enterprise.
//
// GitHub API docs: https://docs.github.com/rest/billing/budgets#create-a-budget
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// GitHub API docs: https://docs.github.com/rest/billing/budgets#create-a-budget
// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#create-a-budget

https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#create-a-budget


// UpdateEnterpriseBudget updates a specific budget for an enterprise.
//
// GitHub API docs: https://docs.github.com/rest/billing/budgets#update-a-budget-for-an-enterprise
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// GitHub API docs: https://docs.github.com/rest/billing/budgets#update-a-budget-for-an-enterprise
// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#update-a-budget

https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#update-a-budget


// DeleteEnterpriseBudget deletes a specific budget for an enterprise.
//
// GitHub API docs: https://docs.github.com/rest/billing/budgets#delete-a-budget-for-an-enterprise
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// GitHub API docs: https://docs.github.com/rest/billing/budgets#delete-a-budget-for-an-enterprise
// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#delete-a-budget

https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#delete-a-budget


// ListEnterpriseBudgets lists all budgets for an enterprise.
//
// GitHub API docs: https://docs.github.com/rest/billing/budgets#get-all-budgets-for-an-enterprise
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// GitHub API docs: https://docs.github.com/rest/billing/budgets#get-all-budgets-for-an-enterprise
// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#get-all-budgets

https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#get-all-budgets

)

// Budget represents a GitHub budget.
type Budget struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Response schema of Budget

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "ID of the budget."
    },
    "budget_scope": {
      "type": "string",
      "description": "The type of scope for the budget",
      "enum": [
        "enterprise",
        "organization",
        "repository",
        "cost_center"
      ],
      "examples": [
        "enterprise"
      ]
    },
    "budget_entity_name": {
      "type": "string",
      "description": "The name of the entity to apply the budget to",
      "examples": [
        "octocat/hello-world"
      ]
    },
    "budget_amount": {
      "type": "integer",
      "description": "The budget amount in whole dollars. For license-based products, this represents the number of licenses."
    },
    "prevent_further_usage": {
      "type": "boolean",
      "description": "Whether to prevent additional spending once the budget is exceeded",
      "examples": [
        true
      ]
    },
    "budget_product_sku": {
      "type": "string",
      "description": "A single product or sku to apply the budget to.",
      "examples": [
        "actions_linux"
      ]
    },
    "budget_type": {
      "type": "string",
      "description": "The type of pricing for the budget",
      "enum": [
        "ProductPricing",
        "SkuPricing"
      ],
      "examples": [
        "ProductPricing"
      ]
    },
    "budget_alerting": {
      "type": "object",
      "properties": {
        "will_alert": {
          "type": "boolean",
          "description": "Whether alerts are enabled for this budget",
          "examples": [
            true
          ]
        },
        "alert_recipients": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Array of user login names who will receive alerts",
          "examples": [
            "mona",
            "lisa"
          ]
        }
      }
    }
  },
  "required": [
    "id",
    "budget_amount",
    "prevent_further_usage",
    "budget_product_sku",
    "budget_type",
    "budget_alerting",
    "budget_scope",
    "budget_entity_name"
  ]
}

it has few missing items -
budget_scope, budget_entity_name, budget_amount, prevent_further_usage, budget_product_sku.

// GitHub API docs: https://docs.github.com/rest/billing/budgets#delete-a-budget-for-an-enterprise
//
// meta:operation DELETE /enterprises/{enterprise}/settings/billing/budgets/{budget_id}
func (s *EnterpriseService) DeleteEnterpriseBudget(ctx context.Context, enterprise string, budgetID string) (*Response, error) {
Copy link
Contributor

@Not-Dhananjay-Mishra Not-Dhananjay-Mishra Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It also returns an object
Image

@youneedgreg
Copy link
Author

youneedgreg commented Jan 21, 2026

Hi @gmlewis , finished and made sure all checks passed, Thank you.

// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/billing/budgets#get-all-budgets
//
//meta:operation GET /enterprises/{enterprise}/settings/billing/budgets
func (s *EnterpriseService) ListEnterpriseBudgets(ctx context.Context, enterprise string) ([]*Budget, *Response, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we call this in Enterprise service we can simplify naming:

Suggested change
func (s *EnterpriseService) ListEnterpriseBudgets(ctx context.Context, enterprise string) ([]*Budget, *Response, error) {
func (s *EnterpriseService) ListBudgets(ctx context.Context, enterprise string) ([]*Budget, *Response, error) {

Am I missing something?

// GitHub API docs: https://docs.github.com/rest/billing/budgets#get-all-budgets-for-an-organization
//
//meta:operation GET /organizations/{org}/settings/billing/budgets
func (s *BillingService) ListOrganizationBudgets(ctx context.Context, org string) ([]*Budget, *Response, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This endpoint returns a response with the following shape:

{
  "budgets": [
    {
      "id": "2066deda-923f-43f9-88d2-62395a28c0cdd",
      "budget_type": "ProductPricing",
      "budget_product_skus": [
        "actions"
      ],
      "budget_scope": "enterprise",
      "budget_amount": 1000,
      "prevent_further_usage": true,
      "budget_alerting": {
        "will_alert": true,
        "alert_recipients": [
          "enterprise-admin",
          "billing-manager"
        ]
      }
    },
    {
      "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "budget_type": "SkuPricing",
      "budget_product_skus": [
        "actions_linux"
      ],
      "budget_scope": "organization",
      "budget_amount": 500,
      "prevent_further_usage": false,
      "budget_alerting": {
        "will_alert": true,
        "alert_recipients": [
          "org-owner"
        ]
      }
    }
  ],
  "has_next_page": false
}

I believe it should return a struct like

{
	Budgets     []Budget `json:"budgets"`
	HasNextPage bool     `json:"has_next_page,omitempty"`
}

// GitHub API docs: https://docs.github.com/rest/billing/budgets#update-a-budget-for-an-organization
//
//meta:operation PATCH /organizations/{org}/settings/billing/budgets/{budget_id}
func (s *BillingService) UpdateOrganizationBudget(ctx context.Context, org, budgetID string, budget *Budget) (*Budget, *Response, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This endpoint returns a response with the following shape:

{
  "message": "Budget successfully updated.",
  "budget": {
    "id": "2066deda-923f-43f9-88d2-62395a28c0cdd",
    "budget_type": "SkuPricing",
    "budget_product_sku": "actions",
    "budget_scope": "enterprise",
    "budget_amount": 500,
    "prevent_further_usage": true,
    "budget_alerting": {
      "will_alert": true,
      "alert_recipients": ["mona"]
    }
  }
}

I believe it should return a struct like

{
	Budget     Budget `json:"budget"`
	Message    string `json:"message"`
}

// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/billing/budgets#get-all-budgets
//
//meta:operation GET /enterprises/{enterprise}/settings/billing/budgets
func (s *EnterpriseService) ListBudgets(ctx context.Context, enterprise string) ([]*Budget, *Response, error) {
Copy link
Contributor

@Not-Dhananjay-Mishra Not-Dhananjay-Mishra Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as comment

// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/billing/budgets#create-a-budget
//
//meta:operation POST /enterprises/{enterprise}/settings/billing/budgets
func (s *EnterpriseService) CreateBudget(ctx context.Context, enterprise string, budget *Budget) (*Budget, *Response, error) {
Copy link
Contributor

@Not-Dhananjay-Mishra Not-Dhananjay-Mishra Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as comment

// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/billing/budgets#update-a-budget
//
//meta:operation PATCH /enterprises/{enterprise}/settings/billing/budgets/{budget_id}
func (s *EnterpriseService) UpdateBudget(ctx context.Context, enterprise, budgetID string, budget *Budget) (*Budget, *Response, error) {
Copy link
Contributor

@Not-Dhananjay-Mishra Not-Dhananjay-Mishra Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support budgets

4 participants