API & publishing from the command line
Everything the website does is available over a JSON API, so you can publish from scripts and CI.
Authentication
Create a token under Settings → API tokens and send it as a bearer token. Tokens are shown once; keep them secret and revoke any you lose.
export C3PKG_TOKEN=c3p_…
curl -H "Authorization: Bearer $C3PKG_TOKEN" https://www.c3pkg.eu/api/v1/me
Errors are JSON: {"error": "…", "errors": {"field": "message"}}. Requests are rate limited; on 429 wait for the Retry-After seconds.
Publish a library
A .c3l is a zip with manifest.json at its root. The package name is the manifest's provides, and it must match the name in the URL. Versions are semver (1.2.3 or 1.2.3-rc.1) and can never be changed once published.
# new package: description is required the first time
curl -X PUT -H "Authorization: Bearer $C3PKG_TOKEN" \
-F file=@vk.c3l -F c3_version=0.7.5 \
-F description="Vulkan bindings for C3" -F tags="gpu,vulkan" -F license=MIT \
https://www.c3pkg.eu/api/v1/packages/vk/versions/1.0.0
# a new version of a package you own
curl -X PUT -H "Authorization: Bearer $C3PKG_TOKEN" \
-F file=@vk.c3l -F c3_version=0.7.5 \
https://www.c3pkg.eu/api/v1/packages/vk/versions/1.0.1
Optional form fields for a new package: license, docs_url, git_url and a readme file. Success returns 201 with {"name", "version", "created", "url"}.
Endpoints
| Method and path | What it does | Auth |
|---|---|---|
| GET /api/v1/packages | List or search. Query: q, tag, sort (latest, downloads, stars), page, per_page (max 100) | – |
| GET /api/v1/packages/{name} | Metadata, README (Markdown) and all versions | – |
| GET /api/v1/packages/{name}/versions | Versions with checksums, sizes and yank state | – |
| GET /api/v1/packages/{name}/{version}/download | The .c3l file (counts as a download) | – |
| PUT /api/v1/packages/{name}/versions/{version} | Publish a version (multipart, see above) | token |
| PUT / DELETE …/versions/{version}/yank | Yank or restore a version | owner |
| PATCH /api/v1/packages/{name} | JSON with any of description, tags[], license, docs_url, git_url | owner |
| PUT /api/v1/packages/{name}/readme | Body: the README as Markdown (max 512 KB) | owner |
| PUT / DELETE /api/v1/packages/{name}/star | Star or unstar; returns the new count | token |
| GET /api/v1/users/{login} | Public profile and packages | – |
| GET / PATCH /api/v1/me | Your account; patch name, bio, github | token |
Package index (for build tools)
Plain, cache-friendly endpoints a package manager can use to resolve and fetch versions, in the style of the Go module proxy.
| GET /index/{name}/list | One version per line, newest first, yanked versions left out |
| GET /index/{name}/{version}.json | C3 version, platforms, size, checksums, yanked flag |
| GET /index/{name}/{version}.c3l | The library file |
Yanked versions are not listed but can still be fetched by exact version, so existing builds keep working.
Checksums
Each version has two SHA-256 values. sha256_file is the hash of the uploaded .c3l. sha256_tree hashes the contents, ignoring zip metadata, so a zipped library and its unpacked directory give the same value:
cd unpacked-library
find . -type f | sed 's|^\./||' | LC_ALL=C sort \
| while read f; do echo "$(sha256sum "$f" | cut -c1-64) $f"; done \
| sha256sum