Skip to content

Webhook setup per provider

gocdnext is webhook-first: a push to a connected repo creates a run, no polling needed. This page walks the setup for each of the three supported providers. The platform’s Settings → SCM integrations + the per-project Connect repo flows automate most of this — manual setup is here as a fallback when auto-register doesn’t apply (self-hosted, restricted org policies, existing webhooks you want to reuse).

What gocdnext expects

Whatever provider, the webhook delivers events to:

POST <PUBLIC_BASE>/api/webhooks/<provider>

Where <provider> is github, gitlab, or bitbucket. The endpoint is unauthenticated by URL but verified by HMAC against a per-source secret — same shape every webhook integration uses.

<PUBLIC_BASE> is GOCDNEXT_PUBLIC_BASE (or the override in GOCDNEXT_WEBHOOK_PUBLIC_URL when behind a public tunnel + private dashboard). The chart’s webhookPublicURL value sets the latter.

Fan-out to multiple pipelines

A single push fans out to every pipeline whose materials match the push’s (repo, branch) fingerprint. So a monorepo with ci-server.yaml, ci-web.yaml, and security.yaml all sharing the implicit project material gets three runs from one push, all dispatched concurrently. The webhook response body is:

HTTP/1.1 202 Accepted
{ "runs": ["<uuid>", "<uuid>", "<uuid>"] }

(Pre-v0.4.20 it was a single run per push; if you have downstream tooling that expected one id, switch it to iterate the runs array.)

GitHub

If you’ve connected gocdnext as a GitHub App with Repository: Webhooks permission, the apply flow auto-registers the webhook on new repos:

  1. Settings → SCM integrations → Add → GitHub App.
  2. Install the app on your org / specific repos.
  3. Apply a project pointing at one of those repos — gocdnext sees the install, registers the webhook, you’re done.

For OAuth-only flows (no App), the auto-register works if the authenticated user has admin on the repo. The platform creates the webhook via the REST API.

Manual setup

Per-repo: Settings → Webhooks → Add webhook.

FieldValue
Payload URLhttps://ci.example.com/api/webhooks/github
Content typeapplication/json
Secret(any random string — copy to gocdnext below)
SSL verificationEnable
EventsPush events, Pull requests, Tags created
Active

After the webhook is created, register the secret with gocdnext:

  1. Project → Settings → SCM source.
  2. Paste the secret you used in the GitHub form into Webhook secret.
  3. Save.

GitHub Enterprise

Same flow, just the Payload URL points at your gocdnext instance and the SCM source apiBase: is set to your GHE API URL (https://github.example.com/api/v3). Auth via GHE works identically — see Auth deep-dive.

GitLab

Settings → SCM integrations → Add → GitLab.

You need a GitLab access token with api scope (Personal Access Token or Project Access Token). Paste it; gocdnext stores it encrypted, uses it to register webhooks on apply.

For self-hosted GitLab: set apiBase: to your instance URL (https://gitlab.example.com/api/v4). The same token format works.

Manual setup

Per-project: Settings → Webhooks.

FieldValue
URLhttps://ci.example.com/api/webhooks/gitlab
Secret token(any random string)
EventsPush events, Tag push events, Merge request events
SSL verificationEnable

Register the secret with gocdnext: Project → Settings → SCM source → Webhook secret.

GitLab system-level webhook (instance-wide)

Self-hosted instances can register a single webhook for the entire instance — gocdnext receives every push to every project. Useful when you don’t want to manage per-project webhooks but downside is the platform’s gocdnext server now sees push traffic from projects it doesn’t manage (silently dropped, but adds noise).

The trade-off rarely pays off; per-project webhooks are the sensible default.

Bitbucket

Auto-register

Same shape as GitLab: store a Bitbucket app password (with webhook:write) in SCM integrations; gocdnext registers webhooks on apply.

Manual setup

Per-repo: Repository settings → Webhooks → Add webhook.

FieldValue
Titlegocdnext
URLhttps://ci.example.com/api/webhooks/bitbucket
Active
TriggersRepository push, Pull request created/updated, Tag created

Bitbucket Cloud doesn’t have a per-webhook secret in the UI; the platform falls back to verifying the request’s source IP against Bitbucket’s documented IP ranges. For tighter security, use Bitbucket Data Center which supports webhook secrets.

For Bitbucket Cloud, the Webhook secret field in gocdnext is still useful — set it to a random string and pass it in the URL query (?secret=...) on the webhook URL when you create it. The platform validates it.

Generic webhook (self-hosted Git, custom integrations)

There is no generic webhook endpoint today. For Gitea / Forgejo and other self-hosted Git hosting, point the provider’s webhook at the most-compatible of the three real endpoints (Gitea ↔ /api/webhooks/github is the closest payload match) and accept that exotic providers may need a shim.

The pre-v0.4 GOCDNEXT_WEBHOOK_TOKEN env var that gated a generic endpoint is deprecated — the server warns on boot if it’s set and ignores the value. Per-source secrets via the SCM-source admin flow replaced it.

Verifying delivery

After the webhook is wired:

  1. Push a trivial commit to the connected repo.
  2. The provider’s webhook delivery log should show 200 OK.
  3. Project → Recent runs in the dashboard shows a new run within ~1 second of the push.

If the run doesn’t appear:

  • Check the gocdnext server log: kubectl -n gocdnext logs deployment/gocdnext-server --tail=100 | grep webhook. HMAC failures, missing-source errors, or YAML parse errors all surface here.
  • Verify the webhook secret matches between the provider and gocdnext. Mismatched secrets show up as webhook: HMAC validation failed.
  • Verify the <PUBLIC_BASE> is reachable from the provider’s delivery IPs. Behind a corporate firewall? Open the relevant IP ranges or use a tunnel (smee.io, ngrok) for dev.

When a push doesn’t create a run

A push that doesn’t match any pipeline’s when: filter (event + branch mismatch) results in no run created — the dashboard shows nothing, but the webhook delivery log shows 200 OK (server received and processed correctly, just nothing matched). To debug:

  • Set GOCDNEXT_LOG_LEVEL=debug temporarily — the server logs every filter decision.
  • Check the project’s pipelines: do their pipeline-level when: blocks list the branch the push hit? Remember branch: is singular (the parser rejects branches:).
  • Path-based filtering isn’t supported in when: — if you split pipelines per sub-tree to scope runs, that’s the right model; if you put paths: under when: expecting it to be honored, it isn’t.

Auto-register caveats

  • GitHub App permissions can drift. If an admin removes the app’s webhook permission later, future apply calls will silently fail to register. Watch the project apply log for auto_register_webhook: failed.
  • Org-level rate limits. GitHub limits webhook creations per hour. Mass-applying 100 projects at once can hit it; spread applies or pre-create webhooks manually.
  • Self-hosted GitLab + IP allowlists. The webhook from GitLab’s runner IP needs to reach gocdnext’s <PUBLIC_BASE>. In closed networks, configure both ends to be on the same internal subnet or whitelist explicitly.