Skip to content
Source

Use the REST API

You want a script, a bot or your own tool to work with the forge: open issues, list pull requests, merge, or read CI results.

The REST API is at /api/v1. It speaks JSON and takes a token in the Authorization header. It has the same features as MCP and the src CLI.

1. Make a token

Make a personal access token in Settings, Tokens. For this page, pick Full access, because /user is an account route. Make an access token shows the form. Keep the token in an environment variable:

export TOKEN=<your token>

For an agent, use an agent session token. See Connect your coding agent.

2. Send your first request

curl -H "Authorization: Bearer $TOKEN" https://gitflare.t-zlak97.workers.dev/api/v1/user

The answer is your account, as JSON.

3. Open a pull request

curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"title": "Count down to zero", "head": "fix-countdown", "body": "It stopped at 1."}' \
  https://gitflare.t-zlak97.workers.dev/api/v1/repos/<owner>/<repo>/pulls

The answer is 201, with the number and the htmlUrl of the new pull request. Without base, the pull request goes into the default branch.

Done

Your script talks to the forge. The same token works for git over HTTPS, MCP and src.

src api sends a request with your src login, so you do not need curl:

src api repos/<owner>/<repo>/pulls

The main routes

You want toRoute
List or open issuesGET or POST /repos/{owner}/{repo}/issues
List or open pull requestsGET or POST /repos/{owner}/{repo}/pulls
CommentPOST /repos/{owner}/{repo}/issues/{n}/comments
Assign people, each with an optional notePOST or PUT /repos/{owner}/{repo}/issues/{n}/assignees
MergePUT /repos/{owner}/{repo}/pulls/{n}/merge
Make a repositoryPOST /repos
Upload an assetPUT /repos/{owner}/{repo}/assets/files/{path}
Change your profile or an organization'sPATCH /user or PATCH /orgs/{org}
Upload an imagePUT /user/avatar or PUT /orgs/{org}/avatar

/llms.txt lists every route, with its fields.

Issue and pull request routes

A path that starts with ... is under /repos/{owner}/{repo}. Issues and pull requests share their numbers.

You want toRouteWho can
Lock or unlock a conversationPUT or DELETE .../issues/{n}/lockPeople with write access
Pin or unpin an issuePUT or DELETE .../issues/{n}/pinPeople with write access
Move an issue to another repository of the ownerPOST .../issues/{n}/transferPeople with write access to both
List the branches of an issue, or make oneGET or POST .../issues/{n}/branchesReaders list them, people with write access make one
Delete an issueDELETE .../issues/{n}Repository admins
Mark a draft ready, or make it a draft againPUT or DELETE .../pulls/{n}/readyThe author, people with write access
Ask for reviews, or stop askingPOST .../pulls/{n}/reviewersThe triage role or more
Bring the base branch into the head branchPOST .../pulls/{n}/update-branchPeople with write access to the head branch
Revert a merged pull requestPOST .../pulls/{n}/revertPeople with write access
  • Lock: the body is {"reason": "too_heated"}, or empty for no reason. A reason is off_topic, too_heated, resolved or spam.
  • Drafts and reviewers: POST .../pulls also takes "draft": true and "reviewers": ["ana"]. Nobody can merge a draft.
  • Transfer: the body is {"repo": "acme/docs"}. After the move, GET .../issues/{n} at the old place answers 301 with the new place.
  • Update branch: {"rebase": true} rebases in place of a merge. With sha, a head that moved is refused. A conflict gets 409.
  • See Lock, pin, move and delete issues and Drafts, reviews and updates of pull requests.

Repository routes

A path that starts with ... is under /repos/{owner}/{repo}.

You want toRouteWho can
Change the description or the default branchPATCH /repos/{owner}/{repo}The maintain role or more
Rename a repositoryPOST .../renameRepository admins
Archive or unarchive a repositoryPUT or DELETE .../archiveRepository admins
Delete a repositoryDELETE /repos/{owner}/{repo}Repository admins, people only
Sync a fork from its parentPOST .../syncPeople with write access to the fork, people only
List, add or delete autolinksGET or POST .../autolinks, GET or DELETE .../autolinks/{id}Repository admins
List the templates for a new repositoryGET /gitignore/templates, GET /licensesEveryone
  • Archived: every write to an archived repository gets 403, except the settings of its admins.
  • Delete: a repository with forks gets 422. Delete the forks first.
  • New repository: POST /repos takes gitignore (a template name) and license (a license key). Its first commit has the files.
  • See Rename, archive or delete a repository.

Search routes

A path that starts with ... is under /repos/{owner}/{repo}.

You want toRoute
Filter the issues or the pull requests of a repositoryGET .../issues or GET .../pulls, with author=, assignee=, mention= and label=
Search issues and pull requests across repositoriesGET /search/issues?q=
List your issues and pull requests across repositoriesGET /user/items?role=assigned, author, review-requested or mentioned
Find repositoriesGET /search/repos?q=
List your organizationsGET /user/orgs
  • A person filter takes a username, or @me for you.
  • GET .../pulls also takes head=, draft=true or false, and reviewRequested=.
  • GET /search/issues takes kind=issue or pull, label=, draft=, author=, assignee=, mention= and reviewRequested=.
  • GET /search/repos gives only the repositories that you can read. It leaves out forks unless you add includeForks=include.

CI routes

The CI reference lists every CI route. These paths are under /repos/{owner}/{repo}:

You want toRouteWho can
Read or change the CI variablesGET /ci/variables, GET, PUT or DELETE /ci/variables/{name}People with write access read them, admins change them
List the workflows, or turn one on or offGET /ci/workflows, PUT or DELETE /ci/workflows/{workflow}/enabledReaders list them, admins turn them on or off
Delete a run that endedDELETE /ci/runs/{id}Repository admins. A run of a pull request gets 422.
List the agent jobsGET /jobs?kind=agentEveryone who can read the jobs

Ask the person for a token

Your tool needs a token, and you do not want the person to copy one by hand. Ask for it with the device login. The person checks the request in the browser and creates the token, and your tool gets it.

  1. Start the request. It needs no token:

    curl -X POST -H "Content-Type: application/json" \
      -d '{"client_name": "my-tool", "token": {"name": "my-tool", "repos": ["acme/app"], "actions": ["contents:read", "pulls:read", "pulls:create"], "ttl": 7200}}' \
      https://gitflare.t-zlak97.workers.dev/api/v1/login/device/code

    The answer:

    {
      "device_code": "<secret>",
      "user_code": "BCDF-GHJK",
      "verification_uri": "https://gitflare.t-zlak97.workers.dev/login/device",
      "verification_uri_complete": "https://gitflare.t-zlak97.workers.dev/settings/tokens/new?code=BCDF-GHJK",
      "expires_in": 900,
      "interval": 5
    }
  2. Show the person verification_uri_complete. They can change the token there, then click Create token or Deny.

  3. Every interval seconds, poll with the device_code:

    curl -X POST -H "Content-Type: application/json" \
      -d '{"device_code": "<secret>"}' \
      https://gitflare.t-zlak97.workers.dev/api/v1/login/device/token
  4. Read the answer of the poll:

    • 200 with {"access_token": "tsp_...", "token_type": "bearer"}: the token. Only the first poll after the approval gets it.
    • 400 with authorization_pending: the person did not answer yet. Poll again.
    • 400 with slow_down: you poll too fast. Wait 5 seconds more between polls.
    • 400 with access_denied or expired_token: the person clicked Deny, or 15 minutes passed. Start again.

The fields of token:

  • name: the name of the token in the person's list.
  • repos: the repositories, as owner/name. At most 20.
  • actions: the actions, for example contents:write or vault:read. The Advanced part of the token form lists them all.
  • ttl: how long the token lives, in seconds. The default is 3600, and the most is 365 days.

Your tool gets the token that the person created. It can differ from your request, because the person can change the repositories, the actions and the end time.

Factory and ban routes

These routes run the software factory and bans. A path that starts with ... is under /repos/{owner}/{repo}, or under /orgs/{org} for an organization.

You want toRouteWho can
Read or change the factory settingsGET or PUT .../factory/settingsRepository admins, organization owners
List the model keysGET .../factory/keysRepository admins, organization owners
Save or delete a model keyPUT or DELETE .../factory/keys/{provider}Repository admins, organization owners
List the custom agentsGET /repos/{owner}/{repo}/factory/agentsRepository admins
See the custom agents that loaded, and the errors of the filesGET /repos/{owner}/{repo}/factory/agents/statusRepository admins
Save or delete a custom agentPUT or DELETE /repos/{owner}/{repo}/factory/agents/{name}Repository admins
List the runs on an issue or a pull requestGET /repos/{owner}/{repo}/issues/{n}/factoryEveryone who can read the item
List the repository's newest runs of every item and of the default branch, each with its number (null for the branch); ?limit= up to 500, 50 by defaultGET /repos/{owner}/{repo}/factory/runsPeople with write access
Read one run, its verdicts and its logGET /repos/{owner}/{repo}/factory/runs/{id}People with write access
Read the architecture of the repositoryGET /repos/{owner}/{repo}/architectureEveryone who can read the code
Make the architecture nowPOST /repos/{owner}/{repo}/architecturePeople with write access
Read the impact of a pull requestGET /repos/{owner}/{repo}/pulls/{n}/impactEveryone who can read the pull request
List the bansGET .../bansRepository admins, organization owners
Ban an account, or lift its banPUT or DELETE .../bans/{username}Repository admins, organization owners
Read the spam signals of an accountGET /repos/{owner}/{repo}/bans/{username}/signalsRepository admins
List the suggested bansGET .../bans/suggestionsRepository admins, organization owners
Ban the account of a suggested ban, or dismiss itPOST .../bans/suggestions/{id}/accept or .../dismissRepository admins, organization owners
  • Settings: a PUT takes only the fields that you change. The security audit (audit), architecture and impact are on by default. Every other agent is off by default. For example, {"agents": {"value": {"enabled": true}}} turns the value check on. null clears a field, so the organization value or the default holds again.
  • Architecture: GET .../architecture gives record (the overview, the packages and the diagrams, or null before the first run), the commit that it describes, at, runId, running, enabled and canGenerate. POST starts a run on the tip of the default branch: 201 with {"runId": "..."}, or 200 with {"skipped": "<why>"}. See Read the architecture of a repository.
  • Impact: GET .../pulls/{n}/impact gives the head commit (headOid), the assessment of that head, the record (architecture and publicApi, each only when it applies), running and enabled. See Read the Impact tab.
  • Keys: PUT .../factory/keys/{provider} takes {"key": "<key>"}. No route gives a key back. GET lists the providers and the time that each key was set.
  • Custom agents: a PUT takes {"script": "<file>"}, a TypeScript file that default-exports defineFactory(...). Each agent is { agent: defineAgent(...), on, trigger, budget }. See Custom agents.
  • Custom agent status: GET .../factory/agents/status gives source (vault or repo-file), the agents that loaded (name, factory, file and events), and errors, one line for each error with its file. It can take a few seconds when the files changed.
  • Suggested bans: GET .../bans/suggestions gives the open ones, each with its id, the account, the item that the spam agent closed (repo and number), the reasons and the signals. Add ?status=banned or ?status=dismissed for the decided ones. accept bans the account with the reason spam. After dismiss, the spam agent suggests the same ban again only after 30 days, or with hard proof.
  • Run logs come one page at a time. Pass next from the log back as ?cursor=.
  • People only: settings, keys, custom agents and bans refuse an agent session token.
  • Appeals: a banned person appeals on the web only. No route opens or decides an appeal.

Skill routes

Find and read skills (no token needed for public skills):

You want toRoute
Search the marketplaceGET /skills?q=
List the skills of an ownerGET /skills?owner=
List trending, popular skills or tagsGET /skills/trending, GET /skills/popular, GET /skills/tags
Read a skill with its filesGET /skills/{address}
List the versions, or compare twoGET /skills/versions?address=, GET /skills/diff?address=&from=&to=

Change your own skills (people only):

You want toRoute
Create a skillPOST /skills
Change its filesPATCH /skills/{owner}/{name}/files
Rename it, or change its visibilityPOST /skills/{owner}/{name}/rename, PUT /skills/{owner}/{name}/visibility
Make, list or revoke share linksPOST /skills/{owner}/{name}/shares, GET /skills/shares?address=, DELETE /skills/{owner}/{name}/shares/{id}
Delete itDELETE /skills/{owner}/{name}

Skills in a repository:

You want toRoute
List them, with their stateGET /repos/{owner}/{repo}/skills
Add onePOST /repos/{owner}/{repo}/skills
Update or remove onePATCH or DELETE /repos/{owner}/{repo}/skills/{name}
Get suggestionsGET /repos/{owner}/{repo}/skills/suggestions
Count an install that you made yourselfPOST /skills/installs

A share link of a private skill goes in ?share= or in a share field, never in the Authorization header. See Agent skills for the addresses.

How the API answers

  • Errors come back as { "error": "<text>" } with the HTTP status.
  • Lists come back as { "items": [...], "next": "<cursor>" }, 100 at a time, newest first. Pass next back as ?cursor=, with the same filters, for the next page.
  • Refused tokens: a token that is unknown, revoked or expired gets 401. It is never treated as anonymous.
  • Tokens limited to repositories get 403 on other repositories and on account routes, such as /user.
  • Merges take sha, the headSha that you read from GET /pulls/{n}. If the head moved since, the merge is refused with 409.
  • Limits: a title is at most 256 characters, and a body or a comment at most 65,536. A longer one gets 422.