# REST API Reference

## Getting Started

The Hookdeck REST API allows you to set up connections, retrieve events, and perform actions programmatically.

### Get an API key

You'll need to include an API key in every API request. If you do not yet have a Hookdeck account, please [sign up](https://dashboard.hookdeck.com/signup) for a free account. Your API key is located in your [project settings](https://dashboard.hookdeck.com/settings/project/secrets).

To include your API key in requests, use either Bearer Token Authentication or Basic Authentication.

| Method | Procedure |
| --- | --- |
| Bearer Token Authentication | Include the header `Authorization: Bearer $API_KEY`, replacing `$API_KEY` with your personal key |
| Basic Authentication | Set the username as your API key, and supply an empty password |

> Basic Authentication is deprecated and remains supported for backwards compatibility.

```bash
curl "https://api.hookdeck.com/2025-07-01/events"
  -H "Content-Type: application/json"
  -H "Authorization: Bearer $API_KEY"

```

### Create your first connection

As an example let's create a connection between a source and a destination. This will allow you to start routing events with Hookdeck.

#### Minimum parameters

| Parameter | Type | Description |
| --- | --- | --- |
| name | `string` | Name of the connection to create |
| source.name | `string` | Name of the source to create |
| destination.name | `string` | Name of the destination to create |
| destination.config.url | `string` | HTTP endpoint of the destination |

> By default, the source is assumed to be of type `WEBHOOK` and the destination of type `HTTP`.

View the full specification for the connection object [here](/docs/api#connection-object).

`POST /2025-07-01/connections`

**Request body example**
```json
{
  "name": "shopify-my-api",
  "source": {
    "name": "shopify"
  },
  "destination": {
    "name": "my-api",
    "config": {
      "url": "https://mock.hookdeck.com/example"
    }
  }
}
```

**Response example**
```json
{
  "id": "web_nbbweTiOtzsm",
  "team_id": "tm_lbhzBKgFOUnB",
  "updated_at": "2026-01-14T13:36:41.582Z",
  "created_at": "2026-01-14T13:36:41.595Z",
  "paused_at": null,
  "name": "shopify-my-api",
  "rules": [],
  "description": null,
  "destination": {
    "id": "des_TU9ioCk5EHUU",
    "team_id": "tm_lbhzBKgFOUnB",
    "updated_at": "2026-01-14T13:36:41.584Z",
    "created_at": "2026-01-14T13:35:55.263Z",
    "name": "my-api",
    "description": null,
    "type": "HTTP",
    "config": {
      "url": "https://mock.hookdeck.com/example",
      "rate_limit": null,
      "rate_limit_period": "second",
      "http_method": null,
      "path_forwarding_disabled": false,
      "auth": {},
      "auth_type": "HOOKDECK_SIGNATURE"
    },
    "disabled_at": null
  },
  "source": {
    "id": "src_qa5626p6y5o79b",
    "team_id": "tm_lbhzBKgFOUnB",
    "updated_at": "2026-01-14T13:36:41.583Z",
    "created_at": "2026-01-14T13:35:55.226Z",
    "name": "shopify",
    "description": null,
    "type": "WEBHOOK",
    "config": {
      "allowed_http_methods": [
        "POST",
        "PUT",
        "PATCH",
        "DELETE"
      ],
      "custom_response": null
    },
    "url": "http://localhost:8787/qa5626p6y5o79b",
    "disabled_at": null,
    "authenticated": false
  },
  "disabled_at": null,
  "full_name": "shopify -> shopify-my-api"
}
```

### Verify your first connection

Verifying the connection lets you know Hookdeck is properly ingesting and processing events from your source.

Copy the unique Hookdeck URL and paste it into your API provider's HTTP URL field. Test the connection by triggering a request on your source. As soon Hookdeck receives your first request, it'll appear in your [dashboard](https://dashboard.hookdeck.com/events).

Congratulations! Your request & events can now be viewed, inspected, filtered, sorted, retried, and so much more using Hookdeck.

```json
{
  "id": "web_xxxxxxxxxxxxxxx",
  "source": {
    "url": "https://hkdk.events/xxxxxxxxxxxxxxx",
    [...]
  },
  [...]
}

```

## Authentication

> Scope: This authentication method applies to Hookdeck REST API endpoints (e.g., `/events`, `/requests`, `/sources`) and Hookdeck Publish API endpoints (`https://hkdk.events/v1/publish`). For authentication when sending requests to a Source URL (e.g., `https://hkdk.events/src_123...`), see [Source Authentication](/docs/authentication#source-authentication).

Your API key is located in your [project settings](https://dashboard.hookdeck.com/settings/project/secrets), and must be included in every API request. Use either Bearer Token Authentication or Basic Authentication.

| Method | Procedure |
| --- | --- |
| Bearer Token Authentication | Include the header `Authorization: Bearer $API_KEY`, replacing `$API_KEY` with your project key |
| Basic Authentication | Set the username as your API key, and supply an empty password |

```bash
curl "https://api.hookdeck.com/2025-07-01/events"
  -H "Content-Type: application/json"
  -H "Authorization: Bearer $API_KEY"

```

## Paging

All `GET` endpoints that retrieve a list of resources are paged using cursor (aka keyset) pagination, which resides in the response body's `pagination` object.

| Parameter | Default | Description |
| --- | --- | --- |
| order_by | `"created_at"` | The sortable key to use (options varies base on the resource ) |
| dir | `"desc"` | The direction to sort it (`"asc"` or `"desc"`) |
| limit | `100` | The making amount of results returned per query (max: `250`) |
| next | `undefined` | The ID to provide in the query to get the next set of results |
| prev | `undefined` | The ID to provide in the query to get the previous set of results |

Unless you have specified an `order_by` or `dir`, you can omit it from the next or previous set query. You only have to carry them over if you are not using the resource default.

```json
{
  "pagination": {
    "order_by": "created_at",
    "dir": "desc",
    "limit": 100,
    "next": "web_2urj7h9puxk6obro3x",
    "prev": "web_2urj7h9puxk6obuf6i"
  }
}

```

```bash
curl "https://api.hookdeck.com/2025-07-01/connections?next=web_2urj7h9puxk6obro3x"
  -H "Authorization: Basic BASE64_API_TOKEN"

```

```bash
curl "https://api.hookdeck.com/2025-07-01/connections?prev=web_2urj7h9puxk6obuf6i"
  -H "Authorization: Basic BASE64_API_TOKEN"

```

```bash
curl "https://api.hookdeck.com/2025-07-01/connections?order_by=updated_at&dir=asc&next=web_2urj7h9puxk6obro3x"
  -H "Authorization: Basic BASE64_API_TOKEN"

```

## Errors

Hookdeck uses standard [HTTP response codes](/docs/events#status-and-error-codes) to indicate the success or failure of an API request.

| Parameter | Type | Description |
| --- | --- | --- |
| handled | `boolean` | Error was handled by the API and did not resolve in an uncaught exception |
| status | `integer` | HTTP status code for the error |
| message | `string` | Any message associated with the error |
| data | `object` | Any data related to the error, useful for diagnostics |

> In general, codes in the 2xx range indicate success, codes in the 4xx range indicate an error that resulted from the provided information (e.g. a required parameter was missing), and codes in the 5xx range indicate an error. See a more complete list of error codes [here](/docs/events#status-and-error-codes).

```json
{
  "handled": true,
  "status": 422,
  "message": "Connection does not exist or is disabled",
  "data": {
    "id": "web_xxxxxxxxxxx"
  }
}

```

## Rate Limits

The Hookdeck API has a rate limit of 240 request per minute, per API key. [Contact us](/contact) if you need your rate limit increased.

```http
Retry-After: Seconds before next request can be made
X-RateLimit-Limit: Request per minute limit for the API key
X-RateLimit-Remaining: Remaining request for the rate limit period
X-RateLimit-Reset: ISO timestamp of the next rate limit period reset

```

## Query Formatting

### Arrays

Arrays in query parameters are indicated by a `[]` appended to their type, like `string[]`.

For example: `?item[1]=hello&item[2]=world` is parsed as `["hello", "world"]`

### Date

Dates are expected in ISO format.

For example: `2021-01-21T20:16:28Z` or `2021-01-21`

### JSON

Some query parameters take JSON as input. The JSON should be stringified and URL encoded.

For example: `?body=%7B%0A%20%20"hello"%3A%20"world"%0A%7D` is parsed as `{ "hello": "world" }`

### Operators

Most `GET` endpoints that retrieve a list of resources support operators as part of the request query.

For example: `?number[gte]=1&number[lte]=10`

| Operator | Supported Types | Description |
| --- | --- | --- |
| gte | `date` `number` | Greater than or equal to |
| gt | `date` `number` | Greater than |
| lte | `date` `number` | Lesser than or equal to |
| lt | `date` `number` | Lesser than |
| any | `date` `number` `string` | Not `null` |
| contains | `string` | Contains |

## OpenAPI Schema

Our [OpenAPI](https://www.openapis.org/) schema is available at https://api.hookdeck.com/2025-07-01/openapi.

OpenAPI schemas can be used to generate SDKs for your language of choice and work with various tools made for OpenAPI definitions such as importing into [Postman](https://www.postman.com/).

## Changelog

When backwards-incompatible changes are made to the API, a new, dated version is released. The latest version is 2025-07-01.

The API version can be set in the base path of any endpoint, such as https://api.hookdeck.com/2025-07-01/sources. Otherwise the API defaults to the oldest supported version.

The backwards-incompatible changes for each version are listed below. Backwards-compatible changes don’t need a new API version and do not appear in this list.

> Dated versions remain officially supported for up to 1 year after the date of release. For instance 2023-07-01 will be officially supported until 2024-07-01.

### 2025-07-01

#### Transformation and Filter Order

Transformations and filters are now be ordered via the `rules` property in a [connection](#connections). This allows for greater flexibility in how events are processed.

Prior to this change, transformations always ran before filters. Now, you can control the order of execution by placing transformations before or after filters in the `rules` array.

To preserve existing behavior, ensure that transformation rules are placed before filter rules in the `rules` array.

The `delay` and `retry` rules do not have an order and can be placed anywhere in the `rules` array.

#### Deduplicate Rule

Added support for deduplicating events based on configurable time windows and field matching. The new [DeduplicateRule](#deduplicate-rule) can be configured in a [Connection's](#connections) `rules` array to prevent duplicate events from being delivered to your destination.

The deduplicate rule includes:

* `type`: Set to `"deduplicate"` to enable deduplication
* `window`: Time window in seconds during which events are considered for deduplication
* `include_fields`: Optional array of event fields to include in duplicate detection (if not specified, all fields are considered)
* `exclude_fields`: Optional array of event fields to exclude from duplicate detection

When an event matches a previously seen event within the specified time window, only the first occurrence will be delivered to your destination.

```json
{
  "type": "deduplicate",
  "window": 300,
  "include_fields": ["id", "type", "user_id"]
}

```

#### Metrics API Endpoints

Added seven new metrics endpoints to provide comprehensive analytics and monitoring capabilities for your webhook infrastructure:

* GET /metrics/requests - Retrieve request volume metrics across your sources and destinations
* GET /metrics/events - Get detailed event processing statistics and success rates
* GET /metrics/attempts - Monitor delivery attempt metrics including retry patterns
* GET /metrics/events-by-issue - Analyze event failures grouped by issue type for easier troubleshooting
* GET /metrics/queue-depth - Track queue depth metrics to monitor processing backlogs
* GET /metrics/transformations - Monitor transformation execution performance and success rates
* GET /metrics/events-pending-timeseries - Retrieve time-series data for pending events to identify processing trends

These endpoints provide the data needed to build comprehensive monitoring dashboards and set up alerting for your webhook infrastructure.

#### New Source Types

Added support for five new [Source](#sources) types to expand webhook integration capabilities:

* HOOKDECK_OUTPOST - For Hookdeck Outpost deployments in private networks
* RECURLY - Native integration with Recurly billing platform webhooks
* FUSIONAUTH - Support for FusionAuth identity platform webhooks
* PORTAL - Integration with Portal platform webhooks
* ASANA - Native support for Asana project management webhooks

Each new source type includes pre-configured authentication and validation settings optimized for the respective platform's webhook implementation.

### 2025-01-01

#### Source and Destination Types

Source and Destination Types are now available on the [Source](#sources) and [Destination](#destinations) objects. This introduces the following changes:

* Added `type` property to the [Source](#sources) and [Destination](#destinations) objects, which can be set when creating or updating them.
* Added `config` property to contain all type-dependent configuration options, including authentication methods, custom responses, and HTTP method restrictions. See the [source object](#source-object) for more details on each Type configuration.

Source

* The Source `type` property defaults to `WEBHOOK` and has no required `config` property.
* The `custom_response`, `allowed_http_methods` properties have been moved to the Source to the `config` object for the supported `type`.
* The `verification` has been moved to the `config` object and the `verification.type` property is now `config.auth_type` and the `verification.config` property is just `config.auth`.

Destination

* The Destination `type` property defaults to `HTTP` and requires a `config.url` property.
* The Destination properties `url`, `rate_limit`, `rate_limit_period`, `disabled_path_forwarding` and `http_method` have been moved to the `config` object for the supported `type`.
* The Destination `cli_path` property has been renamed to `path` and has been moved to the `config` object when `type` is `CLI`.
* When `type` is `CLI` the `rate_limit` and `rate_limit_period` properties are not supported.

### 2024-09-01

#### Change to attempts

Attempts no longer store state and are created when the event is delivered rather then when the event is queued for delivery.

Because of the underlying data structure change, the behavior of the API has changed for some endpoint, regardless of versions. While those are not technically breaking changes, they are worth noting:

* The `/attempts` (see: [Retrieve all attempts](#retrieve-all-attempts)) endpoint now only returns attempts with status of `SUCCESFUL` or `FAILED`. This is true regardless of API version.
* The `/events/:id/retry` will always return `null` for the `attempt` property on the response. This is true regardless of API version.

The breaking changes for this version specifically are:

* The `/events/:id/retry` (see: [Retry an event](#retry-an-event)) endpoint previously returned `{ event: Event, attempt: Attempt }` and now only returns the Event object in root of the response.

## API Resources

### Configure

* [Connections](/docs/api/connections.md)
* [Sources](/docs/api/sources.md)
* [Destinations](/docs/api/destinations.md)
* [Issue triggers](/docs/api/issue-triggers.md)
* [Transformations](/docs/api/transformations.md)
* [Notifications](/docs/api/notifications.md)

### Inspect

* [Inspect](/docs/api/inspect.md)
* [Requests](/docs/api/inspect.md#requests)
* [Events](/docs/api/inspect.md#events)
* [Attempts](/docs/api/inspect.md#attempts)
* [Bookmarks](/docs/api/inspect.md#bookmarks)
* [Issues](/docs/api/inspect.md#issues)
* [Metrics](/docs/api/inspect.md#metrics)

### Publish

* [Publish](/docs/api/publish.md)

### Bulk operations

* [Bulk Operations](/docs/api/bulk.md)
* [Bulk retry events](/docs/api/bulk.md#bulk-retry-events)
* [Bulk cancel events](/docs/api/bulk.md#bulk-cancel-events)
* [Bulk ignored events](/docs/api/bulk.md#bulk-ignored-events)
* [Bulk requests](/docs/api/bulk.md#bulk-requests)

### Rules

* [Rules](/docs/api/rules.md)
