> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/argoproj/argo-cd/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook Configuration

> Configure Git webhooks for instant application updates instead of polling

Argo CD polls Git repositories every three minutes by default to detect changes. Configure webhooks to eliminate this delay and trigger immediate application refreshes when commits are pushed.

## Overview

Webhooks provide event-driven updates:

<CardGroup cols={2}>
  <Card title="Without Webhooks" icon="clock">
    * Polls every 3 minutes
    * Up to 3 minute delay
    * Unnecessary API calls
    * Higher resource usage
  </Card>

  <Card title="With Webhooks" icon="bolt">
    * Instant notifications
    * Immediate updates
    * Event-driven architecture
    * Reduced resource usage
  </Card>
</CardGroup>

<Note>
  Webhooks are optional but recommended for production environments where fast feedback is important.
</Note>

## Supported Git Providers

Argo CD supports webhook notifications from:

* **GitHub** (github.com and GitHub Enterprise)
* **GitLab** (gitlab.com and self-hosted)
* **Bitbucket Cloud**
* **Bitbucket Server** (Data Center)
* **Azure DevOps**
* **Gogs**

## Configuration Steps

### Step 1: Configure Webhook in Git Provider

<Tabs>
  <Tab title="GitHub">
    <Steps>
      <Step title="Navigate to repository settings">
        Go to your repository → **Settings** → **Webhooks** → **Add webhook**
      </Step>

      <Step title="Configure webhook">
        * **Payload URL**: `https://argocd.example.com/api/webhook`
        * **Content type**: `application/json` (required)
        * **Secret**: Enter a secure random string (optional but recommended)
        * **Events**: Select "Just the push event"
        * **Active**: Checked
      </Step>

      <Step title="Save webhook">
        Click **Add webhook**
      </Step>
    </Steps>

    <Warning>
      When creating the webhook in GitHub, the "Content type" **must** be set to `application/json`. The default value `application/x-www-form-urlencoded` is not supported.
    </Warning>

    <img src="https://mintlify.s3.us-west-1.amazonaws.com/argoproj-argo-cd-10/images/webhook-github.png" alt="GitHub Webhook Configuration" />
  </Tab>

  <Tab title="GitLab">
    <Steps>
      <Step title="Navigate to webhook settings">
        Go to your project → **Settings** → **Webhooks**
      </Step>

      <Step title="Configure webhook">
        * **URL**: `https://argocd.example.com/api/webhook`
        * **Secret token**: Enter a secure random string (optional)
        * **Trigger**: Check "Push events"
        * **Enable SSL verification**: Checked (unless using self-signed certs)
      </Step>

      <Step title="Add webhook">
        Click **Add webhook**
      </Step>
    </Steps>
  </Tab>

  <Tab title="Bitbucket Cloud">
    <Steps>
      <Step title="Navigate to webhook settings">
        Go to your repository → **Repository settings** → **Webhooks** → **Add webhook**
      </Step>

      <Step title="Configure webhook">
        * **Title**: "Argo CD Webhook"
        * **URL**: `https://argocd.example.com/api/webhook`
        * **Status**: Active
        * **Triggers**: Select "Repository push"
      </Step>

      <Step title="Save webhook">
        Click **Save**
      </Step>
    </Steps>

    <Info>
      Bitbucket Cloud requires special handling. See [Bitbucket Cloud Special Configuration](#bitbucket-cloud-special-configuration) below.
    </Info>
  </Tab>

  <Tab title="Azure DevOps">
    <Steps>
      <Step title="Create service hook">
        Go to **Project Settings** → **Service hooks** → **+** → **Web Hooks**
      </Step>

      <Step title="Configure trigger">
        * **Trigger on**: "Code pushed"
        * **Repository**: Select your repository
        * Click **Next**
      </Step>

      <Step title="Configure action">
        * **URL**: `https://argocd.example.com/api/webhook`
        * **HTTP headers**: Leave default
        * **Basic authentication**: Add username/password if required
        * Click **Finish**
      </Step>
    </Steps>

    Azure DevOps supports basic authentication. Configure credentials in the next step.
  </Tab>
</Tabs>

### Step 2: Configure Argo CD Secret (Optional)

Configuring a webhook secret is optional but **strongly recommended** to prevent DDoS attacks and unauthorized webhook triggers.

<Steps>
  <Step title="Edit argocd-secret">
    ```bash theme={null}
    kubectl edit secret argocd-secret -n argocd
    ```
  </Step>

  <Step title="Add webhook secret">
    Add the secret under `stringData` (no base64 encoding needed):

    ```yaml theme={null}
    apiVersion: v1
    kind: Secret
    metadata:
      name: argocd-secret
      namespace: argocd
    type: Opaque
    data:
      # ... existing keys ...

    stringData:
      # GitHub webhook secret
      webhook.github.secret: shhhh! it's a GitHub secret
      
      # GitLab webhook secret
      webhook.gitlab.secret: shhhh! it's a GitLab secret
      
      # Bitbucket webhook UUID
      webhook.bitbucket.uuid: your-bitbucket-uuid
      
      # Bitbucket Server webhook secret
      webhook.bitbucketserver.secret: shhhh! it's a Bitbucket server secret
      
      # Gogs webhook secret
      webhook.gogs.secret: shhhh! it's a gogs server secret
      
      # Azure DevOps basic auth
      webhook.azuredevops.username: admin
      webhook.azuredevops.password: secret-password
    ```
  </Step>

  <Step title="Save and exit">
    Changes take effect immediately (no restart required).
  </Step>
</Steps>

### Webhook Secret Keys by Provider

| Git Provider     | Secret Key                                                         | Notes                  |
| ---------------- | ------------------------------------------------------------------ | ---------------------- |
| GitHub           | `webhook.github.secret`                                            | Token string           |
| GitLab           | `webhook.gitlab.secret`                                            | Token string           |
| Bitbucket Cloud  | `webhook.bitbucket.uuid`                                           | UUID from webhook      |
| Bitbucket Server | `webhook.bitbucketserver.secret`                                   | Token string           |
| Gogs             | `webhook.gogs.secret`                                              | Token string           |
| Azure DevOps     | `webhook.azuredevops.username`<br />`webhook.azuredevops.password` | Basic auth credentials |

<Info>
  For security, you can store webhook secrets in a separate Kubernetes Secret with the label `app.kubernetes.io/part-of: argocd`. Reference it using syntax: `$<secret-name>:<key>`
</Info>

### Alternative Secret Storage

Store webhook secrets in a separate secret:

```yaml theme={null}
apiVersion: v1
kind: Secret
metadata:
  name: webhook-secrets
  namespace: argocd
  labels:
    app.kubernetes.io/part-of: argocd
type: Opaque
stringData:
  github-secret: my-github-webhook-secret
```

Reference in argocd-secret:

```yaml theme={null}
stringData:
  webhook.github.secret: $webhook-secrets:github-secret
```

## Bitbucket Cloud Special Configuration

Bitbucket Cloud requires additional configuration because it doesn't include changed files in webhook payloads.

### Why Special Handling?

* Bitbucket Cloud webhooks lack changed file lists
* Prevents [Manifest Paths Annotation](/operations/high-availability#manifest-paths-annotation) from working
* Argo CD uses Bitbucket's `diffstat` API as workaround

### Requirements

<Warning>
  **Security requirement**: Bitbucket Cloud callbacks only work with encrypted webhooks that include the `X-Hook-UUID` header.
</Warning>

<Steps>
  <Step title="Configure webhook UUID">
    Add the UUID from your Bitbucket webhook to argocd-secret:

    ```yaml theme={null}
    stringData:
      webhook.bitbucket.uuid: {your-webhook-uuid}
    ```
  </Step>

  <Step title="Configure repository OAuth token (for private repos)">
    Argo CD uses the repository OAuth token to call Bitbucket API:

    ```bash theme={null}
    argocd repo add https://bitbucket.org/myorg/myrepo \
      --username myuser \
      --password <oauth-token>
    ```
  </Step>
</Steps>

### How It Works

1. Webhook received with `X-Hook-UUID` header
2. UUID verified against `webhook.bitbucket.uuid` secret
3. Argo CD calls Bitbucket `diffstat` API to get changed files
4. For public repos: uses unauthenticated API client
5. For private repos: uses repository OAuth token
6. If API call fails, changed files list remains empty (graceful degradation)

## Testing Webhooks

### Verify Webhook Delivery

<Tabs>
  <Tab title="GitHub">
    1. Go to repository → **Settings** → **Webhooks**
    2. Click on your webhook
    3. Scroll to **Recent Deliveries**
    4. Click on a delivery to see request/response
    5. Green checkmark = successful delivery
  </Tab>

  <Tab title="GitLab">
    1. Go to project → **Settings** → **Webhooks**
    2. Click **Edit** on your webhook
    3. Click **Test** → **Push events**
    4. View response (200 OK = success)
  </Tab>

  <Tab title="Bitbucket">
    1. Go to repository → **Repository settings** → **Webhooks**
    2. Click on your webhook
    3. View request history
    4. Click on a request to see details
  </Tab>
</Tabs>

### Check Argo CD Logs

```bash theme={null}
# Watch API server logs for webhook events
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-server -f | grep webhook

# Successful webhook:
# "Received webhook request"
# "Webhook processed successfully"

# Failed webhook:
# "Webhook signature verification failed"
# "Webhook secret mismatch"
```

### Trigger Test Event

```bash theme={null}
# Make a commit and push
echo "test" >> README.md
git add README.md
git commit -m "Test webhook"
git push

# Watch application refresh
argocd app get myapp --watch

# Should see immediate refresh (not wait 3 minutes)
```

## Webhook Security

<CardGroup cols={2}>
  <Card title="Always Use Secrets" icon="lock">
    Configure webhook secrets to verify payload authenticity and prevent unauthorized triggers.
  </Card>

  <Card title="Limit Payload Size" icon="gauge">
    Set `webhook.maxPayloadSizeMB` in argocd-cm ConfigMap (default: 50MB) to prevent DDoS.
  </Card>

  <Card title="Use HTTPS" icon="shield">
    Always use HTTPS for webhook endpoints to encrypt data in transit.
  </Card>

  <Card title="IP Allowlisting" icon="filter">
    Restrict webhook access to known Git provider IP ranges at firewall/ingress level.
  </Card>
</CardGroup>

### Limiting Payload Size

```yaml theme={null}
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  webhook.maxPayloadSizeMB: "25"  # Limit to 25MB
```

## ApplicationSet Webhooks

ApplicationSets use separate webhook configuration for the Git Generator.

<Info>
  See [ApplicationSet Git Generator Webhook Configuration](https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/Generators-Git/#webhook-configuration) for details.
</Info>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Webhook returns 401 Unauthorized">
    **Cause**: Webhook secret mismatch or missing.

    **Solution**:

    * Verify secret is configured in argocd-secret
    * Ensure secret matches what's configured in Git provider
    * Check for typos or extra whitespace

    ```bash theme={null}
    kubectl get secret argocd-secret -n argocd -o jsonpath='{.data.webhook\.github\.secret}' | base64 -d
    ```
  </Accordion>

  <Accordion title="Webhook received but application not refreshed">
    **Causes**:

    * Branch/tag mismatch in application
    * Application using commit SHA instead of branch
    * Manifest paths annotation doesn't match changed files

    **Check**:

    ```bash theme={null}
    # Verify application target revision
    argocd app get myapp -o json | jq '.spec.source.targetRevision'

    # Manually refresh to compare
    argocd app get myapp --refresh
    ```
  </Accordion>

  <Accordion title="Branch and tag name collision">
    **Issue**: Webhook handler doesn't differentiate between branch `x` and tag `x`.

    **Impact**: Push to branch `x` triggers refresh for apps pointing to `refs/tags/x`.

    **Workaround**: Use fully qualified references in applications:

    ```yaml theme={null}
    spec:
      source:
        targetRevision: refs/heads/main  # Not just "main"
    ```
  </Accordion>

  <Accordion title="Payload too large error">
    **Solution**: Increase payload size limit:

    ```yaml theme={null}
    # In argocd-cm ConfigMap
    webhook.maxPayloadSizeMB: "100"
    ```
  </Accordion>
</AccordionGroup>

## Advanced Configuration

### Webhook Ingress Configuration

Ensure your ingress allows webhook endpoint:

```yaml theme={null}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argocd-server-ingress
  namespace: argocd
  annotations:
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
  rules:
  - host: argocd.example.com
    http:
      paths:
      - path: /api/webhook
        pathType: Prefix
        backend:
          service:
            name: argocd-server
            port:
              number: 443
```

### Rate Limiting

<Warning>
  The `/api/webhook` endpoint currently lacks rate limiting protection. Implement rate limiting at the ingress level.
</Warning>

```yaml theme={null}
# Nginx ingress rate limiting
annotations:
  nginx.ingress.kubernetes.io/limit-rps: "10"
  nginx.ingress.kubernetes.io/limit-connections: "5"
```

## Related Resources

* [High Availability Configuration](/operations/high-availability)
* [Monitoring Webhooks](/operations/monitoring)
* [ApplicationSet Git Generator](https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/Generators-Git/)
