Skip to main content

API

Script against your firm’s boards, issues, and merge requests. Read-only and token-authed.

v1.12.0 Pin the /api/v1 path — that is the major version. Minor releases only add: a new endpoint, a new optional field, a new optional parameter. Nothing is ever removed, renamed or retyped inside v1.

The API is available on Pro and Team. Read on to see what it offers — the reference below is the whole of it.

See pricing →

Quickstart

  1. Mint an API token at /settings/api — that is your firm's own API access card, not the provider access tokens on /settings. Copy it once — it starts with ggb_ and is shown only at creation.
  2. Send it as a Bearer token on every request; it is scoped to the firm you minted it in.
curl -H "Authorization: Bearer ggb_..." https://gitgumbo.com/api/v1/me

Endpoints

Every endpoint in v1. Generated from the same OpenAPI document served at /api/v1/openapi.json, so this page and the spec can never disagree.

GET /api/v1/me

Current token, firm, and rate-limit status

Returns Me · Errors 401, 402, 429

GET /api/v1/projects

List the firm's monitored projects

ParameterInTypeRequired
cursorquerystringno
limitqueryintegerno

Returns Page<Project> · Errors 401, 402, 429

GET /api/v1/projects/{id}

Get one project

ParameterInTypeRequired
idpathstringyes

Returns Project · Errors 401, 402, 404, 429

GET /api/v1/projects/{id}/issues

List issues in a project

§69: scoped to the token's own provider access — an issue the token owner cannot see through the provider (e.g. a GitLab confidential issue they are below the level for) is simply absent from the page, with no separate signal that anything was filtered.

ParameterInTypeRequired
idpathstringyes
cursorquerystringno
limitqueryintegerno
statequery"opened" | "closed" | "all"no
labelquerystringno
labelMatchquery"any" | "all"no
assigneequerystringno
updatedSincequerystringno

Returns Page<Issue> · Errors 401, 402, 404, 429

GET /api/v1/projects/{id}/merge-requests

List merge requests in a project

ParameterInTypeRequired
idpathstringyes
cursorquerystringno
limitqueryintegerno
statequerystringno
draftquerybooleanno
authorquerystringno
reviewerquerystringno

Returns Page<Mr> · Errors 401, 402, 404, 429

GET /api/v1/projects/{id}/labels

List labels in a project

ParameterInTypeRequired
idpathstringyes
cursorquerystringno
limitqueryintegerno

Returns Page<Label> · Errors 401, 402, 404, 429

GET /api/v1/projects/{id}/board

The derived board — columns and the open issues bucketed into each

Open issues only, capped at 2000 (truncated=true when exceeded). GitLab-derived; board is null for GitHub and custom boards. §69: scoped to the token's own provider access — if the token owner cannot see the project at all, or an issue individually (e.g. a GitLab confidential issue below their level), the response shrinks to reflect that rather than adding a distinct error or flag.

ParameterInTypeRequired
idpathstringyes
assigneequerystringno
labelquerystringno
labelMatchquery"any" | "all"no
searchquerystringno
draftquerybooleanno
hasConflictsquerybooleanno
pipelineFailedquerybooleanno
unresolvedThreadsquerybooleanno
blockedquerybooleanno
confidentialquerybooleanno
blockingquerybooleanno
workItemTypequerystringno
boardquerystringno

Returns BoardResponse · Errors 401, 402, 404, 429

The board

The differentiator: GitGumbo’s derived board — columns and the open issues bucketed into each, filterable, that no provider API exposes. GitLab-derived (null for GitHub / custom boards).

curl -H "Authorization: Bearer ggb_..." "https://gitgumbo.com/api/v1/projects/<id>/board?assignee=me"

A response. Columns carry their bucketed open issues, and each issue carries the merge requests linked to it — the join no provider API gives you in one call.

{
  "board": {
    "remoteBoardId": "1042",
    "name": "Development",
    "assigneeUsername": null
  },
  "columns": [
    {
      "name": "In Progress",
      "type": "label",
      "labels": [
        "Stage::In Progress"
      ],
      "match": null,
      "color": "#1f75cb",
      "wipLimit": 3,
      "issues": [
        {
          "number": 318,
          "title": "Re-key webhook registrations when a project is transferred",
          "state": "opened",
          "webUrl": "https://gitlab.com/acme/platform/-/issues/318",
          "labels": [
            "Stage::In Progress",
            "backend"
          ],
          "assignees": [
            {
              "username": "rmedina",
              "name": "Robin Medina",
              "avatarUrl": "https://gitlab.com/uploads/-/system/user/avatar/4471/avatar.png"
            }
          ],
          "authorName": "Robin Medina",
          "authorUsername": "rmedina",
          "remoteCreatedAt": "2026-07-19T09:14:02.000Z",
          "remoteUpdatedAt": "2026-07-27T16:41:55.000Z",
          "dueDate": "2026-08-04T00:00:00.000Z",
          "milestoneTitle": "14.2",
          "milestoneDueDate": "2026-08-15T00:00:00.000Z",
          "statusName": "In progress",
          "statusCategory": "in_progress",
          "blocked": true,
          "blockedByCount": 1,
          "confidential": true,
          "issueType": "issue",
          "blockedBy": [
            {
              "iid": 292,
              "title": "Move webhook registration off the project id",
              "webUrl": "https://gitlab.com/acme/platform/-/issues/292",
              "reference": "#292",
              "state": "OPEN"
            }
          ],
          "blockingCount": 0,
          "blocking": null,
          "linkedMergeRequests": [
            {
              "number": 902,
              "title": "Re-key WebhookRegistration onto (provider, remoteProjectId)",
              "state": "opened",
              "draft": false,
              "webUrl": "https://gitlab.com/acme/platform/-/merge_requests/902",
              "pipelineStatus": "success",
              "reviewState": "pending"
            }
          ]
        }
      ]
    },
    {
      "name": "In Review",
      "type": "label",
      "labels": [
        "Stage::In Review"
      ],
      "match": null,
      "color": "#ab6100",
      "wipLimit": null,
      "issues": [
        {
          "number": 305,
          "title": "Collapsed columns should flag hidden search matches",
          "state": "opened",
          "webUrl": "https://gitlab.com/acme/platform/-/issues/305",
          "labels": [
            "Stage::In Review",
            "frontend"
          ],
          "assignees": [
            {
              "username": "dpatel",
              "name": "Dana Patel",
              "avatarUrl": null
            }
          ],
          "authorName": "Sam Okafor",
          "authorUsername": "sokafor",
          "remoteCreatedAt": "2026-07-11T13:02:44.000Z",
          "remoteUpdatedAt": "2026-07-28T08:19:07.000Z",
          "dueDate": null,
          "milestoneTitle": "14.2",
          "milestoneDueDate": "2026-08-15T00:00:00.000Z",
          "statusName": "In review",
          "statusCategory": "in_progress",
          "blocked": false,
          "blockedByCount": 0,
          "confidential": false,
          "issueType": "task",
          "blockedBy": [],
          "blockingCount": 1,
          "blocking": [
            {
              "iid": 341,
              "title": "Add pagination cursor to search results",
              "webUrl": "https://gitlab.com/acme/platform/-/issues/341",
              "reference": "#341",
              "state": "OPEN"
            }
          ],
          "linkedMergeRequests": [
            {
              "number": 897,
              "title": "Flag search matches inside collapsed columns",
              "state": "opened",
              "draft": false,
              "webUrl": "https://gitlab.com/acme/platform/-/merge_requests/897",
              "pipelineStatus": "running",
              "reviewState": "approved"
            }
          ]
        }
      ]
    },
    {
      "name": "Open",
      "type": "label",
      "labels": [],
      "match": null,
      "color": null,
      "wipLimit": null,
      "issues": []
    }
  ],
  "truncated": false
}

Conventions

Base URL
All endpoints live under https://gitgumbo.com/api/v1. The API is read-only and requires a Pro or Team plan.
Authentication
Send your token in the Authorization header: Authorization: Bearer ggb_... . There is no cookie/session fallback; a missing, revoked, or expired token returns 401.
Pagination
List endpoints return { data, nextCursor }. Pass ?cursor=<nextCursor> for the next page and ?limit= (1-100, default 50) to size it. A null nextCursor means the end.
Errors
Errors return { error: { code, message } }. 401 = auth, 402 api_requires_pro = your plan has no API access, 404 = not found or not in your firm, 429 = rate limited (with Retry-After).
Rate limits
Limits are per firm by plan (Pro 1,000/hr, Team 5,000/hr). A 200 and a 429 carry X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset; the 429 also carries Retry-After. A 401, 402 or 404 carries none, so read your remaining budget from a successful response rather than from an error.

Pagination in practice

Every list endpoint returns the same envelope. Pass the nextCursor back as ?cursor= until it comes back null.

{
  "data": [
    {
      "id": "clz8k2q0h0001s6mf4c9x2b7d",
      "remoteProjectId": "58210447",
      "provider": "gitlab",
      "name": "platform",
      "nameWithNamespace": "Acme / platform",
      "pathWithNamespace": "acme/platform",
      "webUrl": "https://gitlab.com/acme/platform",
      "boardMode": "custom",
      "syncEnabled": true,
      "lastSyncAt": "2026-07-28T08:25:11.000Z"
    },
    {
      "id": "clz8k2q0h0002s6mfa1p7q4we",
      "remoteProjectId": "742119058",
      "provider": "github",
      "name": "acme-web",
      "nameWithNamespace": "acme/acme-web",
      "pathWithNamespace": "acme/acme-web",
      "webUrl": "https://github.com/acme/acme-web",
      "boardMode": "auto",
      "syncEnabled": true,
      "lastSyncAt": "2026-07-28T08:24:58.000Z"
    }
  ],
  "nextCursor": "clz8k2q0h0002s6mfa1p7q4we"
}

Schemas

The object shapes the endpoints above return.

Person

FieldTypeNullable
usernamestringyes
namestringyes
avatarUrlstringyes

Project

FieldTypeNullable
idstringno
remoteProjectIdstringno
providerstringno
namestringno
nameWithNamespacestringyes
pathWithNamespacestringyes
webUrlstringno
boardModestringno
syncEnabledbooleanno
lastSyncAtstringyes

MrCompact

FieldTypeNullable
numberintegerno
titlestringno
statestringno
draftbooleanno
webUrlstringno
pipelineStatusstringyes
reviewStatestringyes

Mr

FieldTypeNullable
numberintegerno
titlestringno
statestringno
draftbooleanno
webUrlstringno
pipelineStatusstringyes
reviewStatestringyes
sourceBranchstringyes
targetBranchstringyes
authorNamestringyes
authorUsernamestringyes
authorAvatarUrlstringyes
hasConflictsbooleanno
mergeStatusstringyes
reviewersPerson[]no
approvedByPerson[]no
changesRequestedByPerson[]no
unresolvedThreadsintegerno
labelsstring[]no
remoteCreatedAtstringyes
remoteUpdatedAtstringyes
lastCommitAtstringyes

Issue

FieldTypeNullable
numberintegerno
titlestringno
statestringno
webUrlstringno
labelsstring[]no
assigneesPerson[]no
authorNamestringyes
authorUsernamestringyes
remoteCreatedAtstringyes
remoteUpdatedAtstringyes
dueDatestringyes
milestoneTitlestringyes
milestoneDueDatestringyes
statusNamestringyes
statusCategorystringyes
blockedbooleanyes
blockedByCountintegeryes
confidentialbooleanyes
issueTypestringyes
blockedBy{ iid, title, webUrl, reference, state }[]yes
blockingCountintegeryes
blocking{ iid, title, webUrl, reference, state }[]yes
linkedMergeRequestsMrCompact[]no

Label

FieldTypeNullable
namestringno
colorstringno

BoardColumn

FieldTypeNullable
namestringno
type"label" | "assignee" | "milestone" | "status"no
labelsstring[]no
matchstringyes
colorstringyes
wipLimitintegeryes
issuesIssue[]no

BoardSummary

FieldTypeNullable
remoteBoardIdstringno
namestringno
assigneeUsernamestringyes

Me

FieldTypeNullable
firm{ id, name, plan }no
token{ name, scopes }no
rateLimit{ limit, remaining, reset }no

Error

FieldTypeNullable
error{ code, message }no

BoardResponse

FieldTypeNullable
boardBoardSummaryyes
columnsBoardColumn[]no
truncatedbooleanno

Full reference

Everything above, machine-readable. Import it into Postman or any OpenAPI tool, or hand it to your codegen / AI client generator.