---
title: "Outbound webhooks"
description: "Use outbound webhooks to integrate with third-party services and subscribe to CircleCI events"
doc_version: "unversioned"
last_updated: "2026-05-20"
---

> For the complete documentation index, see [llms.txt](https://circleci.com/docs/llms.txt)

# Outbound webhooks

Setting up an **outbound webhook** on CircleCI enables your third party service to receive information (referred to as _events_) from CircleCI, as they happen. This can help you avoid polling the API or manually checking the CircleCI web application for desired information.

## Introduction

Use outbound webhooks to integrate your CircleCI builds with external services.

For example, you could use outbound webhooks to:

*   Build a custom dashboard to visualize or analyze workflow/job events.
    
*   Send data to incident management tools (such as [PagerDuty](https://www.pagerduty.com)).
    
*   Use tools like [Airtable](https://circleci.com/docs/guides/integration/webhooks-airtable/) to capture data and visualize it.
    
*   Alert when a workflow is cancelled, then use the API to rerun the workflow.
    
*   Trigger notification systems to alert people when workflows/jobs complete.
    
*   Build your own automation plugins and tools.
    

The following sections detail CircleCI outbound webhook structure and protocols.

## Quickstart

Projects are limited to 5 outbound webhooks. Organization admin permissions are required to add, update, and delete outbound webhooks.

Webhooks are set up on a per-project basis, either within the CircleCI app or via API.

To configure webhooks via API see our documentation for [Webhooks Public API](https://circleci.com/docs/api/v2/#tag/Webhook).

To configure webhooks within the CircleCI app:

1.  In the [CircleCI web app](https://app.circleci.com/), select your organization.
    
2.  Select **Projects** in the sidebar.
    
3.  Find your project in the list, select the ellipsis , and select **Project Settings**.
    
4.  In the sidebar select **Webhooks**.
    
5.  Select **Add Webhook**.
    
6.  Fill out the webhook form (the table below describes the fields and their intent).
    
7.  If your receiving API or third party service is set up, select **Test Ping Event** to send a test event.
    
    The test ping event has an abbreviated payload for ease of testing. See full examples for [Sample Webhook Payloads](https://circleci.com/docs/reference/outbound-webhooks-reference/#sample-webhook-payloads) section of the webhooks reference.
    

| Field | Required? | Intent |
| --- | --- | --- |
| Webhook name | Y | The name of your webhook |
| URL | Y | The URL the webhook will make POST requests to |
| Certificate Validation | Y | Ensure the receiving host has a valid SSL certificate before sending an event. You should only leave this unchecked for testing purposes. |
| Secret token | N | Used by your API/platform to validate incoming data is from CircleCI |
| Select an event | Y | You must select at least one event that will trigger a webhook |

## Communication protocol for outbound webhooks

Once set up, a webhook is sent whenever an event occurs on the CircleCI platform.

A webhook is sent using an HTTP POST to the URL that was registered when the webhook was created, with a body encoded using JSON.

CircleCI expects the server that responds to a webhook will return a 2xx response code. If a non-2xx response is received, CircleCI will retry at a later time. If CircleCI does not receive a response to the webhook within a short period of time, CircleCI will assume that delivery has failed, and will retry at a later time. The timeout period is currently 10 seconds.

Webhook requests may be duplicated. To deduplicate (prevent requests from being duplicated for a specific event), use the [ID Property](https://circleci.com/docs/reference/outbound-webhooks-reference/#common-top-level-keys) in the webhook payload for identification.

If you have feedback about timeouts and retries, [get in touch](https://circleci.canny.io/webhooks) with our team.

### Outbound webhook headers

A number of HTTP headers are set on webhooks, as detailed in the table below.

| Header name | Value |
| --- | --- |
| `content-type` | `application/json` |
| `user-agent` | A string indicating that the sender was CircleCI (`CircleCI-Webhook/1.0`). |
| `circleci-event-type` | The type of event, (`workflow-completed`, `job-completed`, etc). |
| `circleci-signature` | When present, this signature can be used to verify that the sender of the webhook has access to the secret token. |

## Validate outbound webhooks

You should validate webhooks as they come in to third party services to verify that they are coming from CircleCI. To support this, when creating a webhook, you can optionally provide a secret token. Each outgoing HTTP request to your service will contain a `circleci-signature` header. This header will consist of a comma-separated list of versioned signatures.

```shell
POST /uri HTTP/1.1
Host: your-webhook-host
circleci-signature: v1=4fcc06915b43d8a49aff193441e9e18654e6a27c2c428b02e8fcc41ccc2299f9,v2=...,v3=...
```

Currently, the latest (and only) signature version is v1. You should _only_ check the latest signature type to prevent downgrade attacks.

The v1 signature is the HMAC-SHA256 digest of the request body, using the configured signing secret as the secret key.

Here are some example signatures for given request bodies:

| Body | Secret Key | Signature |
| --- | --- | --- |
| `hello world` | `secret` | `734cc62f32841568f45715aeb9f4d7891324e6d948e4c6c60c0621cdac48623a` |
| `lalala` | `another-secret` | `daa220016c8f29a8b214fbfc3671aeec2145cfb1e6790184ffb38b6d0425fa00` |
| `an-important-request-payload` | `hunter123` | `9be2242094a9a8c00c64306f382a7f9d691de910b4a266f67bd314ef18ac49fa` |

The following is an example of how you might validate signatures in Python:

```python
import hmac

def verify_signature(secret, headers, body):
    # get the v1 signature from the `circleci-signature` header
    signature_from_header = {
        k: v for k, v in [
            pair.split('=') for pair in headers['circleci-signature'].split(',')
        ]
    }['v1']

    # Run HMAC-SHA256 on the request body using the configured signing secret
    valid_signature = hmac.new(bytes(secret, 'utf-8'), bytes(body, 'utf-8'), 'sha256').hexdigest()

    # use constant time string comparison to prevent timing attacks
    return hmac.compare_digest(valid_signature, signature_from_header)

# the following will return `True`
verify_signature(
    'secret',
    {
        'circleci-signature': 'v1=773ba44693c7553d6ee20f61ea5d2757a9a4f4a44d2841ae4e95b52e4cd62db4'
    },
    'foo',
)

# the following will return `False`
verify_signature(
    'secret',
    {
        'circleci-signature': 'v1=not-a-valid-signature'
    },
    'foo',
)
```

## Outbound webhook event specifications

CircleCI currently offers outbound webhooks for the following events:

<table><thead><tr><th>Event type</th><th>Description</th><th>Potential status</th><th>Included sub-entities</th></tr></thead><tbody><tr><td>workflow-completed</td><td>A workflow has reached a terminal state</td><td><div><div><ul><li><p>"success"</p></li><li><p>"failed"</p></li><li><p>"error"</p></li><li><p>"canceled"</p></li><li><p>"unauthorized"</p></li></ul></div></div></td><td>project, organization, workflow, pipeline</td></tr><tr><td>job-completed</td><td>A job has reached a terminal state</td><td><div><div><ul><li><p>"success"</p></li><li><p>"failed"</p></li><li><p>"canceled"</p></li><li><p>"unauthorized"</p></li></ul></div></div></td><td>project, organization, workflow, pipeline, job</td></tr></tbody></table>

## Next steps

*   See the [Webhooks Reference](https://circleci.com/docs/reference/outbound-webhooks-reference/) page for key definitions and sample payloads.
    
*   Follow the [Using Webhooks With Third Party Tools](https://circleci.com/docs/guides/integration/webhooks-airtable/) tutorial.