Help us shape the future of Go! Take the 2026 Go Developer Survey

curseforge

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 18 Imported by: 0

README

go-curseforge

Go


A client for the CurseForge API: mods, files, categories and download links, with the distribution flag and API-key header handled. Package curseforge, module github.com/Rethunk-Tech/go-curseforge.

CurseForge sends the API key in a header, forbids downloads for some mods, and answers with large JSON. This client puts the key in a header only, so no error or log line quotes it, caps every answer at 16 MiB, refuses redirects to another origin, and reports a file whose author forbids distribution instead of fetching around it. It never downloads a mod file.

Quick start

go get github.com/Rethunk-Tech/go-curseforge

A worked example and the contracts: HUMANS.md.

Features

  • Search with class, category, game-version and sort filters, up to the API's 10,000-row window.
  • Mods (one or a batch), files, descriptions, changelogs, classes and categories, with the full response fields.
  • Client.DownloadURL and Mod.Restricted tell a distributable file from one the author keeps on CurseForge.
  • Typed errors: httpkit.StatusError (404 matches httpkit.ErrNotFound) and httpkit.RateLimitError with Retry-After.
  • ParseLink reads curseforge://install links; Newest picks a mod's newest file by release channel.

Documentation

Doc Audience
HUMANS.md Running and using the package
AGENTS.md Internals, invariants, and why
CONTRIBUTING.md Process — commits, tests, docs
SECURITY.md Vulnerability disclosure
CHANGELOG.md Release notes

License

MIT — see LICENSE. © 2026 Rethunk.Tech, LLC.

Documentation

Overview

Package curseforge is a client for the CurseForge Core API (v1): mod search, mods, files, categories and classes, download addresses, and curseforge:// install links.

The API key rides in the X-Api-Key header only, so no error or log line quotes it. A file whose author forbids distribution outside CurseForge has no download address; Mod.Restricted and the ErrNoDownload result of Client.DownloadURL report it, and this package never fetches around it. Mod files are never downloaded here.

Index

Constants

View Source
const (
	// BaseURL is the real API.
	BaseURL = "https://api.curseforge.com/v1"

	// MaxWindow is how deep the API pages: Index plus PageSize may not pass it.
	MaxWindow = 10000
	// MaxPageSize is the most mods one Search request returns.
	MaxPageSize = 50
)
View Source
const (
	SortFeatured        = 1
	SortPopularity      = 2
	SortLastUpdated     = 3
	SortName            = 4
	SortAuthor          = 5
	SortTotalDownloads  = 6
	SortCategory        = 7
	SortGameVersion     = 8
	SortEarlyAccess     = 9
	SortFeaturedRelease = 10
	SortReleasedDate    = 11
	SortRating          = 12
)

Values of ModsSearchSortField (https://docs.curseforge.com/rest-api/#tocS_ModsSearchSortField).

View Source
const (
	ReleaseStable = 1
	ReleaseBeta   = 2
	ReleaseAlpha  = 3
)

Values of FileReleaseType.

View Source
const (
	RelationEmbeddedLibrary = 1
	RelationOptional        = 2
	RelationRequired        = 3
	RelationTool            = 4
	RelationIncompatible    = 5
	RelationInclude         = 6
)

Values of FileRelationType.

View Source
const (
	HashSHA1 = 1
	HashMD5  = 2
)

Values of HashAlgo.

View Source
const (
	StatusNew             = 1
	StatusChangesRequired = 2
	StatusUnderSoftReview = 3
	StatusApproved        = 4
	StatusRejected        = 5
	StatusChangesMade     = 6
	StatusInactive        = 7
	StatusAbandoned       = 8
	StatusDeleted         = 9
	StatusUnderReview     = 10
)

Values of ModStatus.

View Source
const Scheme = "curseforge"

Scheme is the scheme of the site's Install button.

Variables

View Source
var (
	// ErrNoKey means the Client has no API key; nothing is sent.
	ErrNoKey = errors.New("curseforge: no API key")
	// ErrBeyondWindow means a search asked past MaxWindow.
	ErrBeyondWindow = errors.New("curseforge: search window exceeded")
	// ErrNoDownload means the API gave no download address for a file: its author forbids downloads outside
	// CurseForge.
	ErrNoDownload = errors.New("curseforge: file has no download address")
)

Functions

func AuthorFilesURL added in v0.3.0

func AuthorFilesURL(projectID int) string

AuthorFilesURL is the author-site page that lists a project's files.

func Denied

func Denied(err error) bool

Denied reports an answer of 401 or 403, which means a bad key or a file the key may not fetch.

Types

type Asset

type Asset struct {
	ID           int    `json:"id"`
	ModID        int    `json:"modId"`
	Title        string `json:"title"`
	Description  string `json:"description"`
	ThumbnailURL string `json:"thumbnailUrl"`
	URL          string `json:"url"`
}

Asset is an image of a mod.

type Category

type Category struct {
	ID               int    `json:"id"`
	GameID           int    `json:"gameId"`
	Name             string `json:"name"`
	Slug             string `json:"slug"`
	URL              string `json:"url"`
	IconURL          string `json:"iconUrl"`
	DateModified     string `json:"dateModified"`
	IsClass          bool   `json:"isClass"`
	ClassID          int    `json:"classId"`
	ParentCategoryID int    `json:"parentCategoryId"`
	DisplayIndex     int    `json:"displayIndex"`
}

Category is a category, or when IsClass is true a class (a top-level kind of content such as "Mods").

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client calls the CurseForge API. It holds no state beyond its configuration, so it is safe for concurrent use and cheap to build again when the key changes.

func New

func New(cfg Config) *Client

New builds a Client.

func (*Client) Categories

func (c *Client) Categories(ctx context.Context, gameID, classID int) ([]Category, error)

Categories lists the categories of one class of a game.

func (*Client) Changelog

func (c *Client) Changelog(ctx context.Context, modID, fileID int) (string, error)

Changelog reads one file's changelog, which is HTML.

func (*Client) Classes

func (c *Client) Classes(ctx context.Context, gameID int) ([]Category, error)

Classes lists a game's classes (top-level kinds of content, such as "Mods").

func (*Client) Description

func (c *Client) Description(ctx context.Context, id int) (string, error)

Description reads a project's long description, which is HTML.

func (*Client) DownloadURL

func (c *Client) DownloadURL(ctx context.Context, modID, fileID int) (string, error)

DownloadURL asks the API for a file's address. A refusal (see Denied) or an empty answer means the author forbids downloads outside CurseForge; the empty answer is ErrNoDownload.

func (*Client) File

func (c *Client) File(ctx context.Context, modID, fileID int) (File, error)

File reads one file of a project.

func (*Client) Files

func (c *Client) Files(ctx context.Context, modID int, q FilesQuery) (FilesResult, error)

Files lists a project's files. A zero PageSize is 50, the API's maximum.

func (*Client) Mod

func (c *Client) Mod(ctx context.Context, id int) (Mod, error)

Mod reads one project.

func (*Client) Mods

func (c *Client) Mods(ctx context.Context, ids []int) ([]Mod, error)

Mods reads many projects with their latest files in one request (POST /mods). The API caps the batch; split long lists. A mod the API does not know is absent from the answer.

func (*Client) Search

func (c *Client) Search(ctx context.Context, q SearchQuery) (SearchResult, error)

Search lists mods. A ClassID restricts the search to that class.

type Config

type Config struct {
	// APIKey is sent in the X-Api-Key header. Empty makes every call fail with ErrNoKey.
	APIKey string
	// HTTP sends every request; nil means http.DefaultClient. Redirects to another origin are refused so the key
	// stays with the API.
	HTTP *http.Client
	// BaseURL is the API; empty means BaseURL.
	BaseURL string
	// UserAgent is sent with every request when set.
	UserAgent string
}

Config is what a Client is built from.

type Dependency

type Dependency struct {
	ModID int `json:"modId"`
	// RelationType is one of the Relation constants.
	RelationType int `json:"relationType"`
}

Dependency is a relation between a file and another mod.

type File

type File struct {
	ID          int    `json:"id"`
	GameID      int    `json:"gameId"`
	ModID       int    `json:"modId"`
	IsAvailable bool   `json:"isAvailable"`
	DisplayName string `json:"displayName"`
	FileName    string `json:"fileName"`
	// ReleaseType is ReleaseStable, ReleaseBeta or ReleaseAlpha.
	ReleaseType   int    `json:"releaseType"`
	FileStatus    int    `json:"fileStatus"`
	Hashes        []Hash `json:"hashes"`
	FileDate      string `json:"fileDate"`
	FileLength    int64  `json:"fileLength"`
	DownloadCount int64  `json:"downloadCount"`
	// DownloadURL is empty when the author forbids distribution outside CurseForge.
	DownloadURL  string       `json:"downloadUrl"`
	GameVersions []string     `json:"gameVersions"`
	Dependencies []Dependency `json:"dependencies"`
}

File is one published file of a mod.

func Newest

func Newest(files []File, gameVersions []string, maxRelease int) (File, bool)

Newest picks the newest available file, keeping to files for one of gameVersions when it names any. With maxRelease ReleaseStable a stable file wins over a newer beta, and a mod with no stable file yields its newest other one; a higher maxRelease takes the newest file whose release type is at most maxRelease.

func (File) Required

func (f File) Required() []int

Required lists the ids of the mods this file requires.

func (File) SHA1

func (f File) SHA1() string

SHA1 is the file's SHA-1, lower-case hex, or "" when the API lists none.

type FilesQuery

type FilesQuery struct {
	GameVersion     string
	Index, PageSize int
}

FilesQuery narrows Files. Zero fields are not sent.

type FilesResult

type FilesResult struct {
	Files      []File     `json:"data"`
	Pagination Pagination `json:"pagination"`
}

FilesResult is one page of a mod's files.

type Hash

type Hash struct {
	Value string `json:"value"`
	// Algo is HashSHA1 or HashMD5.
	Algo int `json:"algo"`
}

Hash is one checksum of a file.

type Mod

type Mod struct {
	ID                int    `json:"id"`
	GameID            int    `json:"gameId"`
	Name              string `json:"name"`
	Slug              string `json:"slug"`
	Summary           string `json:"summary"`
	Status            int    `json:"status"`
	DownloadCount     int    `json:"downloadCount"`
	ThumbsUpCount     int    `json:"thumbsUpCount"`
	PrimaryCategoryID int    `json:"primaryCategoryId"`
	ClassID           int    `json:"classId"`
	MainFileID        int    `json:"mainFileId"`
	DateCreated       string `json:"dateCreated"`
	DateModified      string `json:"dateModified"`
	DateReleased      string `json:"dateReleased"`
	// AllowModDistribution is nil when the API did not say; false forbids downloads outside CurseForge.
	AllowModDistribution *bool `json:"allowModDistribution"`
	// IsAvailable is what the API said, or true when it omitted the field. Use Available.
	IsAvailable bool `json:"isAvailable"`
	IsFeatured  bool `json:"isFeatured"`

	Links struct {
		WebsiteURL string `json:"websiteUrl"`
		WikiURL    string `json:"wikiUrl"`
		IssuesURL  string `json:"issuesUrl"`
		SourceURL  string `json:"sourceUrl"`
	} `json:"links"`
	Authors []struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
		URL  string `json:"url"`
	} `json:"authors"`
	Screenshots []Asset    `json:"screenshots"`
	Categories  []Category `json:"categories"`
	LatestFiles []File     `json:"latestFiles"`
	// contains filtered or unexported fields
}

Mod is a CurseForge project. Dates are the API's RFC 3339 strings, which compare correctly as text.

func (Mod) Available added in v0.2.0

func (m Mod) Available() bool

Available reports that the mod can be used: false only when the API said isAvailable: false. A mod built in code without that answer is available.

func (Mod) CategoryNames

func (m Mod) CategoryNames() []string

CategoryNames lists the names of the mod's categories.

func (Mod) Restricted

func (m Mod) Restricted() bool

Restricted reports that the author forbids downloads outside CurseForge. An unknown flag is not restricted.

func (*Mod) UnmarshalJSON added in v0.2.0

func (m *Mod) UnmarshalJSON(b []byte) error

UnmarshalJSON reads a Mod and remembers whether the API sent isAvailable.

type Pagination

type Pagination struct {
	Index       int `json:"index"`
	PageSize    int `json:"pageSize"`
	ResultCount int `json:"resultCount"`
	TotalCount  int `json:"totalCount"`
}

Pagination is the position of a page within a result.

type Ref

type Ref struct {
	Project, File int
}

Ref names one file of a project in an install link.

func ParseLink(raw string) (Ref, error)

ParseLink reads curseforge://install?addonId=<project>&fileId=<file>. Both ids must be positive; any other host, a path, userinfo or a fragment is refused. Other query keys are ignored.

type SearchQuery

type SearchQuery struct {
	GameID  int
	ClassID int
	// CategoryIDs keeps mods in every listed category (the API ANDs them; at most 10).
	CategoryIDs []int
	GameVersion string
	Text        string
	// SortField is one of the Sort constants; zero keeps the API's default.
	SortField int
	// Ascending reverses the API's default descending order.
	Ascending bool
	// Index is the offset of the first mod and PageSize the page length, at most MaxPageSize; zero PageSize is 50.
	Index, PageSize int
}

SearchQuery is one /mods/search request. GameID is required; zero fields are not sent.

type SearchResult

type SearchResult struct {
	Mods       []Mod      `json:"data"`
	Pagination Pagination `json:"pagination"`
}

SearchResult is one page of mods.

type UploadConfig added in v0.3.0

type UploadConfig struct {
	// Token is the author's upload token, sent in the X-Api-Token header. It is not the API key of Config.
	Token string
	// BaseURL is the origin of the game's upload API, such as https://minecraft.curseforge.com; it has no default
	// because each game answers on its own host.
	BaseURL string
	// HTTP sends every request; nil means http.DefaultClient. Redirects to another origin are refused so the token
	// stays with the upload host.
	HTTP *http.Client
	// UserAgent is sent with every request when set.
	UserAgent string
}

UploadConfig is what an Uploader is built from.

type Uploader added in v0.3.0

type Uploader struct {
	// contains filtered or unexported fields
}

Uploader publishes a file to a CurseForge project through the author upload API.

func NewUploader added in v0.3.0

func NewUploader(cfg UploadConfig) *Uploader

NewUploader builds an Uploader.

func (*Uploader) Upload added in v0.3.0

func (u *Uploader) Upload(ctx context.Context, path string, projectID int, displayName, changelog string) (int, error)

Upload sends the zip at path to the project as a release named displayName, with changelog as markdown, and returns the new file's id. A 401 or 403 is a *httpkit.StatusError that Denied matches, and a 429 a *httpkit.RateLimitError.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL