---
title: "Send a circle’s or a project’s events to your own webhook URL"
description: "Send a circle’s governance events or a project’s tasks as JSON to a URL you own: connecting the card, the payload each event carries, and the events that are not sent"
category: integrations
section: native-integrations
type: Reference
lastUpdated: 2026-09-30
locale: en
canonical: https://support.talkspirit.com/en/integrations/send-circle-or-project-events-to-your-own-webhook
---

# Send a circle’s or a project’s events to your own webhook URL


> **In summary:** open the circle’s settings, then the **Integrations** tab, select **Enable** on the **Webhook** card, paste your URL and **Confirm**. Each governance event of the circle is then sent to that URL as a JSON `POST`, in the format the previous webhook integration used. 25 kinds of event are sent, and a project can send its tasks the same way. 12 are never sent, and this page lists them.

This guide covers the **Webhook** card on a circle. It is not the [Partner API](/integrations/partner-api), which is a developer surface with its own keys and scopes. What a circle integration sends, family by family, is described in [Circle and project integrations](/integrations/circle-and-project-integrations-overview).

Unlike Slack or Microsoft Teams, the destination is a service you run, not a conversation. Nobody reads the result: a program does.

## Before you start

- You are an organisation administrator, or an administrator of the circle.
- You have an endpoint reachable from the internet that accepts a `POST` with a JSON body.
- It answers within 10 seconds, with a status below `400`. Redirects are not followed.

## Connect the circle

1. Open the circle’s settings, then the **Integrations** tab.
2. On the **Webhook** card, select **Enable**. A **Webhook URL** field opens. There is no sign-in and no consent screen.
3. Paste the URL and select **Confirm**.

The card now reads **Connected**: "The webhook URL is stored. Events are sent to it as JSON."

The URL is checked when you select **Confirm**, not when the first event is sent. A malformed address, or one that points to an internal network, is refused there. The reason appears under the field and nothing is stored.

> **Important:** the request carries no signature. Anyone who knows the URL can send your endpoint a body that looks like ours. Use a long URL that cannot be guessed, and treat it like a password.

## Check it works

Nothing is sent when you select **Confirm**. Select **Test** on the card: your endpoint receives this body, and the card records the result.

```json
{
  "object": "connection_test",
  "text": "Talkspirit is connected to this channel. Governance changes in this circle will be posted here."
}
```

If your automation filters on `object`, ignore `connection_test`.

## Change or remove the URL

- **Change the webhook URL** points the circle to a new URL. It also clears the failure count, so it is the repair when the endpoint moved.
- **Disable** removes the URL and the event settings. Nothing more is sent.

## What your endpoint receives

Each event is one `POST` with a JSON body and the `User-Agent` header `Holaspirit Client`. Two keys are always present:

- `object`: what the event is about, for example `role` or `tension`.
- `text`: the event as a sentence, for example `New role Facilitator`.

The other keys depend on `object`. `activity` only exists on the objects that take it.

| `object` | Sent for | Other keys |
| --- | --- | --- |
| `role` | A role or a circle created or updated, a role turned into a circle, a circle turned into a role | `id`, `circle`, `purpose`, `url` |
| `role` | A role or a circle deleted | `circle`, and `url`, which links to the parent circle |
| `policy` | A policy published or updated | `id`, `circle`, `description`, `domain`, `url` |
| `policy` | A policy deleted | `circle`, `url` |
| `tension` | A proposal adopted (`activity: accept`) or rejected (`activity: refuse`) | `activity`, `id`, `name`, `body`, `circle`, `member` |
| `assignation` | A member assigned to a role | `assignation`, `circle`, `circle_id`, `role`, `role_id`, `focus`, `member`, `member_id`, `url` |
| `circleAssignation` | A member assigned to a circle | `assignation`, `circle`, `circle_id`, `member`, `member_id`, `url` |
| `unassignation` | A member removed from a role or a circle | `unassignation`, `circle`, `circle_id`, `member`, `member_id`, `url`, and `role`, `role_id` for a role |
| `objective` | A goal created (`activity: create`), updated (`activity: update`) or deleted (`activity: delete`) | `activity`, `id`, `title`, `description`, `circle`, `members`, `role`, `status`, `url` |
| `checklist`, `metric` | A checklist or a metric created or updated | `id`, `title`, `body`, `circle`, `members`, `recurrence`, and `role` when there is one |
| `project` | A task created (`activity: create`), updated (`activity: update`) or deleted (`activity: delete`) on a project | `activity`, `id`, `title`, `body`, `url`, `board`, `board_id` |

A circle is sent as `object: role`, as the previous integration did. The proposal object is called `tension`, and names its subject `name` rather than `title`: both are the previous integration’s names, kept as they were.

For example, a member assigned to a role:

```json
{
  "object": "assignation",
  "text": "Assignation for role: Facilitator",
  "assignation": "Ada Lovelace was assigned to the role: Facilitator",
  "circle": "Commercial",
  "circle_id": "11111111-2222-3333-4444-555555555555",
  "role": "Facilitator",
  "role_id": "r-1",
  "focus": "EMEA",
  "member": "Ada Lovelace",
  "member_id": "u-1",
  "url": "https://…"
}
```

## Events that are not sent

Of the 37 kinds of event an integration knows, 12 are never sent to a webhook. Each one is refused before anything leaves Talkspirit. A refused event does not count as a failed delivery: the other events keep being sent.

**The previous integration never sent them**: `unsupported_event_kind`, 12 events. They will not be added: there is no earlier format to reproduce.

| Events | Why |
| --- | --- |
| A proposal submitted or withdrawn | The previous integration only sent the outcome: adopted or rejected. |
| A tension raised or closed | The previous integration had no equivalent of this object. |
| A role or a circle moved | The previous integration never announced a move. |
| A meeting finished, a meeting about to start, a meeting report published | The previous integration sent no meeting event to a webhook. |
| A project created, updated or deleted | The previous integration had no project object. |

## Compatibility with the previous webhook format

**For every event it sends, this integration keeps the format of the previous webhook integration.** The same `object` names, the same keys, the same `text` sentence and the same `User-Agent`. An endpoint written for the previous webhook integration reads them without any change.

Some values are not filled yet, and an endpoint that reads them sees the difference:

- `body` on `tension`, `checklist` and `metric`, `description` and `members` on `objective`, and `members` and `recurrence` on `checklist` and `metric` are `null`.
- On `policy`, `description` is empty, and `domain` always holds the text used for a policy with no domain: `All functions and activities within the circle`.
- On `checklist` and `metric`, `last_checked` is never present.
- On `policy`, `url` links to the policy's own page, where the previous integration linked to its circle.

Tasks arrive from a project's webhook as `object: project`, with `board` and `board_id`. The keys the previous integration added to a task, `context`, `circle`, `members`, `role` and `status`, are absent, not `null`.

## On a project

A project connects the webhook from its settings, under **Notifications**, with the same card. You need to be an owner or editor of the project.

- A project holds one webhook destination. Pasting a new URL replaces the previous one.
- A project sends its tasks: a task created or deleted, and a task whose status, priority or due date changes. Subtasks, private tasks and tasks created on a private or secret project are not sent.

For example, a task created on a project:

```json
{
  "object": "project",
  "activity": "create",
  "id": "t-1",
  "text": "New project Ship v2",
  "title": "Ship v2",
  "body": null,
  "url": "https://…",
  "board": "Roadmap",
  "board_id": "66666666-7777-8888-9999-aaaaaaaaaaaa"
}
```

## Several destinations on one circle

A circle can hold more than one webhook destination, as before the migration. Each event is then sent to every destination.

The card, however, manages exactly one. On a circle that holds several, it reads **This circle has more than one destination** and offers nothing: no **Enable**, no **Change the webhook URL**, no **Disable**, no switches and no **Test**. Delivery to every destination continues. To change them, contact Talkspirit support.

## When delivery stops

The URL is the only credential, so pasting a working URL is the repair. There is no **Reconnect** button.

| What the card says | What it means | What to do |
| --- | --- | --- |
| **Sending was interrupted** | Five deliveries in a row failed: your endpoint refused them or did not answer in time. | Fix the cause, then select **Test**, or **Change the webhook URL**. The first success clears the count. |
| **Connected, but nothing has ever been delivered** | The URL was stored, and every attempt since has failed. | Check that your endpoint accepts a `POST` from the internet and answers below `400`. |
| **Recent notifications were not delivered** | Delivery worked before and is failing now. | Check your endpoint's logs. |
| **Notifications are paused on our side** | A fault in Talkspirit, not in your configuration. | Nothing. Our team is alerted automatically and your settings are untouched. |

An answer of `429` from your endpoint is not counted as a failure: Talkspirit reads it as a request to slow down.

## What’s next?

- [Circle and project integrations](/integrations/circle-and-project-integrations-overview), what is sent, the event families, and reading the card
- [Connect a circle or a project to Slack](/integrations/connect-a-circle-or-a-project-to-slack)
- [Connect a circle or a project to Microsoft Teams](/integrations/connect-a-circle-or-a-project-to-microsoft-teams)
