repos
Covers 24 API operations in the repos category.
| Method | Path | Description |
|---|---|---|
| GET | /v1/orgs/{orgSlug}/projects/{projectName}/repos | List of repositories for the project (runlot repo list) |
| POST | /v1/orgs/{orgSlug}/projects/{projectName}/repos | Creates a repository (runlot repo create) |
| GET | /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName} | A single repository |
| PATCH | /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName} | Changes the name, visibility, or default branch (runlot repo rename|visibility) |
| DELETE | /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName} | Deletes a repository (runlot repo delete) |
| GET | /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/ref-updates | Ref history (runlot repo history) |
| GET | /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/deploy-hook | Push-to-deploy settings (runlot repo hook status) |
| PUT | /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/deploy-hook | Turn push-to-deploy on or change it (runlot repo hook set) |
| DELETE | /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/deploy-hook | Turn push-to-deploy off entirely (runlot repo hook unset) |
| POST | /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/deploy | Build and deploy a commit without pushing |
| GET | /v1/orgs/{orgSlug}/projects/{projectName}/builds | Build history (runlot builds list) |
| GET | /v1/orgs/{orgSlug}/projects/{projectName}/builds/{buildId} | One build (runlot builds show) |
| GET | /v1/orgs/{orgSlug}/projects/{projectName}/builds/{buildId}/log | A build's output (runlot builds log) |
| POST | /v1/orgs/{orgSlug}/projects/{projectName}/builds/{buildId}/cancel | Cancel a queued build (runlot builds cancel) |
| GET | /v1/me/ssh-keys | My SSH public keys (runlot key list) |
| POST | /v1/me/ssh-keys | Registers an SSH public key (runlot key add) |
| DELETE | /v1/me/ssh-keys/{keyId} | Removes an SSH public key (runlot key rm) |
| GET | /v1/me/tokens | My access tokens (runlot token list) |
| POST | /v1/me/tokens | Issue an access token (runlot token create) |
| DELETE | /v1/me/tokens/{tokenId} | Revoke an access token (runlot token revoke) |
| GET | /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/refs | List branches and tags |
| GET | /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/tree | List one directory |
| GET | /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/blob | Read a single file |
| GET | /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/commits | Commit log |
GET /v1/orgs/{orgSlug}/projects/{projectName}/repos
Requires viewer or higher.
A repository belongs to a project. Access is governed by your organization role, while repository names are unique within a project. One project can hold several repositories (app, API, infrastructure).
operationId listRepos
| Status code | Description | Response body |
|---|---|---|
| 200 | List of repositories | object |
| 403 | — | — |
| 404 | — | — |
POST /v1/orgs/{orgSlug}/projects/{projectName}/repos
Requires member or higher. Audited as repo.create.
The repository is registered immediately; its storage is created on first access, so this call succeeds even if the repository server is momentarily unavailable.
operationId createRepo
Request body: application/json · object
| Status code | Description | Response body |
|---|---|---|
| 201 | The repository that was created | Repo |
| 400 | — | — |
| 403 | — | — |
| 404 | — | — |
| 409 | This project has a repository with the same name (repo_exists) | Error |
GET /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}
A single repository
operationId getRepo
| Status code | Description | Response body |
|---|---|---|
| 200 | Repository | Repo |
| 403 | — | — |
| 404 | — | — |
PATCH /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}
Requires admin. Audited as repo.update.
Renaming is a metadata change only. A push already in progress is not interrupted when the name changes.
operationId updateRepo
Request body: application/json · object
| Status code | Description | Response body |
|---|---|---|
| 204 | changed | — |
| 400 | — | — |
| 403 | — | — |
| 404 | — | — |
| 409 | A repository with that name already exists (repo_exists) | Error |
DELETE /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}
Requires admin. Audited as repo.delete.
This is a soft delete. The repository stops answering at its URL immediately, and the stored copy is removed after a retention period, so there is a window in which the deletion can still be undone.
operationId deleteRepo
| Status code | Description | Response body |
|---|---|---|
| 204 | deleted | — |
| 403 | — | — |
| 404 | — | — |
GET /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/ref-updates
Requires viewer or higher. The most recent 200 entries.
This is the repository's own ref history, not the audit log. old is what you need
to recover a commit lost to a force-push.
operationId listRefUpdates
| Status code | Description | Response body |
|---|---|---|
| 200 | Ref history | object |
| 403 | — | — |
| 404 | — | — |
GET /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/deploy-hook
Requires viewer or higher.
configured is false when no hook has ever been set, which is different from a hook
that exists and is switched off (enabled). When no hook exists, branch carries the
repository's default branch as a suggested value.
operationId getDeployHook
| Status code | Description | Response body |
|---|---|---|
| 200 | The hook | DeployHook |
| 403 | — | — |
| 404 | — | — |
PUT /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/deploy-hook
Requires admin, while deploying itself requires member.
With the hook on, every future push to branch by anyone with write access becomes a
production deploy, carried out under the identity of whoever turned the hook on.
Because that is a standing grant, a deploy-scoped token cannot create one.
An omitted field keeps its current value, so the switch and the branch can be sent separately without one resetting the other.
operationId setDeployHook
Request body: application/json · object
| Status code | Description | Response body |
|---|---|---|
| 200 | The hook as it now stands | DeployHook |
| 400 | — | — |
| 403 | — | — |
| 404 | — | — |
DELETE /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/deploy-hook
Requires admin. Turns push-to-deploy off completely. Past builds are kept, since they produced the deployments that are still serving.
operationId deleteDeployHook
| Status code | Description | Response body |
|---|---|---|
| 204 | Removed | — |
| 403 | — | — |
| 404 | — | — |
POST /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/deploy
Requires member. Queues a build of commitSha, or of the hooked branch's tip when
commitSha is omitted.
It uses the same settings a pushed deploy does, so a repository whose push-to-deploy
hook is off or missing answers 409 deploy_hook_off instead of building: without a
hook there is no root directory and no identity to deploy under.
operationId deployRepoNow
Request body: application/json · object
| Status code | Description | Response body |
|---|---|---|
| 202 | Queued | object |
| 400 | — | — |
| 403 | — | — |
| 404 | — | — |
| 409 | deploy_hook_off — push-to-deploy is not on for this repository | Error |
GET /v1/orgs/{orgSlug}/projects/{projectName}/builds
Requires viewer or higher. Newest first, with queued builds at the top.
The month's build minutes are returned alongside the list, so one request has everything a build screen needs to show.
The log is not included in the rows. A log can be up to 1 MiB; fetch it from
/builds/{buildId}/log.
operationId listBuilds
| Parameter | Location | Required | Type | Description |
|---|---|---|---|---|
limit | query | No | integer | — |
| Status code | Description | Response body |
|---|---|---|
| 200 | Builds | object |
| 400 | — | — |
| 403 | — | — |
GET /v1/orgs/{orgSlug}/projects/{projectName}/builds/{buildId}
One build (runlot builds show)
operationId getBuild
| Status code | Description | Response body |
|---|---|---|
| 200 | The build | Build |
| 403 | — | — |
| 404 | — | — |
GET /v1/orgs/{orgSlug}/projects/{projectName}/builds/{buildId}/log
Requires viewer or higher. Returned as text/plain, not JSON — it is raw build
output, so a client can display it directly.
Capped at 1 MiB, keeping the tail, because the end of a failed build is where the error is. When the cap applies, the first line says so.
operationId getBuildLog
| Status code | Description | Response body |
|---|---|---|
| 200 | The log | string |
| 403 | — | — |
| 404 | — | — |
POST /v1/orgs/{orgSlug}/projects/{projectName}/builds/{buildId}/cancel
Requires member. Only a queued build can be cancelled. A build that has already started cannot be stopped; it ends on its own after 20 minutes.
operationId cancelBuild
| Status code | Description | Response body |
|---|---|---|
| 204 | Cancelled | — |
| 403 | — | — |
| 404 | — | — |
| 409 | build_not_queued — it is already building, or already over | Error |
GET /v1/me/ssh-keys
My SSH public keys (runlot key list)
operationId listSSHKeys
| Status code | Description | Response body |
|---|---|---|
| 200 | Key list | object |
POST /v1/me/ssh-keys
A public key fingerprint is globally unique. The key is the identity, so the same
key cannot be registered twice — a key that already exists returns 409
ssh_key_exists.
Allowed: ed25519, ecdsa-sha2-nistp256/384/521, rsa (2048 bits or more). DSA is rejected.
operationId addSSHKey
Request body: application/json · object
| Status code | Description | Response body |
|---|---|---|
| 201 | Registered key | SSHKey |
| 400 | — | — |
| 409 | Public key already registered (ssh_key_exists) | Error |
DELETE /v1/me/ssh-keys/{keyId}
Takes effect immediately. The key stops working for git access as soon as this call returns — there is no caching delay.
operationId deleteSSHKey
| Status code | Description | Response body |
|---|---|---|
| 204 | deleted | — |
| 404 | — | — |
GET /v1/me/tokens
Token plaintext is never stored, so it is never returned here.
operationId listAccessTokens
| Status code | Description | Response body |
|---|---|---|
| 200 | Token list | object |
POST /v1/me/tokens
The plaintext token is returned in this response only. You cannot retrieve it again.
git sends Basic auth over HTTPS; the username is ignored and only the token in the
password field is read. The prefix runlot_pat_ is fixed so that leaked tokens can be
detected mechanically in repositories, logs, and pastes.
A token can be narrowed on three independent axes: a scopes set, an org or project
restriction, and an expiry. The default expiry is 90 days and the maximum is 365;
noExpiry is the only way to create a credential with no deadline, and it has to be
set explicitly.
An org or project restriction is checked against your own membership, so a token cannot be pinned to an org you do not belong to.
operationId createAccessToken
Request body: application/json · object
| Status code | Description | Response body |
|---|---|---|
| 201 | The issued token (including the plaintext) | AccessTokenCreated |
| 400 | — | — |
DELETE /v1/me/tokens/{tokenId}
Sets revokedAt instead of removing the token, so its lifetime stays
visible in the token list. Takes effect immediately — there is no
caching delay.
operationId revokeAccessToken
| Status code | Description | Response body |
|---|---|---|
| 204 | discarded | — |
| 404 | — | — |
GET /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/refs
Requires viewer or higher.
Lists every branch and tag in the repository, together with the default branch. This is the browsing API used by the dashboard; cloning, fetching and pushing go over git transport instead.
operationId getRepoRefs
| Status code | Description | Response body |
|---|---|---|
| 200 | List of refs | RepoRefs |
| 403 | — | — |
| 404 | — | — |
| 503 | Git hosting is temporarily unavailable (git_unavailable, git_unreachable) | Error |
GET /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/tree
Requires viewer or higher. path is the repository root when empty.
A directory is truncated at 1000 entries. When that happens, truncated is
true in the response.
A path that escapes the repository (a/../..) returns 404.
operationId getRepoTree
| Status code | Description | Response body |
|---|---|---|
| 200 | Directory | RepoTree |
| 403 | — | — |
| 404 | The repository, ref, or path does not exist (no_ref·no_path) | Error |
GET /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/blob
Requires viewer or higher.
Files over 1 MiB are not returned with content — tooLarge is true and
content is empty. Binary files also carry no content (binary is true).
operationId getRepoBlob
| Status code | Description | Response body |
|---|---|---|
| 200 | File | RepoBlob |
| 403 | — | — |
| 404 | The repository, ref, or path does not exist (no_ref·no_path) | Error |
GET /v1/orgs/{orgSlug}/projects/{projectName}/repos/{repoName}/commits
Requires viewer or higher. Returns up to 200 commits; the default is also 200.
operationId getRepoCommits
| Parameter | Location | Required | Type | Description |
|---|---|---|---|---|
limit | query | No | integer | — |
| Status code | Description | Response body |
|---|---|---|
| 200 | Commit list | object |
| 403 | — | — |
| 404 | — | — |