# GitHub

> GitHub App installation, repositories and stack detection.

GitHub App installation, repositories and stack detection.

| Operation | Method and path |
| --- | --- |
| [URL to install the Guv GitHub App](#url-to-install-the-guv-github-app) | `GET /v1/workspaces/{workspace}/github/install-url` |
| [Connect an installation after the GitHub redirect](#connect-an-installation-after-the-github-redirect) | `POST /v1/github/installations` |
| [List connected GitHub installations](#list-connected-github-installations) | `GET /v1/workspaces/{workspace}/github/installations` |
| [List repositories the installation can see](#list-repositories-the-installation-can-see) | `GET /v1/workspaces/{workspace}/github/installations/{installation_id}/repositories` |
| [Detect the stack of a repository and suggest a guv.yaml](#detect-the-stack-of-a-repository-and-suggest-a-guvyaml) | `POST /v1/workspaces/{workspace}/github/detect` |
| [GitHub App webhook receiver](#github-app-webhook-receiver) | `POST /v1/integrations/github/webhook` |

## URL to install the Guv GitHub App

```http
GET /v1/workspaces/{workspace}/github/install-url
```

- **Operation:** `getGitHubInstallUrl`
- **Scopes:** `projects:write`

**Parameters**

| Name | In | Type | Description |
| --- | --- | --- | --- |
| `workspace` * | path | string | Workspace id (`ws_…`) or slug. |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` OK | OK. | [GitHubInstallUrl](/docs/api/objects/git-hub-install-url/) |

**Errors:** `400`, `401`, `403`, `404`, `429`, `500`, as [problem+json](/errors/) with a stable `code`.

**Example**

```bash
curl https://api.guv.dev/v1/workspaces/acme/github/install-url \
  -H "Authorization: Bearer $GUV_TOKEN"
```

**Example response**

```json
{
  "url": "https://guv.dev/",
  "state": "string",
  "expires_at": "2026-10-22T13:05:00Z"
}
```

## Connect an installation after the GitHub redirect

```http
POST /v1/github/installations
```

- **Operation:** `connectGitHubInstallation`
- **Scopes:** any signed-in principal
- **Idempotency-Key:** required

**Request body** (`application/json`, required): [GitHubConnectRequest](/docs/api/objects/git-hub-connect-request/)

| Field | Type | Description |
| --- | --- | --- |
| `installation_id` * | integer |  |
| `setup_action` | `install`, `update`, `request` |  |
| `code` | string | OAuth authorisation code returned by GitHub when user authorisation is enabled. |
| `state` * | string |  |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `201` Created | Created. | [GitHubInstallation](/docs/api/objects/git-hub-installation/) |

**Errors:** `400`, `401`, `403`, `409`, `422`, `429`, `500`, as [problem+json](/errors/) with a stable `code`.

**Example**

```bash
curl -X POST https://api.guv.dev/v1/github/installations \
  -H "Authorization: Bearer $GUV_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "installation_id": 1,
  "setup_action": "install",
  "code": "string",
  "state": "string"
}'
```

**Example response**

```json
{
  "id": "ghi_01jbx2m9k7q4r8t5v6w3y0z1pr",
  "workspace_id": "string",
  "installation_id": 1,
  "account": {
    "login": "string",
    "type": "User",
    "avatar_url": "string"
  },
  "repository_selection": "all",
  "suspended": false,
  "created_at": "2026-10-22T13:05:00Z"
}
```

## List connected GitHub installations

```http
GET /v1/workspaces/{workspace}/github/installations
```

- **Operation:** `listGitHubInstallations`
- **Scopes:** `projects:read`
- **Paginated:** `?limit=` and `?cursor=`

**Parameters**

| Name | In | Type | Description |
| --- | --- | --- | --- |
| `workspace` * | path | string | Workspace id (`ws_…`) or slug. |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` OK | A page of GitHubInstallation objects. | [GitHubInstallationList](/docs/api/objects/git-hub-installation-list/) |

**Errors:** `400`, `401`, `403`, `404`, `429`, `500`, as [problem+json](/errors/) with a stable `code`.

**Example**

```bash
curl https://api.guv.dev/v1/workspaces/acme/github/installations \
  -H "Authorization: Bearer $GUV_TOKEN"
```

**Example response**

```json
{
  "data": [
    {
      "id": "ghi_01jbx2m9k7q4r8t5v6w3y0z1pr",
      "workspace_id": "string",
      "installation_id": 1,
      "account": {
        "login": "string",
        "type": "User",
        "avatar_url": "string"
      },
      "repository_selection": "all",
      "suspended": false,
      "created_at": "2026-10-22T13:05:00Z"
    }
  ],
  "next_cursor": "string",
  "has_more": false
}
```

## List repositories the installation can see

```http
GET /v1/workspaces/{workspace}/github/installations/{installation_id}/repositories
```

- **Operation:** `listGitHubRepositories`
- **Scopes:** `projects:read`
- **Paginated:** `?limit=` and `?cursor=`

**Parameters**

| Name | In | Type | Description |
| --- | --- | --- | --- |
| `workspace` * | path | string | Workspace id (`ws_…`) or slug. |
| `installation_id` * | path | string | Guv GitHub installation id (`ghi_…`). |
| `q` | query | string | Filter by name. |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` OK | A page of GitHubRepository objects. | [GitHubRepositoryList](/docs/api/objects/git-hub-repository-list/) |

**Errors:** `400`, `401`, `403`, `404`, `429`, `500`, as [problem+json](/errors/) with a stable `code`.

**Example**

```bash
curl https://api.guv.dev/v1/workspaces/acme/github/installations/ins_01jbx2m9k7q4r8t5v6w3y0z1pr/repositories \
  -H "Authorization: Bearer $GUV_TOKEN"
```

**Example response**

```json
{
  "data": [
    {
      "id": 1,
      "full_name": "primecarers/platform",
      "private": false,
      "default_branch": "string",
      "language": "string",
      "has_manifest": false,
      "pushed_at": "2026-10-22T13:05:00Z"
    }
  ],
  "next_cursor": "string",
  "has_more": false
}
```

## Detect the stack of a repository and suggest a guv.yaml

```http
POST /v1/workspaces/{workspace}/github/detect
```

- **Operation:** `detectStack`
- **Scopes:** `projects:read`
- **CLI:** `guv init`
- **Idempotency-Key:** optional

**Parameters**

| Name | In | Type | Description |
| --- | --- | --- | --- |
| `workspace` * | path | string | Workspace id (`ws_…`) or slug. |

**Request body** (`application/json`, required): [StackDetectRequest](/docs/api/objects/stack-detect-request/)

| Field | Type | Description |
| --- | --- | --- |
| `installation_id` * | string |  |
| `repo` * | string |  |
| `branch` | string |  |
| `root` | string | Default `.`. |

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `200` OK | OK. | [StackDetection](/docs/api/objects/stack-detection/) |

**Errors:** `400`, `401`, `403`, `404`, `409`, `422`, `429`, `500`, as [problem+json](/errors/) with a stable `code`.

**Example**

```bash
curl -X POST https://api.guv.dev/v1/workspaces/acme/github/detect \
  -H "Authorization: Bearer $GUV_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "installation_id": "string",
  "repo": "string",
  "branch": "string",
  "root": "."
}'
```

**Example response**

```json
{
  "summary": "We'll build a Next.js app with Node 22 and give you a Postgres database.",
  "has_manifest": false,
  "services": [
    {
      "name": "string",
      "root": "string",
      "builder": "railpack",
      "language": "string",
      "framework": "string",
      "start": "string",
      "port": 1
    }
  ],
  "databases": [
    "postgres"
  ],
  "variables": [
    {
      "name": "string",
      "example": "string",
      "likely_secret": false
    }
  ],
  "suggested_manifest": "string"
}
```

## GitHub App webhook receiver

```http
POST /v1/integrations/github/webhook
```

Called by GitHub. Authenticated by `X-Hub-Signature-256`; deduplicated by `X-GitHub-Delivery` instead of `Idempotency-Key`.

- **Operation:** `receiveGitHubWebhook`
- **Scopes:** none (public)

**Request body** (`application/json`, required): object

**Responses**

| Status | Meaning | Body |
| --- | --- | --- |
| `204` No Content | Done. No body. | none |

**Errors:** `400`, `401`, `409`, `422`, `429`, `500`, as [problem+json](/errors/) with a stable `code`.

**Example**

```bash
curl -X POST https://api.guv.dev/v1/integrations/github/webhook \
  -H "Authorization: Bearer $GUV_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```
