---
title: Create an integration
description: Creates a notification integration. type picks the integration, and config holds its settings, listed per type in Integration types.
url: https://docs.honeybadger.io/api/v3/integrations/create-integration/
---

API v3 is in preview

Endpoints and response shapes [can change before general availability](https://docs.honeybadger.io/api/v3/#preview). API v2 is unchanged.

POST `https://app.honeybadger.io/v3/projects/{project_id}/integrations`

[Required scope](https://docs.honeybadger.io/api/v3/authentication/#scopes) `integrations:write`

Creates a notification integration. `type` picks the integration, and `config` holds its settings, listed per type in [Integration types](https://docs.honeybadger.io/api/v3/integrations/types/). An OAuth integration (Slack, GitHub, Linear and the like) sends nothing until someone connects it in the web UI at its `links.web`.

Example request

```sh
curl -X POST "https://app.honeybadger.io/v3/projects/$PROJECT_ID/integrations" \
  -H "Authorization: Bearer $HONEYBADGER_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "type": "WebHook",
  "events": [
    "occurred",
    "resolved"
  ],
  "config": {
    "url": "https://example.com/hook"
  }
}'
```

## Parameters

### Path parameters

| Field | Type | Description |
| - | - | - |
| `project_id` required | string | Project ID. |

## Request body

A new integration. `type` picks the integration, and `config` holds that type’s settings. OAuth integrations (Slack, GitHub and the like) are created active by default and send nothing until someone connects them in the web UI at `links.web`. Some required settings are IDs from the other service, such as a Linear team or a Trello board.

| Field | Type | Description |
| - | - | - |
| `active` | boolean | Whether to use the integration. An OAuth integration that's active sends nothing until someone connects it in the web UI at `links.web`. Default: `true`. |
| `rate` | string \| null | Period the `rate_exceeded` threshold counts over. Null resets it to `wday`. Period the `rate_exceeded` threshold counts over: `min` a minute, `hour` an hour, `wday` a day (24 hours, not a weekday), `week` a week. Allowed values: `min`, `hour`, `wday`, `week`. Default: `"wday"`. |
| `threshold` | integer \| null | Number of occurrences before `rate_exceeded` fires. Null resets it to 100. Default: `100`. |
| `notification_limit` | integer \| null | Maximum notifications in a 10-minute window before flood control. Null removes the limit. |
| `site_ids` | array \| null | Sites whose up and down events this integration receives. null follows every site in the project, including ones added later; a create that leaves it out does the same. \[] follows none, and a list follows just those sites. A set; order is ignored and duplicates are dropped. |
| `check_in_ids` | array \| null | Check-ins whose events this integration receives. null follows every check-in in the project, including ones added later; a create that leaves it out does the same. \[] follows none, and a list follows just those check-ins. A set; order is ignored and duplicates are dropped. |
| `alarm_alert_ids` | array \| null | IDs of alarms whose alert events this integration receives. Null or empty clears it. A set; order is ignored and duplicates are dropped. Default: `[]`. |
| `alarm_ok_ids` | array \| null | IDs of alarms whose recovery events this integration receives. Null or empty clears it. A set; order is ignored and duplicates are dropped. Default: `[]`. |
| `excluded_environments` | array \| null | Errors from these environments never notify through this integration. Takes precedence over `included_environments`. An environment can be excluded before it first reports. Null or empty clears it. Changing it requires environment settings on the plan. A set; order is ignored and duplicates are dropped. Default: `[]`. |
| `included_environments` | array \| null | When non-empty, only errors from these environments notify through this integration, including environments that haven't reported yet. Empty means every environment not excluded. Null or empty clears it. Changing it requires environment settings on the plan. A set; order is ignored and duplicates are dropped. Default: `[]`. |
| `filters` | array \| null | An ordered list. Each event that has a filter notifies only for errors matching its query. Replaces the stored filters; null or empty clears them. Changing it requires integration filters on the plan. Default: `[]`. |
| `filters[].event` required | string | An event a filter applies to, or `all` for every event. Allowed values: `occurred`, `rate_exceeded`, `assigned`, `resolved`, `unresolved`, `commented`, `deployed`, `up`, `down`, `cert_will_expire`, `flooded`, `check_in_missing`, `check_in_reporting`, `alarm_alert`, `alarm_ok`, `volume_spike`, `all`. |
| `filters[].query` required | string | An error search query, as in the Errors search box. Min length 1. |

The remaining fields depend on `type`. See [Integration types](https://docs.honeybadger.io/api/v3/integrations/types/) for each value's settings.

| Type | Value | Settings |
| - | - | - |
| [AlertOps](https://docs.honeybadger.io/api/v3/integrations/types/#alertops) | `AlertOps` | 2 |
| [Asana](https://docs.honeybadger.io/api/v3/integrations/types/#asana) | `Asana` | 1 |
| [Backlog](https://docs.honeybadger.io/api/v3/integrations/types/#backlog) | `Backlog` | 11 |
| [Bitbucket](https://docs.honeybadger.io/api/v3/integrations/types/#bitbucket) | `Bitbucket` | 1 |
| [Campfire](https://docs.honeybadger.io/api/v3/integrations/types/#campfire) | `CampfireV3` | 1 |
| [ClickUp](https://docs.honeybadger.io/api/v3/integrations/types/#clickup) | `ClickUp` | 10 |
| [ClickUp Chat](https://docs.honeybadger.io/api/v3/integrations/types/#clickup-chat) | `ClickUpChat` | 2 |
| [Datadog](https://docs.honeybadger.io/api/v3/integrations/types/#datadog) | `Datadog` | 4 |
| [Discord](https://docs.honeybadger.io/api/v3/integrations/types/#discord) | `DiscordWebhook` | 2 |
| [Email](https://docs.honeybadger.io/api/v3/integrations/types/#email) | `Email` | 2 |
| [GitHub](https://docs.honeybadger.io/api/v3/integrations/types/#github) | `Github` | 6 |
| [GitLab](https://docs.honeybadger.io/api/v3/integrations/types/#gitlab) | `Gitlab` | 6 |
| [Google Chat](https://docs.honeybadger.io/api/v3/integrations/types/#google-chat) | `GoogleHangoutsChat` | 2 |
| [ilert](https://docs.honeybadger.io/api/v3/integrations/types/#ilert) | `Ilert` | 2 |
| [incident.io](https://docs.honeybadger.io/api/v3/integrations/types/#incidentio) | `IncidentIo` | 2 |
| [Instatus](https://docs.honeybadger.io/api/v3/integrations/types/#instatus) | `Instatus` | 2 |
| [Intercom](https://docs.honeybadger.io/api/v3/integrations/types/#intercom) | `Intercom` | 1 |
| [Jira](https://docs.honeybadger.io/api/v3/integrations/types/#jira) | `Jira` | 11 |
| [Jira Cloud](https://docs.honeybadger.io/api/v3/integrations/types/#jira-cloud) | `JiraCloud` | 8 |
| [Linear](https://docs.honeybadger.io/api/v3/integrations/types/#linear) | `Linear` | 8 |
| [Mattermost](https://docs.honeybadger.io/api/v3/integrations/types/#mattermost) | `Mattermost` | 2 |
| [Microsoft Teams](https://docs.honeybadger.io/api/v3/integrations/types/#microsoft-teams) | `MicrosoftTeamsV2` | 2 |
| [OpsGenie](https://docs.honeybadger.io/api/v3/integrations/types/#opsgenie) | `OpsGenieV2` | 3 |
| [PagerDuty](https://docs.honeybadger.io/api/v3/integrations/types/#pagerduty) | `PagerDutyV2` | 3 |
| [PagerTree](https://docs.honeybadger.io/api/v3/integrations/types/#pagertree) | `PagerTree` | 1 |
| [Redmine](https://docs.honeybadger.io/api/v3/integrations/types/#redmine) | `Redmine` | 4 |
| [Rootly](https://docs.honeybadger.io/api/v3/integrations/types/#rootly) | `Rootly` | 4 |
| [Shortcut](https://docs.honeybadger.io/api/v3/integrations/types/#shortcut) | `ShortcutV2` | 9 |
| [Slack](https://docs.honeybadger.io/api/v3/integrations/types/#slack) | `Slack` | 2 |
| [Splunk On-Call](https://docs.honeybadger.io/api/v3/integrations/types/#splunk-on-call) | `VictorOps` | 3 |
| [Sprintly](https://docs.honeybadger.io/api/v3/integrations/types/#sprintly) | `Sprintly` | 4 |
| [Trello](https://docs.honeybadger.io/api/v3/integrations/types/#trello) | `Trello` | 3 |
| [Webhook](https://docs.honeybadger.io/api/v3/integrations/types/#webhook) | `WebHook` | 4 |
| [Zulip](https://docs.honeybadger.io/api/v3/integrations/types/#zulip) | `Zulip` | 6 |

## Responses

### 201 Created

Example payload

```json
{
  "data": {
    "id": "Ch9wLp",
    "project_id": "Xk9mZp",
    "type": "Slack",
    "active": true,
    "events": [
      "occurred",
      "resolved",
      "assigned"
    ],
    "site_ids": null,
    "check_in_ids": null,
    "excluded_environments": [
      "development"
    ],
    "included_environments": [],
    "filters": [
      {
        "event": "occurred",
        "query": "environment:production"
      }
    ],
    "alarm_alert_ids": [],
    "alarm_ok_ids": [],
    "threshold": 100,
    "rate": "min",
    "notification_limit": null,
    "connected": true,
    "config": {},
    "error": true,
    "error_reason": "The webhook URL returned 410 Gone",
    "created_at": "2026-01-01T00:00:00Z",
    "links": {
      "web": "https://app.honeybadger.io/projects/Xk9mZp"
    }
  },
  "meta": {
    "request_id": "6f1c2b0e-8d4a-4f6e-9b2a-3c5d7e9f1a2b"
  }
}
```

Response schema

| Field | Type | Description |
| - | - | - |
| `data` required | object | A notification integration. |
| `data.id` required | string | |
| `data.project_id` required | string | ID of the project this integration belongs to. |
| `data.type` required | string | Integration type. |
| `data.active` required | boolean | Whether to use the integration. An OAuth integration that isn't `connected` sends nothing until it is. |
| `data.events` required | array\<string> | Events this integration notifies on. |
| `data.site_ids` required | array \| null | Sites whose up and down events this integration receives. null means every site in the project, including ones added later. |
| `data.check_in_ids` required | array \| null | Check-ins whose events this integration receives. null means every check-in in the project, including ones added later. |
| `data.excluded_environments` required | array\<string> | Errors from these environments never notify through this integration. Takes precedence over `included_environments`. |
| `data.included_environments` required | array\<string> | When non-empty, only errors from these environments notify through this integration. |
| `data.filters` required | array\<object> | An ordered list. Each event that has a filter notifies only for errors matching its query. |
| `data.filters[].event` required | string | An event a filter applies to, or `all` for every event. Allowed values: `occurred`, `rate_exceeded`, `assigned`, `resolved`, `unresolved`, `commented`, `deployed`, `up`, `down`, `cert_will_expire`, `flooded`, `check_in_missing`, `check_in_reporting`, `alarm_alert`, `alarm_ok`, `volume_spike`, `all`. |
| `data.filters[].query` required | string | An error search query, as in the Errors search box. Min length 1. |
| `data.alarm_alert_ids` required | array\<string> | IDs of alarms whose alert events this integration receives. |
| `data.alarm_ok_ids` required | array\<string> | IDs of alarms whose recovery events this integration receives. |
| `data.threshold` required | integer | Occurrence threshold before `rate_exceeded` fires. |
| `data.rate` required | string | Period the `rate_exceeded` threshold counts over: `min` a minute, `hour` an hour, `wday` a day (24 hours, not a weekday), `week` a week. Allowed values: `min`, `hour`, `wday`, `week`. |
| `data.notification_limit` required | integer \| null | Maximum notifications in a 10-minute window before flood control. |
| `data.connected` | boolean | Present on OAuth integrations (Slack, GitHub, GitLab, Bitbucket, Jira Cloud, Asana, Intercom and the like) and WebSocket integrations. On an OAuth integration it says whether the integration is authenticated, which someone does in the web UI at `links.web`. Separate from `active`: an active integration that isn't connected sends nothing until it is, and connecting doesn't change `active`. GitHub authenticates through the GitHub App: the app is installed on the repo, and the installation is attached when someone with access to it saves the integration. A creator who signed in to Honeybadger with GitHub is connected on create. On a WebSocket integration it says whether a client checked in within the last two minutes. |
| `data.config` required | object | The type's settings, one IntegrationConfig\<Type> per `type`. Unset settings are null. Write-only secrets are never returned. Other settings are, including webhook URLs, which can contain credentials. |
| `data.error` | boolean | Set when a delivery fails in a way that stops the integration; `error_reason` says why. The integration sends nothing while it's set. A successful update clears it. |
| `data.error_reason` | string | Reason for the error state, if any. |
| `data.created_at` required | date-time | When the integration was created. |
| `data.links` required | object | Links into the Honeybadger web UI. |
| `data.links.web` required | uri | The resource's page in the Honeybadger web UI, as an absolute URL. Resources without a page, such as outages and deploys, don't have `links`. For a project provisioned through Heroku, error, notice and comment links go through Heroku's single sign-on. |
| `meta` | object | |
| `meta.request_id` | string | Unique identifier for the request, for correlating with support. |

## Errors

### 401 Unauthorized

The credential is missing, invalid, expired or revoked (`unauthorized`), or was sent in a way v3 doesn’t accept (see the examples).

Example payload: unauthorized (Missing, malformed, expired or revoked credential)

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Access denied"
  },
  "meta": {
    "request_id": "abc123"
  }
}
```

Example payload: unsupported\_auth\_scheme (Sent as HTTP basic, which v3 does not accept)

```json
{
  "error": {
    "code": "unsupported_auth_scheme",
    "message": "Send the credential as `Authorization: Bearer <token>`; v3 does not accept HTTP basic"
  },
  "meta": {
    "request_id": "abc123"
  }
}
```

Example payload: credential\_in\_query (Sent as the \`auth\_token\` query parameter)

```json
{
  "error": {
    "code": "credential_in_query",
    "message": "Credentials must be sent in the Authorization header"
  },
  "meta": {
    "request_id": "abc123"
  }
}
```

Response schema

| Field | Type | Description |
| - | - | - |
| `error` required | object | |
| `error.code` required | string | Machine-readable code. Branch on this, not the message. Allowed values: `unauthorized`, `unsupported_auth_scheme`, `credential_in_query`, `access_denied`, `insufficient_scope`, `requires_user_token`, `project_restricted`, `account_inactive`, `account_parked`, `feature_unavailable`, `not_found`, `validation_error`, `delete_failed`, `limit_reached`, `rate_limit_exceeded`, `concurrent_request`, `streams_provisioning`, `ingestion_key_not_accepted`, `maintenance_mode`, `invalid_parameter`, `forbidden_attributes`, `service_unavailable`, `ambiguous_account`, `fault_merged`. |
| `error.message` required | string | Human-readable explanation. |
| `error.details` | array\<object> \| object | A list of `{field, message}` on `validation_error` and `invalid_parameter`, and on `feature_unavailable` or `limit_reached` when one field caused the refusal; `{required_scope, token_scopes}` on `insufficient_scope`; `{merged_into, location}` on `fault_merged`. Absent when there's nothing to add. |
| `meta` | object | |
| `meta.request_id` | string | Unique identifier for the request, for correlating with support. |

### 403 Forbidden

The credential isn’t allowed to do this. `error.code` says why. An account or project the credential doesn’t cover is 404 `not_found`, not 403.

Example payload: access\_denied (The credential isn't allowed to do this to this record)

```json
{
  "error": {
    "code": "access_denied",
    "message": "Access denied"
  },
  "meta": {
    "request_id": "abc123"
  }
}
```

Example payload: insufficient\_scope (The credential lacks the permission this endpoint requires)

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "Insufficient scope",
    "details": {
      "required_scope": "faults:write",
      "token_scopes": [
        "faults:read",
        "insights:read"
      ]
    }
  },
  "meta": {
    "request_id": "abc123"
  }
}
```

Example payload: requires\_user\_token (The endpoint records who acted, and an account token has nobody)

```json
{
  "error": {
    "code": "requires_user_token",
    "message": "This endpoint records the person who acted, so it requires a user credential rather than an account token"
  },
  "meta": {
    "request_id": "abc123"
  }
}
```

Example payload: project\_restricted (A project-restricted credential cannot create a project)

```json
{
  "error": {
    "code": "project_restricted",
    "message": "Project-restricted tokens cannot create projects"
  },
  "meta": {
    "request_id": "abc123"
  }
}
```

Response schema

| Field | Type | Description |
| - | - | - |
| `error` required | object | |
| `error.code` required | string | Machine-readable code. Branch on this, not the message. Allowed values: `unauthorized`, `unsupported_auth_scheme`, `credential_in_query`, `access_denied`, `insufficient_scope`, `requires_user_token`, `project_restricted`, `account_inactive`, `account_parked`, `feature_unavailable`, `not_found`, `validation_error`, `delete_failed`, `limit_reached`, `rate_limit_exceeded`, `concurrent_request`, `streams_provisioning`, `ingestion_key_not_accepted`, `maintenance_mode`, `invalid_parameter`, `forbidden_attributes`, `service_unavailable`, `ambiguous_account`, `fault_merged`. |
| `error.message` required | string | Human-readable explanation. |
| `error.details` | array\<object> \| object | A list of `{field, message}` on `validation_error` and `invalid_parameter`, and on `feature_unavailable` or `limit_reached` when one field caused the refusal; `{required_scope, token_scopes}` on `insufficient_scope`; `{merged_into, location}` on `fault_merged`. Absent when there's nothing to add. |
| `meta` | object | |
| `meta.request_id` | string | Unique identifier for the request, for correlating with support. |

### 404 Not Found

Resource not found

Example payload

```json
{
  "error": {
    "code": "not_found",
    "message": "Resource not found"
  },
  "meta": {
    "request_id": "abc123"
  }
}
```

Response schema

| Field | Type | Description |
| - | - | - |
| `error` required | object | |
| `error.code` required | string | Machine-readable code. Branch on this, not the message. Allowed values: `unauthorized`, `unsupported_auth_scheme`, `credential_in_query`, `access_denied`, `insufficient_scope`, `requires_user_token`, `project_restricted`, `account_inactive`, `account_parked`, `feature_unavailable`, `not_found`, `validation_error`, `delete_failed`, `limit_reached`, `rate_limit_exceeded`, `concurrent_request`, `streams_provisioning`, `ingestion_key_not_accepted`, `maintenance_mode`, `invalid_parameter`, `forbidden_attributes`, `service_unavailable`, `ambiguous_account`, `fault_merged`. |
| `error.message` required | string | Human-readable explanation. |
| `error.details` | array\<object> \| object | A list of `{field, message}` on `validation_error` and `invalid_parameter`, and on `feature_unavailable` or `limit_reached` when one field caused the refusal; `{required_scope, token_scopes}` on `insufficient_scope`; `{merged_into, location}` on `fault_merged`. Absent when there's nothing to add. |
| `meta` | object | |
| `meta.request_id` | string | Unique identifier for the request, for correlating with support. |

### 422 Unprocessable Content

Validation error

Example payload

```json
{
  "error": {
    "code": "validation_error",
    "message": "Name can't be blank",
    "details": [
      {
        "field": "name",
        "message": "can't be blank"
      }
    ]
  },
  "meta": {
    "request_id": "abc123"
  }
}
```

Response schema

| Field | Type | Description |
| - | - | - |
| `error` required | object | |
| `error.code` required | string | Machine-readable code. Branch on this, not the message. Allowed values: `unauthorized`, `unsupported_auth_scheme`, `credential_in_query`, `access_denied`, `insufficient_scope`, `requires_user_token`, `project_restricted`, `account_inactive`, `account_parked`, `feature_unavailable`, `not_found`, `validation_error`, `delete_failed`, `limit_reached`, `rate_limit_exceeded`, `concurrent_request`, `streams_provisioning`, `ingestion_key_not_accepted`, `maintenance_mode`, `invalid_parameter`, `forbidden_attributes`, `service_unavailable`, `ambiguous_account`, `fault_merged`. |
| `error.message` required | string | Human-readable explanation. |
| `error.details` | array\<object> \| object | A list of `{field, message}` on `validation_error` and `invalid_parameter`, and on `feature_unavailable` or `limit_reached` when one field caused the refusal; `{required_scope, token_scopes}` on `insufficient_scope`; `{merged_into, location}` on `fault_merged`. Absent when there's nothing to add. |
| `meta` | object | |
| `meta.request_id` | string | Unique identifier for the request, for correlating with support. |

---

## Try Honeybadger for FREE

Intelligent logging, error tracking, and Just Enough APM™ in one dev-friendly platform. Find and fix problems before users notice.

[Start free trial](https://app.honeybadger.io/users/sign_up)

[See plans and pricing](https://www.honeybadger.io/plans/)
