Skip to content

Migrate to the normalized /api/v1 API surface

Use this guide when you need to update existing automation for the proxy’s normalized HTTP contract.

Treat Forgejo Proxy as the canonical API surface for this ecosystem:

  • API families now live under /api/v1/...
  • Root-path exceptions are intentionally narrow: /health and /activitypub/**
  • thfg api always joins your path onto the active /api/v1 base URL
  • Project write flows use the normalized /api/v1/projects/... routes instead of legacy /api/v1/proxy/... paths

This is a breaking cleanup for callers that hard-coded the old paths.

Use this mapping when migrating scripts and operator runbooks.

BeforeAfterNotes
thfg api /repos/owner/repo with unclear base-path assumptionsthfg api /repos/owner/repo relative to /api/v1The CLI path stays the same, but the contract is now explicit.
curl "$PROXY_URL/api/v1/proxy/projects/$PROJECT/issues"curl "$PROXY_URL/api/v1/projects/$PROJECT/columns/$COLUMN/cards"The normalized API is column-scoped. Pick the target column explicitly.
curl "$PROXY_URL/api/v1/proxy/projects/$PROJECT/columns/$COLUMN/move"curl "$PROXY_URL/api/v1/projects/$PROJECT/columns/$COLUMN/cards"Posting a card to the target column is the normalized move/add contract.
Root-path custom API routes/api/v1/...Keep only /health and /activitypub/** at the root.
thfg api /activitypub/...thfg activitypub ... or curl "$PROXY_URL/activitypub/..."ActivityPub stays outside /api/v1.

thfg api now has one clear rule: pass a path relative to /api/v1.

Terminal window
# Read a repo through the normalized proxy API surface
thfg api /repos/myorg/myrepo
# Fetch all pages from an array endpoint
thfg api /user/repos --paginate
# Inspect the merged proxy contract
thfg api spec

Do not use thfg api for root-path resources.

Terminal window
# Health stays at the root
curl "$PROXY_URL/health"
# ActivityPub stays at the root too
thfg activitypub repo actor myorg/myrepo

Legacy project write endpoints hid the destination column behind /api/v1/proxy/... routes. The normalized API makes the target column explicit.

Terminal window
curl -s -X POST \
-H "Authorization: token $FORGEJO_TOKEN" \
-H "X-Webui-Username: $FORGEJO_WEBUI_USERNAME" \
-H "X-Webui-Password: $FORGEJO_WEBUI_PASSWORD" \
-H "Content-Type: application/json" \
-d '{"issue_id":7,"owner":"forgejo-proxy","repo":"forgejo-proxy"}' \
"$FORGEJO_PROXY_URL/api/v1/projects/2/columns/5/cards"

Use the same normalized endpoint, but point it at the new column.

Terminal window
curl -s -X POST \
-H "Authorization: token $FORGEJO_TOKEN" \
-H "X-Webui-Username: $FORGEJO_WEBUI_USERNAME" \
-H "X-Webui-Password: $FORGEJO_WEBUI_PASSWORD" \
-H "Content-Type: application/json" \
-d '{"issue_id":7,"owner":"forgejo-proxy","repo":"forgejo-proxy"}' \
"$FORGEJO_PROXY_URL/api/v1/projects/2/columns/7/cards"

If an older script relied on the proxy choosing a default column implicitly, resolve the column up front:

Terminal window
thfg project columns --id 2 --output-format json | jq '.[] | {id, title}'

Run these checks after updating your scripts:

Terminal window
# Contract still loads
thfg api spec > /dev/null
# Updated path works
thfg api /repos/myorg/myrepo > /dev/null
# Root exception still works
curl "$PROXY_URL/health"