Connect a project to a GitHub repository
PUThttps://api.spice.ai/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.
Authorizations
AuthorizationstringRequiredBearer <token>. Authentication lists the tokens it accepts.
Path parameters
projectIdintegerRequiredThe ID of the project to connect
Header parameters
X-Org-NamestringThe 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(400org_assertion_requiredotherwise).- Pattern:
^[A-Za-z0-9._-]{1,255}$
- Pattern:
Body
application/jsonRequired
repositorystringRequiredRepository in the organization's GitHub account, as
nameorowner/name. The owner must be the organization's GitHub account.- Example:
cookbook
- Example:
root_directorystring | nullDirectory 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
- Maximum length:
production_branchstringBranch 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
- Maximum length:
Responses
200Project connectedapplication/json
project_idintegerRequiredThe project ID
repositorystringRequiredThe repository as
owner/namerepository_idintegerRequiredThe GitHub repository ID
root_directorystring | nullRequiredThe stored root directory. Null is the repository root.
production_branchstringRequiredThe branch that deployments read
connected_atstring (date-time)RequiredWhen the project was connected
has_spicepodbooleanRequiredTrue when spicepod.yaml or spicepod.yml exists in the root directory on the production branch. A deployment fails until it does.
400Bad 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)
401Unauthorized
403Insufficient scope, or viewer role cannot mutate projects
404Not Found
Project not found, or the organization's GitHub App installation cannot read the repository (code: repository_not_found)
409Conflict
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)
413Request body too large
422Unprocessable 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
500Internal server error
503GitHub did not answer (code: github_unavailable)
curl -X PUT "https://api.spice.ai/v1/projects/<projectId>/repository" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"repository": "cookbook"
}'PUT /v1/projects/<projectId>/repository HTTP/1.1
Host: api.spice.ai
Authorization: Bearer <token>
Content-Type: application/json
Content-Length: 30
{
"repository": "cookbook"
}{
"project_id": 0,
"repository": "string",
"repository_id": 0,
"root_directory": "string",
"production_branch": "string",
"connected_at": "2026-01-01T00:00:00Z",
"has_spicepod": true
}application/json
No response body
No response body
No response body
No response body
No response body
No response body
No response body
No response body
No response body
PUThttps://api.spice.ai/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.
Authorizations
AuthorizationstringRequiredBearer <token>. Authentication lists the tokens it accepts.
Path parameters
orgIdintegerRequiredThe org id from GET /v1/orgs
- Minimum:
1
- Minimum:
projectIdintegerRequiredThe ID of the project to connect
Header parameters
X-Org-NamestringWhen 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}$
- Pattern:
Body
application/jsonRequired
repositorystringRequiredRepository in the organization's GitHub account, as
nameorowner/name. The owner must be the organization's GitHub account.- Example:
cookbook
- Example:
root_directorystring | nullDirectory 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
- Maximum length:
production_branchstringBranch 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
- Maximum length:
Responses
200Project connectedapplication/json
project_idintegerRequiredThe project ID
repositorystringRequiredThe repository as
owner/namerepository_idintegerRequiredThe GitHub repository ID
root_directorystring | nullRequiredThe stored root directory. Null is the repository root.
production_branchstringRequiredThe branch that deployments read
connected_atstring (date-time)RequiredWhen the project was connected
has_spicepodbooleanRequiredTrue when spicepod.yaml or spicepod.yml exists in the root directory on the production branch. A deployment fails until it does.
400Bad 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).
401Unauthorized
403Forbidden
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).
404Not Found
Project not found, or the organization's GitHub App installation cannot read the repository (code: repository_not_found)
409Conflict
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)
413Request body too large
422Unprocessable 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
500Internal server error
503GitHub did not answer (code: github_unavailable)
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"
}'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"
}{
"project_id": 0,
"repository": "string",
"repository_id": 0,
"root_directory": "string",
"production_branch": "string",
"connected_at": "2026-01-01T00:00:00Z",
"has_spicepod": true
}application/json
No response body
No response body
No response body
No response body
No response body
No response body
No response body
No response body
No response body
PUThttps://api.spice.ai/v1/apps/{appId}/repositoryDeprecated
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.
Authorizations
AuthorizationstringRequiredBearer <token>. Authentication lists the tokens it accepts.
Path parameters
appIdintegerRequiredThe ID of the project to connect
Header parameters
X-Org-NamestringThe 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(400org_assertion_requiredotherwise).- Pattern:
^[A-Za-z0-9._-]{1,255}$
- Pattern:
Body
application/jsonRequired
repositorystringRequiredRepository in the organization's GitHub account, as
nameorowner/name. The owner must be the organization's GitHub account.- Example:
cookbook
- Example:
root_directorystring | nullDirectory 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
- Maximum length:
production_branchstringBranch 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
- Maximum length:
Responses
200Project connectedapplication/json
project_idintegerRequiredThe project ID
repositorystringRequiredThe repository as
owner/namerepository_idintegerRequiredThe GitHub repository ID
root_directorystring | nullRequiredThe stored root directory. Null is the repository root.
production_branchstringRequiredThe branch that deployments read
connected_atstring (date-time)RequiredWhen the project was connected
has_spicepodbooleanRequiredTrue when spicepod.yaml or spicepod.yml exists in the root directory on the production branch. A deployment fails until it does.
400Bad 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)
401Unauthorized
403Insufficient scope, or viewer role cannot mutate projects
404Not Found
Project not found, or the organization's GitHub App installation cannot read the repository (code: repository_not_found)
409Conflict
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)
413Request body too large
422Unprocessable 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
500Internal server error
503GitHub did not answer (code: github_unavailable)
OpenAPIapi.spice.ai/openapi.json
curl -X PUT "https://api.spice.ai/v1/apps/<appId>/repository" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"repository": "cookbook"
}'PUT /v1/apps/<appId>/repository HTTP/1.1
Host: api.spice.ai
Authorization: Bearer <token>
Content-Type: application/json
Content-Length: 30
{
"repository": "cookbook"
}{
"project_id": 0,
"repository": "string",
"repository_id": 0,
"root_directory": "string",
"production_branch": "string",
"connected_at": "2026-01-01T00:00:00Z",
"has_spicepod": true
}application/json
No response body
No response body
No response body
No response body
No response body
No response body
No response body
No response body
No response body