forge
ExploreLog in

Tahinli/forge

public
0 watching
★ 0
4.3 KiB

forge JSON API

A small JSON API under /api/v1. It is forge's own; it does not copy another forge's API. The examples use the base URL from config/forge.toml, http://127.0.0.1:7660.

Authentication

Requests authenticate with a personal access token. Create one at Settings → Tokens (/settings/tokens). Send it either way:

Authorization: Bearer forge_...
Authorization: token forge_...
  • A token needs the repo scope. It is the only scope the token form offers. A token without it gets 403.
  • Session cookies are never read by this API. A browser that is logged in cannot call these routes by itself, so CSRF does not apply. Without a token, a write gets 401.
  • Anonymous reads of public repos need no token. Anonymous calls that cannot read a repo get 401, as git does, so a private repo looks the same as a missing one to an anonymous caller. A signed-in user with no access to a repo gets 404.
  • Failed authentication counts against the client IP. It shares the budget git authentication uses, so after too many failures the API answers 429 with Retry-After.

Errors are JSON: {"error": "message"}.

Status Meaning
400 The body is not valid JSON.
401 No token, an unknown or expired token, or an anonymous caller who cannot use the repo.
403 The token lacks the repo scope, or the user has read-only access and tried to write.
404 The repo or the commit does not exist, or the signed-in user cannot see the repo.
413 The request body is larger than 16 KiB.
422 A field has an invalid value, or sha is not a full commit id.
429 Too many failed authentication attempts from this IP.

Commit statuses

A status reports the result of one check (for example a CI job) on one commit. Each commit can have one status per context. Reporting again for the same context replaces the earlier report, so the latest report wins.

A status has these fields:

Field Notes
state pending, success, failure or error.
context Name of the check, 1 to 255 characters. Defaults to default.
description Optional, at most 1024 characters.
target_url Optional, http or https only, at most 2048 bytes. Shown as a link.

The combined state of a commit is worked out from every context:

  • any failure or error gives failure;
  • otherwise any pending gives pending;
  • otherwise success;
  • a commit with no statuses has state: null.

Report a status

POST /api/v1/repos/{owner}/{repo}/statuses/{sha} needs a token with write access to the repo. sha is the full 40-character (or 64-character, SHA-256) commit id. Upper-case hex is accepted.

curl -X POST http://127.0.0.1:7660/api/v1/repos/alice/demo/statuses/$SHA \
  -H "Authorization: Bearer $FORGE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"state": "success", "context": "ci/build", "description": "Passed in 42s",
       "target_url": "https://ci.example.com/runs/7"}'

Response, 201 Created:

{
  "id": "01J...",
  "sha": "0123...",
  "context": "ci/build",
  "state": "success",
  "description": "Passed in 42s",
  "target_url": "https://ci.example.com/runs/7",
  "created_at": "2026-10-15T10:00:00Z",
  "updated_at": "2026-10-15T10:00:00Z"
}

Only state is required. A commit that is not in the repo gets 404.

Read the statuses of a commit

GET /api/v1/repos/{owner}/{repo}/commits/{sha}/statuses needs no token for a public repo. A token is needed for a private one.

curl http://127.0.0.1:7660/api/v1/repos/alice/demo/commits/$SHA/statuses \
  -H "Authorization: Bearer $FORGE_TOKEN"

Response, 200 OK:

{
  "state": "failure",
  "statuses": [
    {
      "id": "01J...",
      "sha": "0123...",
      "context": "ci/build",
      "state": "failure",
      "description": "2 tests failed",
      "target_url": "https://ci.example.com/runs/8",
      "created_at": "2026-10-15T10:05:00Z",
      "updated_at": "2026-10-15T10:05:00Z"
    },
    {
      "id": "01J...",
      "sha": "0123...",
      "context": "lint",
      "state": "success",
      "description": null,
      "target_url": null,
      "created_at": "2026-10-15T10:01:00Z",
      "updated_at": "2026-10-15T10:01:00Z"
    }
  ]
}

statuses is ordered by context. The list is empty and state is null when nothing has reported on the commit.