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

# Webhook events

> Every event that can reach your endpoint, who receives it, and the body each one carries.

Every delivery names its event in the `X-Usertick-Event` header, and every survey event also names it in the body's `type`. Usertick may add events within v1, so a handler should check the event first and ignore any event it doesn't recognize.

## Response events

| Event | When it is sent | Who receives it |
| - | - | - |
| `response.created` | Right after a response is submitted. `data.ai` is always null. | Workflows that start **When a response is submitted** and send to the endpoint with a **Send to a webhook** step, endpoints set to **When a response is submitted** in Settings, and subscriptions to `response.created` |
| `response.analyzed` | After AI analysis, usually about 30 seconds after the response. `data.ai` carries the type, urgency, theme, category and sentiment. | Workflows that start **After AI analysis** and send to the endpoint with a **Send to a webhook** step, endpoints set to **After AI analysis** in Settings, and subscriptions to `response.analyzed` |

The AI analyzes a response that has a written answer of 20 characters or more, or two or more answers. A response it doesn't analyze, or one the analysis failed on, is still sent after AI analysis with `data.ai` set to null.

A workflow runs at most once for each event it starts on.

Each event has a reference page with its full schema: [response.created](https://docs.usertick.com/developers/api/reference/webhook-response-created.md) and [response.analyzed](https://docs.usertick.com/developers/api/reference/webhook-response-analyzed.md).

## AI events

Four more events report what happens after a response arrives: a status change, a correction to the AI's reading, high urgency and a spiking theme.

| Event | When it is sent | Who receives it |
| - | - | - |
| `response.status_changed` | A response's status changed. The change can come from a teammate in the inbox (one response or many at once), an API key or app through [`PATCH /responses/{responseId}`](https://docs.usertick.com/developers/api/reference/update-response), or a linked [Jira](https://docs.usertick.com/integrations/jira.md) or [Linear](https://docs.usertick.com/integrations/linear.md) issue. Setting the same status again sends nothing. | Endpoints set to **When its status changes** in Settings, and subscriptions to `response.status_changed` |
| `response.classification_corrected` | A teammate, an API key or an app changed what the AI said: the response's type or urgency, or one answer's type, theme or category. Corrections to sentiment, customer risk and spam are not sent, and neither are changes a Jira or Linear sync makes. | Endpoints set to **When someone corrects the AI** in Settings, and subscriptions to `response.classification_corrected` |
| `response.urgent` | A response's urgency became high, because the AI read it as high or a teammate, an API key or an app set it to high. Sent once per response and endpoint. | Workflows that start **When a response becomes urgent** and send to the endpoint with a **Send to a webhook** step, endpoints set to **When it becomes urgent** in Settings, and subscriptions to `response.urgent` |
| `theme.spiking` | A theme receives far more responses than the day before. See [Theme spikes](#theme-spikes). | Endpoints set to **When a theme spikes** in Settings, and subscriptions to `theme.spiking` |

A workflow can start on `response.urgent`, but not on the other three events. Its **Send to a webhook** step sends the event the workflow started on.

Reference pages: [response.status\_changed](https://docs.usertick.com/developers/api/reference/webhook-response-status-changed.md), [response.classification\_corrected](https://docs.usertick.com/developers/api/reference/webhook-response-classification-corrected.md), [response.urgent](https://docs.usertick.com/developers/api/reference/webhook-response-urgent.md) and [theme.spiking](https://docs.usertick.com/developers/api/reference/webhook-theme-spiking.md).

### What changed

`response.status_changed` and `response.classification_corrected` carry the response as it reads now, plus `data.change`:

```json theme={null}
{
  "id": "0d4e6f70-1a2b-4c3d-8e9f-a0b1c2d3e4f5:n1",
  "type": "response.status_changed",
  "createdAt": "2026-09-30T12:31:05.120Z",
  "data": {
    "id": "9b1c2d3e-4f50-4a61-8b72-93a4b5c6d7e8",
    "status": "resolved",
    "...": "the rest of the Response resource",
    "change": {
      "field": "status",
      "questionId": null,
      "from": "open",
      "to": "resolved",
      "by": { "kind": "integration", "id": "jira", "name": "Jira" }
    }
  }
}
```

| Field | What it holds |
| - | - |
| `field` | `status` on `response.status_changed`. `type`, `urgency`, `theme` or `category` on `response.classification_corrected`. |
| `questionId` | The answer a type, theme or category correction is on. `null` when the change is on the whole response. |
| `from`, `to` | The value before and after, written the way `data.ai` writes it. A status, type or urgency is a string, such as `in_progress` or `bug`. A theme or category is `{ "id": "...", "name": "..." }`. `null` means no value. A value nobody set is the AI's own reading, so when someone clears a correction, `to` is what the AI read. |
| `by` | Who made the change. `kind` is `member`, `api_key`, `app` or `integration`. `id` is the member id (as in [`GET /members`](https://docs.usertick.com/developers/api/reference/list-members)), the key or app id, or `jira` or `linear`. `name` is the member's name or email, the key's or app's name, or the tool's name. |

A correction to a theme looks like this:

```json theme={null}
"change": {
  "field": "theme",
  "questionId": "9e8d7c6b-0000-4a5b-8c9d-0e1f2a3b4c5d",
  "from": { "id": "44444444-4444-4444-8444-444444444444", "name": "Checkout errors" },
  "to": { "id": "77777777-7777-4777-8777-777777777777", "name": "Card declined" },
  "by": { "kind": "member", "id": "66666666-6666-4666-8666-666666666666", "name": "Ana Ruiz" }
}
```

`response.urgent` carries the response as it reads now, with no `change`. Its `data.ai.urgency` is `high`.

A status a Jira or Linear sync applied comes with `by.kind` set to `integration` and is never sent back to the tracker, so a Zap or script that writes the same status again does not start a loop.

### Theme spikes

Usertick checks themes every hour. A theme spikes when, over the last 24 hours:

* it has **at least 10 responses**, and
* that is **at least 2 times** its count in the 24 hours before.

Nothing spikes when the covered surveys had no responses at all in the 24 hours before, so a survey that just went live doesn't trigger a spike. When those surveys had responses the day before, a theme with no responses that day spikes on its count alone.

Each endpoint or subscription receives a spike for the same theme **at most once every 24 hours**, and **at most 5 spikes per check**, the largest first. The counts include only the surveys it covers, and they include corrections your team made.

```json theme={null}
{
  "id": "3c5d7e9f-2b4a-4c6d-8e0f-1a3b5c7d9e0f:n1",
  "type": "theme.spiking",
  "createdAt": "2026-09-30T14:50:00.000Z",
  "data": {
    "theme": { "id": "44444444-4444-4444-8444-444444444444", "name": "Checkout errors" },
    "category": { "id": "55555555-5555-4555-8555-555555555555", "name": "Payments" },
    "window": { "from": "2026-09-29T14:50:00.000Z", "to": "2026-09-30T14:50:00.000Z" },
    "count": 24,
    "previousCount": 6,
    "share": 12.5,
    "surveyIds": []
  }
}
```

| Field | What it holds |
| - | - |
| `theme` | The theme that spiked |
| `category` | Its category, or `null` |
| `window` | The 24 hours measured |
| `count` | Responses with an answer in the theme during the window |
| `previousCount` | The same over the 24 hours before |
| `share` | The theme's responses as a percent of every response in the window, from 0 to 100 with one decimal |
| `surveyIds` | The surveys counted. Empty means every survey. |

`data` is a spike, not a response, so code that handles response events should check `type` first.

### Filters

Each event takes the filters in this table. A subscription sets them in `filters`, and an endpoint in Settings sets them under **Only these responses**, or **Only these themes** for `theme.spiking`.

| Event | Feedback types | Urgency | Themes |
| - | - | - | - |
| `response.created` | No | No | No |
| `response.analyzed` | Yes | Yes | Yes |
| `response.status_changed` | Yes | Yes | Yes |
| `response.classification_corrected` | Yes | Yes | Yes |
| `response.urgent` | Yes | No, it is always high | Yes |
| `theme.spiking` | No | No | Yes |
| `workflow.step` | No | No | No |

* **Feedback types**: `bug`, `idea`, `complaint`, `question`, `praise`.
* **Urgency**: `high`, `medium`, `low`.
* **Themes**: theme ids from [`GET /themes`](https://docs.usertick.com/developers/api/reference/list-themes), up to 5,000. A response matches when any of its answers is in one of them. On `theme.spiking`, only those themes are reported.

The API answers `400` with `APK-006-002` for a filter the event doesn't take, `APK-006-010` for an unknown theme and `APK-006-011` for more than 5,000 themes.

### Choose the event in Settings

An endpoint's **Survey events** settings appear when you create it with **New webhook** under **Settings → Developers → Webhooks**, and later under **Settings** in its row. **Surveys** starts at **No surveys**. When you select **All surveys, including new ones** or **Only selected surveys**, the **When** choices appear, each mapped to one event:

| Choice | Event |
| - | - |
| **When a response is submitted** | `response.created` |
| **After AI analysis** | `response.analyzed` |
| **When its status changes** | `response.status_changed` |
| **When someone corrects the AI** | `response.classification_corrected` |
| **When it becomes urgent** | `response.urgent` |
| **When a theme spikes** | `theme.spiking` |

Settings offers the filters from the table above. An endpoint sends one of these events, so another event needs a second endpoint with its own URL, such as a different path. **Only selected surveys** takes as many surveys as you select.

### Latest items from the API

[`GET /responses/recent`](https://docs.usertick.com/developers/api/reference/list-recent-responses) returns the newest items in the shape a delivery of the same event carries in `data`, filtered the way a subscription is. Zapier uses it for trigger samples. It looks through the newest 1,000 responses, or the newest 1,000 status changes, within your plan's history. When a filter matches only older items, it returns fewer than `limit`. To read every response, use [`GET /responses`](https://docs.usertick.com/developers/api/reference/list-responses).

| `event` | What comes back |
| - | - |
| `response.created` | The newest responses, with `ai` set to null |
| `response.analyzed` | The newest analyzed responses |
| `response.status_changed` | The newest status changes, each with its `change`. A response that changed twice is listed twice. |
| `response.urgent` | The newest responses whose urgency is high |
| `response.classification_corrected` | Not listed. The API answers `400` with `APK-006-012`. |
| `theme.spiking` | Not listed. The API answers `400` with `APK-006-012`. |

## A workflow's Zapier step

A subscription can receive what a workflow sends to one of its Zapier steps instead of an event. Such a subscription sets `event` to `workflow.step` and names the step with `workflowId` and `stepId`, which [`GET /workflows/zapier-steps`](https://docs.usertick.com/developers/api/reference/list-zapier-steps) lists. The Zapier app's **Workflow Step** trigger subscribes this way.

```json theme={null}
{
  "targetUrl": "https://usertick.com/hooks/zapier-step",
  "event": "workflow.step",
  "workflowId": "9c3d4e5f-6071-4c8d-8e9f-1a2b3c4d5e6f",
  "stepId": "s_k3v9q2"
}
```

* The workflow's trigger, conditions, branches and waits decide which responses reach the step, so a `workflow.step` subscription takes no `surveyId` and no filters. A filter answers `400` with `APK-006-002`.
* Each delivery carries the event that started the workflow's run: `type` and the `X-Usertick-Event` header are `response.created`, `response.analyzed` or `response.urgent`, and `data` is the Response resource.
* `workflowId` and `stepId` are required with `workflow.step` and refused with any other event, with `400` and `APK-006-013`. A workflow or a Zapier step the organization doesn't have answers `404` with `APK-006-014`.
* A step has one subscription at a time. While one is active, another subscription to the same step answers `409` with `WH-005-010`.
* A step in a workflow's draft can be subscribed to before the workflow is published, and a test run of the workflow never sends to the subscription.
* The subscribe answer and the items of `GET /webhooks` include `workflowId` and `stepId`. They are set for a `workflow.step` subscription and `null` for every other subscription.
* When an app such as Zapier subscribes, the person who connected it needs the **Manage workflows** permission, or the API answers `403` with `AUTHZ-001-002`.
* When the workflow is deleted, Usertick deletes the subscriptions to its steps.

## A full payload

The following body is a `response.analyzed` delivery. A `response.created` delivery has the same shape with `"ai": null`.

```json theme={null}
{
  "id": "6f1d2c3b-8a90-4e12-b345-67c890d12e34:n1",
  "type": "response.analyzed",
  "createdAt": "2026-09-30T10:00:07.300Z",
  "data": {
    "id": "9b1c2d3e-4f50-4a61-8b72-93a4b5c6d7e8",
    "url": "https://app.usertick.com/inbox/9b1c2d3e-4f50-4a61-8b72-93a4b5c6d7e8",
    "survey": { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "name": "Checkout feedback" },
    "site": { "id": "22222222-2222-4222-8222-222222222222", "domain": "shop.example.com" },
    "createdAt": "2026-09-30T10:00:00.123Z",
    "updatedAt": "2026-09-30T10:00:07.250Z",
    "source": "widget",
    "language": "en",
    "country": "US",
    "pageUrl": "https://shop.example.com/checkout",
    "device": { "type": "desktop", "browser": "Chrome", "os": "macOS" },
    "variant": null,
    "variantName": null,
    "contact": { "id": null, "email": "maya@example.com" },
    "respondent": {
      "userId": "user_8271",
      "anonymousId": "5f0c7a2b-8d4e-4c1a-9e3f-2b6d8a0c4e1f",
      "verified": false,
      "email": "maya@example.com",
      "emailSource": "identify",
      "name": "Maya Chen",
      "company": null,
      "traits": { "plan": "pro" },
      "traitsVerified": false,
      "contactQuestion": null,
      "contact": null
    },
    "answers": [
      {
        "questionId": "4b1c2d3e-0000-4a5b-8c9d-0e1f2a3b4c5d",
        "question": "How likely are you to recommend us?",
        "type": "nps",
        "value": 4,
        "text": "4"
      },
      {
        "questionId": "9e8d7c6b-0000-4a5b-8c9d-0e1f2a3b4c5d",
        "question": "What went wrong?",
        "type": "text",
        "value": "Checkout rejects my card every time",
        "text": "Checkout rejects my card every time"
      }
    ],
    "answerText": {
      "4b1c2d3e-0000-4a5b-8c9d-0e1f2a3b4c5d": "4",
      "9e8d7c6b-0000-4a5b-8c9d-0e1f2a3b4c5d": "Checkout rejects my card every time"
    },
    "attachments": [],
    "status": "open",
    "assignees": [],
    "ai": {
      "type": "bug",
      "urgency": "high",
      "theme": { "id": "44444444-4444-4444-8444-444444444444", "name": "Checkout errors" },
      "category": { "id": "55555555-5555-4555-8555-555555555555", "name": "Payments" },
      "sentiment": "negative",
      "analyzedAt": "2026-09-30T10:00:07.250Z",
      "corrected": false
    },
    "commentsCount": 0
  }
}
```

Every field of `data` is described on [the Response resource](https://docs.usertick.com/developers/api/response-object.md). To see the payload for one of your own surveys, select an endpoint's row under **Settings → Developers → Webhooks**, select **Settings**, and select a survey and an event under **Payload sample**. The sample is built the same way as a real delivery, from the survey's newest response, or from its questions when the survey has no responses yet. For the two change events it adds an example change made by you, and for `theme.spiking` it shows an example spike for one of your themes.

## Test pings

**Send test** in an endpoint's row under **Settings → Developers → Webhooks** sends a `ping` event, which checks that the endpoint answers and that its signature check works. A ping carries the `X-Usertick-Test: 1` header, is sent once without retries, and isn't available for subscriptions made by an app or the API.

```json theme={null}
{
  "event": "ping",
  "timestamp": "2026-09-30T10:00:00.000Z",
  "webhook": { "id": "3b1f5a70-2222-4333-8444-555566667777", "name": "Production" },
  "message": "Hello from Usertick. If you see this, your endpoint is wired up correctly."
}
```

**Test run** on a workflow's page runs the workflow once on the survey's latest response, or on a sample response when the survey has none. Its **Send to a webhook** step sends a response envelope instead of a ping, also marked with `X-Usertick-Test: 1`.

## Account notifications

An endpoint created in Settings can also receive account notifications. None are selected when the endpoint is created. Account notifications aren't tied to a survey, and all of them share one body:

```json theme={null}
{
  "type": "MemberAdded",
  "eventKey": "member.added",
  "title": "New member joined",
  "body": "ada@usertick.com joined as Member",
  "url": "/settings/members",
  "organizationId": "8cf77a7d-3ce0-4c58-ba4d-0b33fbe8f8c5",
  "at": "2026-09-30T10:00:00.000Z"
}
```

The `X-Usertick-Event` header carries the event key.

| Event key | Sent when |
| - | - |
| `invitation.accepted` | Someone accepted an invitation |
| `member.added` | A member joined the organization |
| `member.removed` | A member was removed |
| `survey.published` | A survey went live |
| `usage.warning80` | The organization used 80 percent of this month's response limit, or its extra responses are running low. The `title` says which: "Responses at 80% of the monthly limit" or "Extra responses running low" |
| `usage.warning100` | The organization reached this month's response limit, or Usertick stopped collecting responses at the limit or when the extra responses ran out. The `title` says which: "Monthly response limit reached", "Response collection stopped" or "Extra responses used up" |
| `subscription.updated` | The plan changed |
| `subscription.past_due` | A payment failed |
| `subscription.canceled` | The subscription was canceled |
| `organization.updated` | Usertick support deactivated the organization or reactivated it |

Notifications about one person, such as a mention or a dashboard shared with someone, are not sent to webhooks.

> [!NOTE]
>
> Delivery failures are never sent as webhook events, because the report would go to the endpoint that is failing. Usertick notifies people in the app and by email instead.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.