API

GitHub API

Connect a GitHub account or App, browse repos, branches and files, and manage push webhooks.

The GitHub API connects an Alaf Server instance to GitHub — via the Alaf Server GitHub App, an OAuth account, or the local gh CLI — and then lets you browse the accounts, repositories, branches and files you can deploy from. It also manages the push webhooks that drive auto-deploy. In the dashboard this is the GitHub connection card in Settings and the repo picker in the deploy wizard.

Base path & auth

All paths are relative to your instance, under /api — e.g. https://your-host/api/github/home. Send a personal access token as a bearer header (Authorization: Bearer <token>), created with alaf server token create. The dashboard uses your session cookie instead. See the API overview for the full auth model and Auth for how GitHub credentials are stored.

Both cloud and self-hosted

This module is mounted on every instance. Two routes — GET /api/github/local-status and GET /api/github/connect/poll — are self-hosted only (they back the local gh CLI login flow) and return 404 on Alaf Server Cloud.

Endpoints

Method & pathPermissionWhat it does
GET /api/github/statusgithub:readGitHub connection status for the org.
GET /api/github/homegithub:readConnection state, accounts, and repos in one call.
GET /api/github/local-statusgithub:readWhether the host has gh CLI auth available (self-hosted only).
GET /api/github/connect/pollgithub:readPoll device-flow login status (self-hosted only).
POST /api/github/connectgithub:writeStart or advance the connection flow.
GET /api/github/connect/redirectpublicGitHub OAuth callback — browser navigates here, no session yet.
POST /api/github/disconnectgithub:adminDisconnect one source or all.
GET /api/github/reposgithub:listList the connected account's repos (optionally ?owner=).
POST /api/github/reposgithub:writeCreate a repository.
GET /api/github/orgs/:org/reposgithub:listList repositories in an org / account.
GET /api/github/repos/:owner/:repogithub:readGet a repository's metadata.
DELETE /api/github/repos/:owner/:repogithub:adminDelete a repository.
GET /api/github/repos/:owner/:repo/branchesgithub:listList a repository's branches.
GET /api/github/repos/:owner/:repo/clone-tokengithub:readMint a short-lived clone token + git clone command.
GET /api/github/repos/:owner/:repo/filesgithub:listList files/dirs at a path (query: path, branch).
GET /api/github/repos/:owner/:repo/filegithub:readRead a single file's contents (query: file, branch).
GET /api/github/repos/:owner/:repo/webhooksgithub:listList a repo's webhooks.
POST /api/github/repos/:owner/:repo/webhooksgithub:writeRegister (or reuse) the Alaf Server push webhook.
DELETE /api/github/repos/:owner/:repo/webhooksgithub:adminDelete a webhook.

Connection state

GET /api/github/home is the dashboard's single entry point: it returns { state, accounts, repos } in one round trip, filtered to the accounts and repos your member role is allowed to see. GET /api/github/status is narrower — the Settings card's data source — returning { state, accounts, installUrl, cloudUnreachable }.

curl https://your-host/api/github/home \
  -H "Authorization: Bearer $ALAFSERVER_TOKEN"
# The CLI has no dedicated `github` command; use the raw-request escape hatch:
alaf server api /github/home

Connect

Starts or advances the connection flow. The response is intentionally mode-agnostic — the frontend just reacts to the flow field:

  • { connected: true } — already connected, nothing to do.
  • { connected: false, flow: "redirect", url } — open url (OAuth handoff or GitHub App install).
  • { connected: false, flow: "device_code", userCode, verificationUri, ... } — self-hosted device login.
  • { connected: false, flow: "terminal", command, message } — run command (e.g. gh auth login) yourself.
POST /api/github/connect

The optional body field source ("oauth" | "cli") forces a specific path when the dashboard shows both the "Connect Alaf Server App" and "Use gh CLI" buttons; omit it to let the server pick based on the instance's auth mode.

curl -X POST https://your-host/api/github/connect \
  -H "Authorization: Bearer $ALAFSERVER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"source":"oauth"}'

Disconnect

POST /api/github/disconnect

Body (or ?source=): source is "oauth", "cli", or "all" (default "all"). This drops Alaf Server's stored credentials for that source; it does not uninstall the GitHub App — that happens only when you remove it from github.com (Alaf Server reacts to the uninstall webhook).

alaf server api /github/disconnect -X POST -d '{"source":"cli"}'

Create a repository

POST /api/github/repos

Prop

Type

curl -X POST https://your-host/api/github/repos \
  -H "Authorization: Bearer $ALAFSERVER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"my-app","private":true,"owner":"acme"}'
alaf server api /github/repos -X POST -d '{"name":"my-app","private":true}'

Returns 201 with { data } (the created repository).

Browse repos, branches and files

List repos for the connected account (?owner= narrows to one account), or for a named org via GET /api/github/orgs/:org/repos. Both return { data: [...] } filtered to repos your role may see.

# Repos for one owner
alaf server api /github/repos --query owner=acme

# Branches for a repo
alaf server api /github/repos/acme/my-app/branches

# One repo, with its branches inlined
alaf server api /github/repos/acme/my-app --query branches=true

File browsing reads directly from GitHub:

  • GET /api/github/repos/:owner/:repo/files — directory listing. Query: path (default repo root) and branch.
  • GET /api/github/repos/:owner/:repo/file — one file's contents. Query: file (default package.json) and branch. .json files are parsed and returned as JSON.
curl "https://your-host/api/github/repos/acme/my-app/file?file=package.json&branch=main" \
  -H "Authorization: Bearer $ALAFSERVER_TOKEN"

Webhooks

POST /api/github/repos/:owner/:repo/webhooks registers the Alaf Server push webhook on the repo (or reuses an existing one) so pushes trigger auto-deploy. It takes no request body — the target repo comes from the path. GET lists the repo's hooks. To remove one, DELETE with the hook id:

DELETE /api/github/repos/:owner/:repo/webhooks

Prop

Type

alaf server api /github/repos/acme/my-app/webhooks -X DELETE -d '{"hookId":123456}'

Clone token

GET /api/github/repos/:owner/:repo/clone-token mints a short-lived (under an hour) GitHub App installation token and returns { token, cloneUrl, command } — a ready-to-run git clone. This is the same credential the build pipeline clones with, and is available only when the Alaf Server GitHub App is installed for the owner.

Errors you might see

400 — Not connected to GitHub

Returned by the repo-listing routes when no usable GitHub source (App installation, OAuth account, or gh CLI) is configured. Connect first with POST /api/github/connect, then retry.

409 — no installation token

clone-token needs a GitHub App installation for the owner. In gh CLI or PAT modes there is no installation token, so this route 409s. Install the Alaf Server GitHub App on that account to use clone tokens.

503 — cloud_unreachable

On a self-hosted instance connected to Alaf Server Cloud, GitHub OAuth and App-install URLs are resolved through alafteknoloji.com. If the SaaS is unreachable, connect returns 503 rather than a dead install link. Check network / the cloud connection in Settings, then retry.

404 on a repo route

The :owner/:repo isn't visible to the active GitHub source (private, not granted to your member role, or does not exist). Confirm the repo appears in GET /api/github/home first.

On this page