# Connect a project to a GitHub repository

## `PUT /v1/projects/{projectId}/repository`

Connects the project to a repository in the organization's GitHub
account, through the organization's Spice Cloud GitHub App
installation. The next deployment reads spicepod.yaml (or
spicepod.yml) from `root_directory` on `production_branch`.
Connecting sets the project description to the repository
description. Connecting again replaces the repository, root directory
and production branch.
Requires `apps:write`.

### Path parameters

- `projectId` (integer, required): The ID of the project to connect

### Header parameters

- `Authorization` (string, required): `Bearer <token>`. [Authentication](https://spice.ai/docs/cloud/api/management#authentication) lists the tokens it accepts.
- `X-Org-Name` (string, optional): The organization to act on, by handle. Omit it to act on the organization the credential is bound to; sending it blank is a 400, not the same as omitting it. A user credential may name any organization its owner belongs to; a machine credential is pinned to its own. A portal session token is bound to none, so it must send this header on every route but `GET /v1/orgs` (400 `org_assertion_required` otherwise). Pattern: `^[A-Za-z0-9._-]{1,255}$`.

### Request body

Required.

Content type: `application/json`

- `repository` (string, required): Repository in the organization's GitHub account, as `name` or `owner/name`. The owner must be the organization's GitHub account. Example: `cookbook`.
- `root_directory` (string | null): Directory inside the repository that contains spicepod.yaml. Omit it, or send null or an empty string, for the repository root. Maximum length: `512`. Example: `cayenne`.
- `production_branch` (string): Branch that deployments read. Defaults to the repository's default branch. A branch that GitHub renamed is stored under its new name. Maximum length: `255`. Example: `trunk`.

### Example request

```bash
curl -X PUT "https://api.spice.ai/v1/projects/<projectId>/repository" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "repository": "cookbook"
  }'
```

```http
PUT /v1/projects/<projectId>/repository HTTP/1.1
Host: api.spice.ai
Authorization: Bearer <token>
Content-Type: application/json
Content-Length: 30

{
  "repository": "cookbook"
}
```

### Responses

**200 OK**

Project connected

Content type: `application/json`

- `project_id` (integer, required): The project ID
- `repository` (string, required): The repository as `owner/name`
- `repository_id` (integer, required): The GitHub repository ID
- `root_directory` (string | null, required): The stored root directory. Null is the repository root.
- `production_branch` (string, required): The branch that deployments read
- `connected_at` (string (date-time), required): When the project was connected
- `has_spicepod` (boolean, required): True when spicepod.yaml or spicepod.yml exists in the root directory on the production branch. A deployment fails until it does.

**400 Bad Request**

Invalid project ID or request body, a repository outside the organization's GitHub account (code: `invalid_repository`), or a root directory outside the repository (code: `invalid_root_directory`)

**401 Unauthorized**

Unauthorized

**403 Forbidden**

Insufficient scope, or viewer role cannot mutate projects

**404 Not Found**

Project not found, or the organization's GitHub App installation cannot read the repository (code: `repository_not_found`)

**409 Conflict**

The organization has no usable GitHub App installation (code: `github_not_connected`), or another project already deploys this repository and root directory (code: `root_directory_conflict`)

**413 Content Too Large**

Request body too large

**422 Unprocessable Content**

The repository has no branch named `production_branch` (code: `branch_not_found`), the project has no spicepod configuration (code: `spicepod_missing`), or the organization is not fully configured

**500 Internal Server Error**

Internal server error

**503 Service Unavailable**

GitHub did not answer (code: `github_unavailable`)

## `PUT /v1/orgs/{orgId}/projects/{projectId}/repository`

The org is `orgId` in the path. Connects the project to a repository in the organization's GitHub
account, through the organization's Spice Cloud GitHub App
installation. The next deployment reads spicepod.yaml (or
spicepod.yml) from `root_directory` on `production_branch`.
Connecting sets the project description to the repository
description. Connecting again replaces the repository, root directory
and production branch.
Requires `apps:write`.

### Path parameters

- `orgId` (integer, required): The org id from GET /v1/orgs. Minimum: `1`.
- `projectId` (integer, required): The ID of the project to connect

### Header parameters

- `Authorization` (string, required): `Bearer <token>`. [Authentication](https://spice.ai/docs/cloud/api/management#authentication) lists the tokens it accepts.
- `X-Org-Name` (string, optional): When present, X-Org-Name must name the same org as orgId. Otherwise the request returns org\_path\_mismatch (400). Pattern: `^[A-Za-z0-9._-]{1,255}$`.

### Request body

Required.

Content type: `application/json`

- `repository` (string, required): Repository in the organization's GitHub account, as `name` or `owner/name`. The owner must be the organization's GitHub account. Example: `cookbook`.
- `root_directory` (string | null): Directory inside the repository that contains spicepod.yaml. Omit it, or send null or an empty string, for the repository root. Maximum length: `512`. Example: `cayenne`.
- `production_branch` (string): Branch that deployments read. Defaults to the repository's default branch. A branch that GitHub renamed is stored under its new name. Maximum length: `255`. Example: `trunk`.

### Example request

```bash
curl -X PUT "https://api.spice.ai/v1/orgs/<orgId>/projects/<projectId>/repository" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "repository": "cookbook"
  }'
```

```http
PUT /v1/orgs/<orgId>/projects/<projectId>/repository HTTP/1.1
Host: api.spice.ai
Authorization: Bearer <token>
Content-Type: application/json
Content-Length: 30

{
  "repository": "cookbook"
}
```

### Responses

**200 OK**

Project connected

Content type: `application/json`

- `project_id` (integer, required): The project ID
- `repository` (string, required): The repository as `owner/name`
- `repository_id` (integer, required): The GitHub repository ID
- `root_directory` (string | null, required): The stored root directory. Null is the repository root.
- `production_branch` (string, required): The branch that deployments read
- `connected_at` (string (date-time), required): When the project was connected
- `has_spicepod` (boolean, required): True when spicepod.yaml or spicepod.yml exists in the root directory on the production branch. A deployment fails until it does.

**400 Bad Request**

Invalid project ID or request body, a repository outside the organization's GitHub account (code: `invalid_repository`), or a root directory outside the repository (code: `invalid_root_directory`). orgId is not a valid org id (`invalid_org_id`), or X-Org-Name does not name that org (`org_path_mismatch`).

**401 Unauthorized**

Unauthorized

**403 Forbidden**

Insufficient scope, or viewer role cannot mutate projects. The caller is not a member of the org (`org_forbidden`). A machine credential named a different org (`org_assertion_mismatch`). The org is deleted (`org_deleted`).

**404 Not Found**

Project not found, or the organization's GitHub App installation cannot read the repository (code: `repository_not_found`)

**409 Conflict**

The organization has no usable GitHub App installation (code: `github_not_connected`), or another project already deploys this repository and root directory (code: `root_directory_conflict`)

**413 Content Too Large**

Request body too large

**422 Unprocessable Content**

The repository has no branch named `production_branch` (code: `branch_not_found`), the project has no spicepod configuration (code: `spicepod_missing`), or the organization is not fully configured

**500 Internal Server Error**

Internal server error

**503 Service Unavailable**

GitHub did not answer (code: `github_unavailable`)

## `PUT /v1/apps/{appId}/repository` (deprecated)

Legacy alias of `/v1/projects/{projectId}/repository` — projects were previously called apps. Connects the project to a repository in the organization's GitHub
account, through the organization's Spice Cloud GitHub App
installation. The next deployment reads spicepod.yaml (or
spicepod.yml) from `root_directory` on `production_branch`.
Connecting sets the project description to the repository
description. Connecting again replaces the repository, root directory
and production branch.
Requires `apps:write`.

### Path parameters

- `appId` (integer, required): The ID of the project to connect

### Header parameters

- `Authorization` (string, required): `Bearer <token>`. [Authentication](https://spice.ai/docs/cloud/api/management#authentication) lists the tokens it accepts.
- `X-Org-Name` (string, optional): The organization to act on, by handle. Omit it to act on the organization the credential is bound to; sending it blank is a 400, not the same as omitting it. A user credential may name any organization its owner belongs to; a machine credential is pinned to its own. A portal session token is bound to none, so it must send this header on every route but `GET /v1/orgs` (400 `org_assertion_required` otherwise). Pattern: `^[A-Za-z0-9._-]{1,255}$`.

### Request body

Required.

Content type: `application/json`

- `repository` (string, required): Repository in the organization's GitHub account, as `name` or `owner/name`. The owner must be the organization's GitHub account. Example: `cookbook`.
- `root_directory` (string | null): Directory inside the repository that contains spicepod.yaml. Omit it, or send null or an empty string, for the repository root. Maximum length: `512`. Example: `cayenne`.
- `production_branch` (string): Branch that deployments read. Defaults to the repository's default branch. A branch that GitHub renamed is stored under its new name. Maximum length: `255`. Example: `trunk`.

### Example request

```bash
curl -X PUT "https://api.spice.ai/v1/apps/<appId>/repository" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "repository": "cookbook"
  }'
```

```http
PUT /v1/apps/<appId>/repository HTTP/1.1
Host: api.spice.ai
Authorization: Bearer <token>
Content-Type: application/json
Content-Length: 30

{
  "repository": "cookbook"
}
```

### Responses

**200 OK**

Project connected

Content type: `application/json`

- `project_id` (integer, required): The project ID
- `repository` (string, required): The repository as `owner/name`
- `repository_id` (integer, required): The GitHub repository ID
- `root_directory` (string | null, required): The stored root directory. Null is the repository root.
- `production_branch` (string, required): The branch that deployments read
- `connected_at` (string (date-time), required): When the project was connected
- `has_spicepod` (boolean, required): True when spicepod.yaml or spicepod.yml exists in the root directory on the production branch. A deployment fails until it does.

**400 Bad Request**

Invalid project ID or request body, a repository outside the organization's GitHub account (code: `invalid_repository`), or a root directory outside the repository (code: `invalid_root_directory`)

**401 Unauthorized**

Unauthorized

**403 Forbidden**

Insufficient scope, or viewer role cannot mutate projects

**404 Not Found**

Project not found, or the organization's GitHub App installation cannot read the repository (code: `repository_not_found`)

**409 Conflict**

The organization has no usable GitHub App installation (code: `github_not_connected`), or another project already deploys this repository and root directory (code: `root_directory_conflict`)

**413 Content Too Large**

Request body too large

**422 Unprocessable Content**

The repository has no branch named `production_branch` (code: `branch_not_found`), the project has no spicepod configuration (code: `spicepod_missing`), or the organization is not fully configured

**500 Internal Server Error**

Internal server error

**503 Service Unavailable**

GitHub did not answer (code: `github_unavailable`)

OpenAPI: [api.spice.ai/openapi.json](https://api.spice.ai/openapi.json)
