GitLab Webhooks and API

GitLab Webhooks send automatic notifications to external services when something happens in your project. The GitLab API lets external tools read and write GitLab data programmatically. Together, they connect GitLab to the rest of your technology stack.

What a Webhook Is — The Doorbell Analogy

  Normal API (you ask):          Webhook (GitLab tells you):
  ───────────────────────        ──────────────────────────────────────
  Your app → "Any new MRs?"      GitLab → POST request to your app
  GitLab  → "Yes, here are 3"    Payload: "MR #48 just merged on main"
  (you must keep asking)         (GitLab rings your doorbell automatically)

Webhooks eliminate the need to repeatedly poll GitLab for updates. GitLab pushes data to you the moment an event occurs.

Events That Trigger Webhooks

EventWhen It FiresCommon Use
Push eventsSomeone pushes commits to any branchTrigger an external build system
Merge request eventsMR opened, approved, merged, or closedPost a Slack notification to the team
Pipeline eventsPipeline starts, passes, or failsUpdate a dashboard or send an alert
Issue eventsIssue created, updated, or closedSync with an external project tracker
Release eventsA new release is publishedNotify the customer success team
Deployment eventsA deployment starts or finishesUpdate a status page automatically

Creating a Webhook

Go to Settings → Webhooks → Add new webhook. Fill in:

  URL:       https://hooks.slack.com/services/T00/B00/xxxx
  Secret token:  (optional — used to verify the sender is GitLab)
  Trigger:   ✅ Merge request events
             ✅ Pipeline events

  SSL verification: ✅ enabled (always keep this on)

  → Save → Test → GitLab sends a sample payload to your URL

Webhook Payload — What GitLab Sends

GitLab sends an HTTP POST request to your URL with a JSON body containing details about the event.

  Webhook payload example (MR merged):
  ──────────────────────────────────────────────────────────────
  {
    "object_kind": "merge_request",
    "event_type": "merge_request",
    "user": { "name": "Sara Ahmed", "username": "sara" },
    "project": { "name": "my-webapp", "id": 1234 },
    "object_attributes": {
      "id": 48,
      "title": "Add search bar",
      "state": "merged",
      "target_branch": "main",
      "url": "https://gitlab.com/acme/my-webapp/-/merge_requests/48"
    }
  }
  ──────────────────────────────────────────────────────────────

Securing Webhooks With a Secret Token

Anyone who discovers your webhook URL could send fake payloads to it. A secret token prevents this. Set a secret in GitLab when creating the webhook. GitLab sends that secret in every request header as X-Gitlab-Token. Your receiving server checks the header and rejects requests without the matching value.

  Incoming webhook request headers:
  ────────────────────────────────────────────────────────────
  POST /webhook HTTP/1.1
  X-Gitlab-Token: my-secret-value-here   ← your server checks this
  Content-Type: application/json
  ────────────────────────────────────────────────────────────

The GitLab REST API

The GitLab API lets any program read and write data in GitLab. You can create issues, trigger pipelines, list members, update files, and thousands of other actions — all with HTTP requests.

  API base URL:  https://gitlab.com/api/v4/

  Authentication: add your access token to every request
  Header: PRIVATE-TOKEN: glpat-xxxxxxxxxxxxxxxxxxxx

Common API Operations

List All Projects You Have Access To

  GET https://gitlab.com/api/v4/projects

  curl --header "PRIVATE-TOKEN: glpat-xxx" \
       "https://gitlab.com/api/v4/projects"

Create a New Issue

  POST https://gitlab.com/api/v4/projects/1234/issues

  curl --request POST \
       --header "PRIVATE-TOKEN: glpat-xxx" \
       --header "Content-Type: application/json" \
       --data '{"title":"Login page crashes on mobile","labels":"bug,high-priority"}' \
       "https://gitlab.com/api/v4/projects/1234/issues"

Trigger a Pipeline Manually

  POST https://gitlab.com/api/v4/projects/1234/trigger/pipeline

  curl --request POST \
       --form "token=my-pipeline-trigger-token" \
       --form "ref=main" \
       "https://gitlab.com/api/v4/projects/1234/trigger/pipeline"

Get a List of Open Merge Requests

  GET https://gitlab.com/api/v4/projects/1234/merge_requests?state=opened

  Response includes: MR id, title, author, labels, created_at, web_url

Pagination — Handling Large Result Sets

API responses are paginated — they return a limited number of results per page (20 by default). Check the response headers to navigate pages.

  Response headers:
  ─────────────────────────────────────────
  X-Total:       247
  X-Total-Pages: 13
  X-Per-Page:    20
  X-Page:        1
  X-Next-Page:   2

  Fetch page 2:
  GET /api/v4/projects?page=2&per_page=20

GraphQL API — An Alternative to REST

GitLab also offers a GraphQL API at https://gitlab.com/api/graphql. GraphQL lets you fetch exactly the fields you need in a single request instead of making multiple REST calls.

  GraphQL query — get project name and all open issue titles:
  ──────────────────────────────────────────────────────────────────
  {
    project(fullPath: "acme/my-webapp") {
      name
      issues(state: opened) {
        nodes {
          title
          createdAt
          assignees { nodes { name } }
        }
      }
    }
  }
  ──────────────────────────────────────────────────────────────────
  One request returns everything — no extra calls needed ✅

Pipeline Triggers — API-Driven Pipeline Starts

Create a pipeline trigger token at Settings → CI/CD → Pipeline triggers → Add trigger. External systems use this token to start a pipeline on demand — useful for scheduled nightly builds or cross-project dependencies.

  Scenario: Your test management tool should trigger a regression
  suite in GitLab every night at midnight.

  Cron job runs at 00:00:
  curl --request POST \
       --form "token=TRIGGER_TOKEN" \
       --form "ref=main" \
       "https://gitlab.com/api/v4/projects/1234/trigger/pipeline"

  GitLab starts the pipeline → runs tests → emails results ✅

Webhook Delivery Log

GitLab records every webhook delivery attempt. Go to Settings → Webhooks → Edit next to a webhook and click Recent deliveries. Each entry shows the payload sent, the HTTP response code from your server, and any error message.

  Recent deliveries
  ────────────────────────────────────────────────────────────
  ID     Event            Response   Sent At
  ────────────────────────────────────────────────────────────
  10041  push             200 ✅     10 minutes ago
  10040  merge_request    200 ✅     1 hour ago
  10039  pipeline         500 ❌     2 hours ago (server error)
  ────────────────────────────────────────────────────────────
  [Resend] button available on failed deliveries

Leave a Comment

Your email address will not be published. Required fields are marked *