A reference guide for building AI agents: every method, how to authenticate, and the permissions each one needs.
The GitLab API is how an app or AI agent works with a GitLab project: reading and creating issues, opening and merging merge requests, reading and writing repository files, and triggering CI/CD pipelines. Access is granted through a token, and the scope on that token decides whether a call can only read or can also write, and which projects and groups it reaches. GitLab can also push events to a webhook URL when something happens in a project, so an agent learns about activity without polling.
How an app or AI agent connects to GitLab determines what it can reach. There are several routes, each governed by the token behind it and the scope that token carries.
The REST API answers under /api/v4 on the GitLab host, for example https://gitlab.com/api/v4. A call authenticates with a token sent in a PRIVATE-TOKEN header, or as a Bearer token in an Authorization header.
The GraphQL API answers at /api/graphql with a typed schema, letting a caller fetch many related fields in one request. It complements REST and GitLab is investing in it for newer features.
GitLab's own MCP server lets an agent call GitLab through the Model Context Protocol, at /api/v4/mcp on the GitLab host. It is in beta, having changed from experiment to beta in GitLab 18.6, and authenticates with OAuth 2.0 Dynamic Client Registration so a tool can register itself. It exposes tools for issues, merge requests, and pipelines.
Webhooks deliver the chosen events to a receiver URL when activity happens in a project or group. Each payload carries an object_kind field naming the event, and a configured secret token is sent in the X-Gitlab-Token header so the receiver can confirm the delivery came from GitLab.
A personal access token acts as the user who created it and carries one or more scopes, such as api for full read and write, read_api for read-only, read_repository or write_repository for repository access, and read_user for the user's own profile. It is sent in a PRIVATE-TOKEN header.
OAuth 2.0 lets a third-party app act for a user after consent, through the authorization code with PKCE flow or the device authorization grant. The access token carries the granted scopes, expires after two hours, and is renewed with a refresh token. It is sent as a Bearer token.
A project or group access token is scoped to a single project or group rather than a whole user, with its own scopes and an attached bot user and role. It suits automation that should reach only one project or group. It is sent in a PRIVATE-TOKEN header.
A CI/CD job token is created automatically for a running pipeline job and exposed as the CI_JOB_TOKEN variable. It is short-lived, tied to the job, and reaches only what the job's project is authorized for. It is sent in a JOB-TOKEN header.
The GitLab API is split into areas an agent can act on, such as projects, issues, merge requests, repository files, and pipelines. Each area has its own methods, and a single token scope decides whether a call can only read or can also write.
List projects, read a single project, create a project, update its settings, and delete it.
List, read, create, and update issues in a project.
List, create, and update merge requests, and merge them.
Create comments on issues and merge requests.
Read and update repository files, create commits, and list and create branches.
List pipelines, create a new pipeline, and retry one.
Read the authenticated user's own profile.
List groups visible to the authenticated user.
Search across the instance, scoped by a search type such as projects, issues, or merge requests.
Filter by method, access, or permission, or search any path. Select a row for version detail, rate limits, the related webhook event, and the source.
| Method | Endpoint | What it does | Access | Permission | Version | |
|---|---|---|---|---|---|---|
ProjectsList projects, read a single project, create a project, update its settings, and delete it.4 | ||||||
| GET | /projects | List all projects visible to the authenticated user. | read | read_api | Current | |
read_api grants read-only access across the API. The api scope also works but adds write access. Acts onproject Permission (capability) read_apiVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /projects/:id | Get a single project by ID or URL-encoded path. | read | read_api | Current | |
Any default role can read project properties; editing needs the Maintainer or Owner role. Acts onproject Permission (capability) read_apiVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /projects | Create a new project owned by the authenticated user. | write | api | Current | |
The api scope grants full read and write access to the API. read_api cannot write. Acts onproject Permission (capability) apiVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /projects/:id | Update an existing project's settings. | write | api | Current | |
Requires the Maintainer or Owner role on the project. Acts onproject Permission (capability) apiVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
IssuesList, read, create, and update issues in a project.4 | ||||||
| GET | /projects/:id/issues | List issues in a project. | read | read_api | Current | |
Issues are addressed by their per-project internal id (issue_iid), not the global id. Acts onissue Permission (capability) read_apiVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /projects/:id/issues/:issue_iid | Get a single issue in a project. | read | read_api | Current | |
read_api grants read-only access across the API. Acts onissue Permission (capability) read_apiVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /projects/:id/issues | Create a new issue in a project. | write | api | Current | |
The api scope grants full read and write across the API. Acts onissue Permission (capability) apiVersionAvailable since the API’s base version Webhook event issueRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /projects/:id/issues/:issue_iid | Update an issue, including its title, description, labels, assignees, or state. | write | api | Current | |
Closing and reopening use the state_event field here. Acts onissue Permission (capability) apiVersionAvailable since the API’s base version Webhook event issueRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Merge requestsList, create, and update merge requests, and merge them.4 | ||||||
| GET | /projects/:id/merge_requests | List merge requests in a project. | read | read_api | Current | |
Merge requests are addressed by their per-project internal id (merge_request_iid). Acts onmerge request Permission (capability) read_apiVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /projects/:id/merge_requests | Create a merge request from a source branch to a target branch. | write | api | Current | |
The api scope grants full read and write across the API. Acts onmerge request Permission (capability) apiVersionAvailable since the API’s base version Webhook event merge_requestRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /projects/:id/merge_requests/:merge_request_iid | Update a merge request, including its title, description, labels, or target branch. | write | api | Current | |
Closing and reopening use the state_event field here. Acts onmerge request Permission (capability) apiVersionAvailable since the API’s base version Webhook event merge_requestRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /projects/:id/merge_requests/:merge_request_iid/merge | Accept and merge a merge request. | write | api | Current | |
Merging commits to the target branch and needs at least the Developer role with merge rights. Acts onmerge request Permission (capability) apiVersionAvailable since the API’s base version Webhook event merge_requestRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Comments (notes)Create comments on issues and merge requests.2 | ||||||
| POST | /projects/:id/issues/:issue_iid/notes | Create a comment (note) on an issue. | write | api | Current | |
The api scope grants full read and write across the API. Acts onnote Permission (capability) apiVersionAvailable since the API’s base version Webhook event noteRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /projects/:id/merge_requests/:merge_request_iid/notes | Create a comment (note) on a merge request. | write | api | Current | |
The same note model serves merge request discussion comments. Acts onnote Permission (capability) apiVersionAvailable since the API’s base version Webhook event noteRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Repository files, commits & branchesRead and update repository files, create commits, and list and create branches.5 | ||||||
| GET | /projects/:id/repository/files/:file_path | Get a file from the repository, with its content Base64-encoded. | read | read_repository | Current | |
read_repository grants read access to repositories through the repository files API. read_api also covers this. Acts onfile Permission (capability) read_repositoryVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /projects/:id/repository/files/:file_path | Update an existing file in the repository, which records a commit. | write | api | Current | |
Writing through the repository files API needs the api scope. Acts onfile Permission (capability) apiVersionAvailable since the API’s base version Webhook event pushRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /projects/:id/repository/commits | Create a commit with multiple file actions (create, update, move, delete) in one request. | write | api | Current | |
A single request can batch several file changes into one commit. Acts oncommit Permission (capability) apiVersionAvailable since the API’s base version Webhook event pushRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /projects/:id/repository/branches | List the branches of a repository. | read | read_repository | Current | |
read_api also covers this read. Acts onbranch Permission (capability) read_repositoryVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /projects/:id/repository/branches | Create a new branch from a given ref. | write | api | Current | |
Creating a branch fires the push event under the create object_kind for new refs. Acts onbranch Permission (capability) apiVersionAvailable since the API’s base version Webhook event pushRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Pipelines (CI/CD)List pipelines, create a new pipeline, and retry one.3 | ||||||
| GET | /projects/:id/pipelines | List CI/CD pipelines in a project. | read | read_api | Current | |
read_api grants read-only access across the API. Acts onpipeline Permission (capability) read_apiVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /projects/:id/pipeline | Create and trigger a new pipeline on a given ref. | write | api | Current | |
This path is singular (/pipeline), unlike the plural listing path. Acts onpipeline Permission (capability) apiVersionAvailable since the API’s base version Webhook event pipelineRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /projects/:id/pipelines/:pipeline_id/retry | Retry the failed or canceled jobs in a pipeline. | write | api | Current | |
The api scope grants full read and write across the API. Acts onpipeline Permission (capability) apiVersionAvailable since the API’s base version Webhook event pipelineRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
UsersRead the authenticated user's own profile.1 | ||||||
| GET | /user | Get the profile of the authenticated user. | read | read_user | Current | |
read_user grants read-only access to the authenticated user's own profile through the /user endpoint. read_api and api also cover it. Acts onuser Permission (capability) read_userVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
GroupsList groups visible to the authenticated user.1 | ||||||
| GET | /groups | List groups visible to the authenticated user. | read | read_api | Current | |
read_api grants read-only access across the API. Acts ongroup Permission (capability) read_apiVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
SearchSearch across the instance, scoped by a search type such as projects, issues, or merge requests.1 | ||||||
| GET | /search | Search across the whole instance, scoped by a search type such as projects, issues, merge_requests, or blobs. | read | read_api | Current | |
The scope parameter chooses what to search; available scopes include projects, issues, merge_requests, milestones, users, commits, and blobs. Acts onsearch result Permission (capability) read_apiVersionAvailable since the API’s base version Webhook eventNone Rate limit10 requests per minute per IP address (search API) SourceOfficial documentation ↗ | ||||||
GitLab can notify an app or AI agent when something happens in a project, instead of the app repeatedly asking. GitLab posts the event payload to a webhook URL that has been registered for the chosen events, and each payload carries an object_kind field naming the event.
| Event | What it signals | Triggered by |
|---|---|---|
Push events (object_kind: push) | Fires when a push is made to the repository, which includes commits created through the repository files and commits APIs. | /projects/:id/repository/files/:file_path/projects/:id/repository/commits/projects/:id/repository/branches |
Tag push events (object_kind: tag_push) | Fires when tags are created or deleted in the repository. | In-app only |
Issue events (object_kind: issue) | Fires when an issue is created, or an existing one is edited, closed, or reopened. | /projects/:id/issues/projects/:id/issues/:issue_iid |
Merge request events (object_kind: merge_request) | Fires when a merge request is created, edited, merged, or closed, or a commit is added in the source branch. | /projects/:id/merge_requests/projects/:id/merge_requests/:merge_request_iid/projects/:id/merge_requests/:merge_request_iid/merge |
Comment events (object_kind: note) | Fires when a comment is made or edited on a commit, merge request, issue, or code snippet. | /projects/:id/issues/:issue_iid/notes/projects/:id/merge_requests/:merge_request_iid/notes |
Pipeline events (object_kind: pipeline) | Fires when a pipeline's status changes. | /projects/:id/pipeline/projects/:id/pipelines/:pipeline_id/retry |
Job events (object_kind: build) | Fires when the status of a job within a pipeline changes. | In-app only |
Release events (object_kind: release) | Fires when a release is created, edited, or deleted. | In-app only |
Deployment events (object_kind: deployment) | Fires when a deployment starts, succeeds, fails, or is canceled. | In-app only |
GitLab limits how fast an app or AI agent can call, through a per-minute request quota that depends on whether the call is authenticated, with tighter limits on a few specific endpoints like search.
GitLab.com meters requests per minute, decided by whether the call is authenticated. Authenticated API traffic for a user is allowed 2,000 requests per minute; unauthenticated traffic from an IP address is allowed 500 requests per minute, with all traffic from one IP address capped at 2,000 per minute. A few endpoints are tighter: the search API is held to 10 requests per minute per IP address, and endpoints like repository archives and webhook testing to 5 per minute per user. Every response carries RateLimit-Limit, RateLimit-Observed, RateLimit-Remaining, and RateLimit-Reset headers reporting the current state, and going over returns 429 with a Retry-After header giving the seconds to wait. Self-managed instances set their own limits, so these figures are GitLab.com's.
List endpoints page through results with the page and per_page parameters, where per_page defaults to 20 and tops out at 100, and the response headers x-total, x-total-pages, x-next-page, and x-prev-page describe the set. For large collections, keyset pagination is offered by sending pagination=keyset with order_by and sort, which returns a Link header carrying the URL of the next page rather than a page number.
Requests and responses are JSON. List pages return at most 100 items through per_page, and some unauthenticated or wide list endpoints cap the total reachable through offset pagination, where keyset pagination is recommended instead. There is no single documented payload size limit across the whole API, though individual endpoints set their own ceilings.
The status codes an agent should handle, and what to do about each.
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 304 | Not Modified | The resource has not been modified since the last request, returned for a conditional request. | Treat the cached copy as current and skip refetching it. |
| 400 | Bad Request | A required attribute of the request is missing, for example the title of an issue is not given. | Add the missing or correct the invalid attribute, then resend. |
| 401 | Unauthorized | The caller is not authenticated; a valid user token is necessary. | Send a valid token in the PRIVATE-TOKEN or Authorization header. |
| 403 | Forbidden | The request is not allowed, for example the user lacks the role to delete a project, or the token's scope does not cover the action. | Grant the needed role or token scope, then retry. |
| 404 | Not Found | A resource could not be accessed, because its ID could not be found or the user is not authorized to see it. GitLab returns 404 rather than 403 so it does not reveal a private resource exists. | Confirm the path and ID, and that the token has access to the resource. |
| 409 | Conflict | A conflicting resource already exists, for example creating something that is already present. | Refetch the current state and reconcile before retrying. |
| 412 | Precondition Failed | The request was denied, which can happen when an If-Unmodified-Since header is set on a delete and the resource was modified in between. | Refetch the resource and retry the conditional request. |
| 422 | Unprocessable | The entity could not be processed, typically a semantic validation failure on an otherwise well-formed request. | Correct the offending fields named in the response and resend. |
| 429 | Too Many Requests | The caller exceeded the application rate limits. | Honor the Retry-After header, or the RateLimit-Reset time, before retrying. |
| 500 | Server Error | Something went wrong on the server while handling the request. | Retry after a short delay, and contact GitLab support if it persists. |
GitLab versions its REST API by a single major number, currently 4, and follows semantic versioning so new endpoints and fields are added without breaking the major version.
Version 4 is the supported REST API, addressed in the path as /api/v4, and complies with semantic versioning where the major number is 4. New endpoints and fields are added within v4 without breaking it. Breaking changes are deferred to a future v5 rather than shipped into v4, and individual fields are deprecated across dated GitLab releases ahead of that move. Version 4 has been the preferred version since GitLab 9.0.
GitLab's Model Context Protocol server, at /api/v4/mcp, changed from experiment to beta in GitLab 18.6, and the mcp_server and oauth_dynamic_client_registration feature flags were removed. It authenticates with OAuth 2.0 Dynamic Client Registration and exposes tools for issues, merge requests, and pipelines. Search by project path was added in the same release.
GitLab introduced its Model Context Protocol server as an experiment in GitLab 18.3, behind feature flags, letting AI tools connect to a GitLab instance and act through standard MCP tools.
GitLab 18.0, released in May 2025, removed a range of long-deprecated behaviors, including some legacy API endpoints and CI/CD defaults, ahead of their replacements. Field-level REST deprecations such as default_branch_protection across group and settings APIs were flagged in earlier 17.x releases for this transition.
Breaking changes are held back for a future major version rather than shipped into the current one.
GitLab REST API deprecations ↗Bollard AI sits between a team's AI agents and GitLab. Grant each agent exactly the access it needs, read or write, resource by resource, and every call is checked and logged.