Test and connect GitHub Actions, GitLab CI or CircleCI, or change the connection
const url = 'https://beta-api.plune.ai/v1/projects/example/integrations/ci';const options = { method: 'PUT', headers: { cookie: 'plune_session=<plune_session>', 'Content-Type': 'application/json' }, body: '{"provider":"github","repository":"plune-ai/cli","workflow":".github/workflows/plune.yml","ref":"main","token":"github_pat_EXAMPLE_not_a_real_token_0000000000000000000000"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request PUT \ --url https://beta-api.plune.ai/v1/projects/example/integrations/ci \ --header 'Content-Type: application/json' \ --cookie plune_session=<plune_session> \ --data '{ "provider": "github", "repository": "plune-ai/cli", "workflow": ".github/workflows/plune.yml", "ref": "main", "token": "github_pat_EXAMPLE_not_a_real_token_0000000000000000000000" }'Owner only. Runs the five checks of POST …/test with what was sent, and saves the connection only if every one passed — the token encrypted with the server’s key, bound to this project, never returned — answering with what GET shows, the check as its last one. A check that failed saves nothing and answers 422 with the checks. One CI a project for now: with another one connected, 409 and nothing is sent. Left out of an edit of a project already connected, token is the saved one, and so are who saved it and when. Recorded in the audit feed of the project as a ci_integration entry, every token… field masked. At most 10 checks a minute for a project, this and POST …/test together, counted after the role. Session cookie only.
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters ”An id from GET /v1/projects
Request Body required
Section titled “Request Body required ”GitHub Actions on one repository.
object
owner/name, as in the address of the repository on GitHub.
The workflow file, .github/workflows/<name>.yml (or .yaml).
The branch or tag launches run on.
Write-only: a fine-grained personal access token on this one repository with one permission, Repository permissions → Actions → Read and write. A classic token (ghp_) is refused. Stored encrypted, bound to the project, and in no response, no log and no error message. Required for a new connection; left out of an edit, the saved one is kept.
GitLab CI on one project of gitlab.com or a self-managed GitLab. A launch is a pipeline with the variables PLUNE_RUN and PLUNE_GREP.
object
The https address of the GitLab — https://gitlab.com, or your own. A name, not an IP address; one on a private network is refused.
group/project (subgroups too), as in the address of the project on GitLab.
Optional: the file GitLab reads, .gitlab-ci.yml.
The branch or tag launches run on.
Write-only: a project access token, role Developer, scope api. Stored encrypted, bound to the project, in no response. Required for a new connection.
CircleCI on one project. A launch is a pipeline with the parameters plune_run and grep.
object
The project slug, as in its CircleCI address: gh/org/repo, bb/org/repo or circleci/<org id>/<project id>.
Optional: the file CircleCI reads, .circleci/config.yml.
The branch launches run on.
Write-only: a personal API token (CCIPAT_…) — CircleCI has no narrower token that can start pipelines, so make it a machine user’s. A project token (CCIPRJ_) is refused. Stored encrypted, bound to the project, in no response. Required for a new connection.
Example
{ "provider": "github", "repository": "plune-ai/cli", "workflow": ".github/workflows/plune.yml", "ref": "main", "token": "github_pat_EXAMPLE_not_a_real_token_0000000000000000000000"}Responses
Section titled “ Responses ”Connected — the same body as GET
The CI of a project, as a member of it reads it. With none connected it is { "configured": false }. The token is not in it.
object
Present exactly when configured is true, as every field below but url and the four token….
GitLab only: its address.
GitHub’s owner/name, GitLab’s group/project, CircleCI’s project slug.
userId of the owner who connected it, or last changed it.
When the saved connection was last checked: the save itself, or POST …/test.
object
object
Present exactly when result is failed.
The HTTP status the CI answered with, for unexpected. Never its body.
inputs_missing only: the inputs the workflow does not take.
Owner only: who saved the token. An edit that keeps the token keeps this.
Owner only.
Owner only: when the CI says the token expires, as of its last check; null when it does not, or the CI did not say.
Owner only: whose token it is, when the CI says — the CircleCI user of a personal API token; null otherwise.
Example
{ "configured": true, "provider": "github", "repository": "plune-ai/cli", "workflow": ".github/workflows/plune.yml", "ref": "main", "savedBy": "u-shop", "savedAt": "2026-09-16T09:12:04.151Z", "verifiedAt": "2026-09-16T09:12:04.151Z", "verifyResult": { "ok": true, "steps": [ { "step": "token", "result": "ok" }, { "step": "repository", "result": "ok" }, { "step": "actions", "result": "ok" }, { "step": "workflow", "result": "ok" }, { "step": "inputs", "result": "ok" } ] }, "tokenSavedBy": "u-shop", "tokenSavedAt": "2026-09-16T09:12:04.151Z", "tokenExpiresAt": null}Invalid body, or a first connect with no token; the message names the field and never a value. Nothing was sent to GitHub
object
Examples
A first connect with no token
{ "error": "validation failed — token: is required for a new connection"}A classic token
{ "error": "validation failed — token: must be a fine-grained personal access token — it starts with github_pat_"}No / invalid session — a CLI token is refused here
You are in the project, but not as its owner
object
Example
{ "error": "project owner only"}No such project among yours
object
Example
{ "error": "project 'u-shop::default' not found"}Another CI is connected — one CI a project for now: disconnect it first. Nothing was sent to the CI
object
Example
{ "error": "GitHub Actions is connected — one CI a project for now: disconnect it to use GitLab CI"}A check failed; nothing was saved. The body is the check, as POST …/test answers it, with error. A failed check carries one of these codes: unreachable — the CI did not answer in time; rate_limited — the CI is limiting the token’s requests: try again in a minute; token_rejected — the CI does not accept the token: it is mistyped, expired or revoked; repository_not_found — the token does not reach the repository, project or project slug: a private one it was not given, or a name that is not there; actions_denied — the token may not start workflows or pipelines: on GitHub, Repository permissions → Actions → Read and write; on GitLab, role Developer and scope api; on CircleCI, a user who may start the project’s pipelines; workflow_not_found — the workflow file, .gitlab-ci.yml or .circleci/config.yml is not there; workflow_disabled — the workflow is switched off on GitHub; ref_not_found — the branch or tag is not there; no_workflow_dispatch — the GitHub workflow does not run on workflow_dispatch; inputs_missing — the workflow, job or config does not take everything Plune sends (GitHub: the inputs plune_run, grep, ref; GitLab: a job for $PLUNE_RUN that greps by $PLUNE_GREP; CircleCI: the parameters plune_run and grep): missing names them; variables_denied — the GitLab project keeps pipeline variables from the token’s role: Settings → CI/CD → Variables → Minimum role to use pipeline variables → Developer; address_refused — the GitLab address is not https, is an IP address, or is on a private network: Plune sends no request there; unexpected — the CI answered with a status the check did not expect: the step carries it.
object
object
Present exactly when result is failed.
The HTTP status the CI answered with, for unexpected. Never its body.
inputs_missing only: the inputs the workflow does not take.
Example
{ "error": "the connection did not pass its checks — nothing was saved", "ok": false, "steps": [ { "step": "token", "result": "ok" }, { "step": "repository", "result": "ok" }, { "step": "actions", "result": "failed", "code": "actions_denied" }, { "step": "workflow", "result": "skipped" }, { "step": "inputs", "result": "skipped" } ], "testedAt": "2026-09-16T09:12:04.151Z"}More than 60 saves a minute from you, or more than 10 checks a minute for this project. Retry-After carries the seconds until the window rolls over
object
Example generated
{ "error": "example"}Headers
Section titled “Headers ”Seconds until the window rolls over
The server has no key to keep tokens under; nothing is saved
object
Example
{ "error": "integrations are not configured on this server — contact your operator"}