API reference

Gluecron exposes a REST API at /api/v2/. All endpoints return JSON. Authenticated endpoints require a Bearer token in the Authorization header.

Authentication

Generate a personal access token at /settings/tokens. Tokens start with glc_ and are hashed (SHA-256) before storage — the plaintext is shown exactly once.

curl -H "Authorization: Bearer glc_your_token_here" \
  https://gluecron.com/api/v2/repos

Tokens can also authenticate git over HTTPS — use the token as the password with any username.

Rate limits

SurfaceLimitWindow
API (anonymous)1 000 requests60 seconds
API (authenticated)4 000 requests60 seconds
AI commit message60 requests60 seconds per token
Login / register10–20 requests60 seconds per IP

When a limit is exceeded the server returns 429 Too Many Requests with a Retry-After header.

Repositories

List your repos

GET /api/v2/repos

Response 200:
[
  {
    "id": "...",
    "name": "my-project",
    "fullName": "you/my-project",
    "description": "...",
    "isPrivate": false,
    "defaultBranch": "main",
    "starCount": 12,
    "forkCount": 3,
    "issueCount": 5,
    "createdAt": "2025-01-15T10:00:00Z",
    "updatedAt": "2025-06-01T14:30:00Z"
  }
]

Create a repo

POST /api/v2/repos
Content-Type: application/json

{
  "name": "my-project",
  "description": "Optional description",
  "isPrivate": false,
  "initReadme": true,
  "defaultBranch": "main"
}

Response 201:
{ "id": "...", "name": "my-project", "fullName": "you/my-project" }

Get a repo

GET /api/v2/repos/:owner/:repo

Response 200:
{ /* same shape as list item */ }

Delete a repo

DELETE /api/v2/repos/:owner/:repo

Response 204 No Content

Issues

List issues

GET /api/v2/repos/:owner/:repo/issues?state=open&limit=25

Response 200:
[
  {
    "number": 42,
    "title": "Bug in auth flow",
    "body": "...",
    "state": "open",
    "author": "kit",
    "createdAt": "2025-05-20T08:00:00Z"
  }
]

Create an issue

POST /api/v2/repos/:owner/:repo/issues
Content-Type: application/json

{
  "title": "Bug in auth flow",
  "body": "Steps to reproduce: ..."
}

Response 201:
{ "number": 42, "url": "/you/my-project/issues/42" }

Close / reopen an issue

PATCH /api/v2/repos/:owner/:repo/issues/:number
Content-Type: application/json

{ "state": "closed" }   // or "open"

Response 200:
{ "state": "closed" }

Pull requests

List PRs

GET /api/v2/repos/:owner/:repo/pulls?state=open

Response 200:
[
  {
    "number": 17,
    "title": "Add rate limiter",
    "state": "open",
    "baseBranch": "main",
    "headBranch": "feat/rate-limit",
    "isDraft": false,
    "author": "kit",
    "createdAt": "2025-06-01T09:00:00Z"
  }
]

Create a PR

POST /api/v2/repos/:owner/:repo/pulls
Content-Type: application/json

{
  "title": "Add rate limiter",
  "body": "## Summary
- Implements token-bucket rate limiter

## Test plan
- [ ] Run bun test",
  "headBranch": "feat/rate-limit",
  "baseBranch": "main"
}

Response 201:
{ "number": 17, "url": "/you/my-project/pulls/17" }

Merge a PR

POST /api/v2/repos/:owner/:repo/pulls/:number/merge

Response 200:
{ "merged": true, "sha": "a3f9c2d..." }

// If gate checks fail:
Response 422:
{ "merged": false, "reason": "GateTest: leaked secret in src/config.ts" }

// If the pre-merge risk score is critical, the merge soft-blocks:
Response 422:
{ "merged": false, "reason": "risk score is critical (9/10) — ...", "riskScore": { ... } }

// Confirm past the soft-block with an optional JSON body:
{ "confirmHighRisk": true }

Deploy keys and deploy tokens

Credentials scoped to one repository, for a build box, a deploy target or a mirror job — read-only unless you ask for write. Repository admin access is required to manage them (Settings → Deploy keys). A deploy token is the HTTPS form and works on every instance; a deploy key is an SSH public key and needs the instance's SSH port to be published. Both record when and from where they were last used.

Create a deploy token and clone with it

POST /api/v2/repos/:owner/:repo/deploy-tokens
Content-Type: application/json

{ "title": "ci runner", "read_only": true, "expires_at": "2027-01-01T00:00:00Z" }

Response 201 (the "token" field is shown here and never again):
{ "id": "...", "title": "ci runner", "token_prefix": "gcdt_1a2b3c4d",
  "read_only": true, "token": "gcdt_…", "last_used_at": null }

git clone https://deploy:gcdt_…@gluecron.com/:owner/:repo.git

A push with a read-only token answers 403 naming the token; create one
with "read_only": false for a job that must push.

GET    /api/v2/repos/:owner/:repo/deploy-tokens        list (never includes the secret)
DELETE /api/v2/repos/:owner/:repo/deploy-tokens/:id    revoke — clones stop at the next fetch

Add a deploy key (SSH)

POST /api/v2/repos/:owner/:repo/keys
Content-Type: application/json

{ "title": "prod deploy box", "key": "ssh-ed25519 AAAA… comment", "read_only": true }

Response 201:
{ "id": "...", "fingerprint": "SHA256:…", "read_only": true, "last_used_at": null }

422 when the key is already a deploy key elsewhere or a user's SSH key —
a deploy key attaches to exactly one repository.

GET    /api/v2/repos/:owner/:repo/keys        list
DELETE /api/v2/repos/:owner/:repo/keys/:id    remove

Repository tokens (fine-grained)

A token for one repository that works on the REST API (/api/v2 and the GitHub-compatible /api/v3) and on git over HTTPS, with a none / read / write level for each ofcontents, issues, pull_requests,statuses and actions. Admin and settings can never be granted. It also pushes and pulls the repository's container images (docker login, then :owner/:repo) withcontents read or write. An expiry is optional: leave it out for a token that works until revoked, or give 5 minutes to 1 year. The token never does more than the person who made it: its levels are held to that person's current access to the repository on every use, so if they lose access the token does too. Branch protection, rulesets and merge gates apply to it as they apply to that person. Create them at /settings/repo-tokens, over the API below, or with the gluecron_create_repo_token MCP tool.

POST /api/v2/user/repo-tokens
Content-Type: application/json

{ "owner": ":owner", "repo": ":repo", "name": "deploy box",
  "permissions": { "actions": "read" } }      (add "expires_in": "90d" for an expiry)

Response 201 (the "token" field is shown here and never again):
{ "id": "...", "repository": ":owner/:repo", "tokenPrefix": "gcft_1a2b3c4",
  "permissions": { "contents": "none", "issues": "none", "pull_requests": "none",
                   "statuses": "none", "actions": "read" },
  "state": "active", "expiresAt": null, "token": "gcft_…" }

curl -H "Authorization: Bearer gcft_…" https://gluecron.com/api/v2/repos/:owner/:repo/actions/runs
git clone https://x:gcft_…@gluecron.com/:owner/:repo.git     (needs contents: read; push needs write)

403 on any other repository, on a route the token's permissions do not cover,
and on every account, admin, settings or MCP route; 401 once it has expired
or been revoked.

GET    /api/v2/user/repo-tokens        list yours (never the secret)
DELETE /api/v2/user/repo-tokens/:id    revoke — the next request with it is refused

Webhooks

Register a webhook

POST /api/v2/repos/:owner/:repo/webhooks
Content-Type: application/json

{
  "url": "https://example.com/hooks/gluecron",
  "secret": "mysecret",
  "events": "push,pr,issue,star,workflow_run"
}

// GitHub-compatible format: GitHub's events, headers and payloads.
{
  "url": "https://example.com/github-receiver",
  "secret": "mysecret",
  "format": "github",               // "gluecron" (default) | "github"
  "content_type": "json",           // "json" (default) | "form"
  "events": ["push", "pull_request", "workflow_run", "issue_comment"]  // or ["*"]
}

Response 201: the stored webhook row (a github hook is sent "ping" at once)

Gluecron format (default)

// push
{ "branch": "main", "oldSha": "<sha>", "newSha": "<sha>" }
// pr / issue
{ "action": "opened" | "closed" | "merged" | "reopened" | "commented", "number": 12 }

X-Gluecron-Event: push
X-Gluecron-Delivery: <uuid>
X-Gluecron-Signature: sha256=<hex>   // HMAC-SHA256 of the raw body
X-Gluecron-Timestamp + X-Gluecron-Signature-Timestamped   // replay-resistant

GitHub format

Events: ping, push, create, delete, pull_request, pull_request_review,
pull_request_review_comment, issue_comment, issues, workflow_run,
workflow_job, status, release, star — GitHub's documented payloads
(repository, sender, ref/before/after/commits/head_commit/forced …).

X-GitHub-Event: push
X-GitHub-Delivery: <uuid>
X-Hub-Signature-256: sha256=<hex>    // verify exactly as for GitHub
X-Hub-Signature: sha1=<hex>
User-Agent: Gluecron-Hookshot/1
(plus the X-Gluecron-* headers above)

Ids are Gluecron UUIDs, matching the /api/v3 compatibility API.
No check_suite: Gluecron has no Checks API (CI is workflow_run + status).

AI endpoints

Generate a commit message

POST /api/v2/ai/commit-message
Content-Type: application/json

{ "diff": "<git diff output>" }

Response 200:
{
  "message": "feat(auth): add token-bucket rate limiter\n\nPrevents brute-force login attempts..."
}

Semantic code search

GET /api/v2/repos/:owner/:repo/semantic-search?q=password+hashing&limit=10

Response 200:
[
  {
    "path": "src/lib/auth.ts",
    "startLine": 12,
    "endLine": 28,
    "snippet": "...",
    "score": 0.94
  }
]