# triggers

> **Part of**: [Admin API reference](admin_api.md)


[Run in Postman](https://www.postman.com/cloudinaryteam/workspace/programmable-media/folder/16080251-29060527-94bb-4ce5-8895-a98a4ba1fa3c?ctx=documentation) | [Learn more about running Postman collections](using_cloudinary_postman_collections)

Enables you to manage event triggers and notifications within your product environment. Your product environment supports triggers up to a maximum determined by multiplying the number of unique event types by the limit of 30 notification URLs. Each `trigger` pairs a single [event type](#event_types_table) with one notification URL.

> **NOTE**:
>
> You can manage webhook notifications via the [Webhook Notifications](https://console.cloudinary.com/app/settings/webhooks) page of the Console Settings. <p>Because a `trigger` consists of a single triggering event paired with a single notification URL, whereas in the Console each notification URL is linked to all configured **Notification Types** (triggering events), programmatically creating a trigger reflects in the Console by either generating a new notification URL with a single **Notification Type** or appending a new **Notification Type** to an existing URL's list of notifications. </p><p>For more information, see [Managing webhook notifications from the Console](notifications#managing_webhook_notifications_from_the_console).</p>

Method | Description
---|---
GET /triggers | [Lists all triggers.](#get_triggers) 
POST /triggers | [Creates a new trigger.](#create_a_trigger)
PUT /triggers/:id | [Updates a trigger.](#update_a_trigger)
POST /triggers/:id/test | [Tests a trigger's filter against sample data.](#test_a_trigger_filter)
DELETE /triggers/:id | [Deletes a trigger.](#delete_a_trigger)

> **NOTE**: This endpoint isn't currently supported by SDKs.

---

### Get triggers

Lists the triggers configured for your product environment. 

The response is an array of `triggers` objects and a `total` count (after any optional `event_type` filter). Each object describes one trigger; `filter` and `filter_language` are present only when that trigger has a filter configured to narrow when the webhook fires to a specific group of assets.

#### Syntax
`GET /triggers`

#### Optional parameters
Parameter | Type | Description
---|---|---
`event_type` | String | Filters and retrieves triggers for a specific [event_type](#event_type).

#### Example
List all triggers associated with the "upload" `event_type`:

```multi

|curl
curl 'https://<API_KEY>:<API_SECRET>@api.cloudinary.com/v1_1/<CLOUD_NAME>/triggers?event_type=upload'
```

#### Sample response
```json
{
  "triggers": [
    {
      "id": "f8a3c9012d4e5f6789ab01cd34ef56ab",
      "product_environment_id": "a1b2c3d4e5f67081928394a5b6c7d8e",
      "uri_type": "webhook",
      "uri": "https://example.com/webhook",
      "event_type": "upload",
      "additive": false,
      "created_at": "2026-01-21T11:57:37Z",
      "updated_at": "2026-01-21T11:57:37Z",
      "auth_scheme": "default"
    },
    {
      "id": "b7e6d5c4b3a291807263544556677889aa00bbccddeeff0011223344556677",
      "product_environment_id": "a1b2c3d4e5f67081928394a5b6c7d8e",
      "uri_type": "webhook",
      "uri": "https://example.com/webhook",
      "event_type": "delete",
      "additive": true,
      "created_at": "2026-05-06T11:07:00Z",
      "updated_at": "2026-05-06T11:07:00Z",
      "filter": {
        "and": [
          { "==": [{ "var": "resource_type" }, "image"] },
          { "startsWith": [{ "var": "folder" }, "products/campaigns/"] }
        ]
      },
      "filter_language": "jsonlogic",
      "auth_scheme": "default"
    }
  ],
  "total": 2
}
```

> **NOTES**:
>
> * Trigger responses include `auth_scheme`, which selects the signing headers Cloudinary attaches to webhook deliveries for that trigger. See [**Per-trigger webhook signing**](notifications#trigger_auth_scheme) (`auth_scheme`) for values and headers.

> * For triggers that have a `filter` configured, responses also include `filter_language` (currently always `jsonlogic`). See [**JSONLogic filters for triggers**](#trigger_jsonlogic_filters).

> * Optionally set **`payload_template`** (Mustache) on create or update to send a **custom JSON body** for webhook notifications. See [**Custom webhook payload templates**](notifications#trigger_payload_templates).

---

### Create a trigger

Creates a new trigger. Your product environment supports triggers up to a maximum determined by multiplying the number of unique event types by the limit of 30 notification URLs.

#### Syntax
`POST /triggers`

#### Required parameters
| Parameter | Type | Description |
|---|---|---|
| uri | String | The URL that will receive the notification response.<a class="anchor" name="event_type"> |
| event_type | String | The type of event that will trigger the notification response.<p>**Possible values:** See the [table](#event_types_table).</p>

#### Optional parameters
| Parameter | Type | Description |
|---|---|---|
| additive | Boolean | When `true`, this trigger still fires when the Upload API call or upload preset supplies an explicit [`notification_url`](notifications#upload_api_notifications) for the same `event_type` (in addition to that URL). Default: `false`. See [Notification URLs and global triggers](notifications#notification_urls_and_global_triggers). |
| filter | Object | [JSONLogic](https://jsonlogic.com/) expression evaluated against the notification payload at send time. If omitted or empty, no filter is applied. |
| auth_scheme | String | One of `default`, `legacy_hmac`, or `eddsa_v2`. Controls which webhook signature headers are sent for this trigger. Default: `default`. See [**Per-trigger webhook signing**](notifications#trigger_auth_scheme). |
| payload_template | Object or String | Optional. Defines a **[Mustache](https://mustache.github.io/)**-templated JSON object for custom webhook bodies. Accept a JSON object or a JSON string that parses to an object. Omit for default notification bodies. See [**Custom webhook payload templates**](notifications#trigger_payload_templates). |

<a class="anchor" name="trigger_jsonlogic_filters"></a>
##### JSONLogic filters for triggers

The `filter` value uses [JSONLogic](https://jsonlogic.com/) rules. For the full list of built-in operators and patterns, see [Supported operations](https://jsonlogic.com/operations.html). You can also try rules interactively in the [JSONLogic playground](https://jsonlogic.com/play.html).

When `filter` is set, the notification is sent only if the expression evaluates to **true** for the payload fields available for the event (using JSONLogic rules for true and false).

**Supported payload fields include:**

* `resource_type`: Asset resource type, including `image`, `video`, and `raw`.
* `type`: Delivery type, including `upload`, `private`, and `authenticated`.
* `public_id`: Full public ID, including any slashes.
* `asset_id`: Immutable unique asset identifier.
* `folder`: The asset’s folder within the product environment. In dynamic-folder environments this is the Media Library `asset_folder`. In product environments using the legacy [fixed folder mode](https://cloudinary.com/documentation/folder_modes), it reflects the folder portion of the`public_id`.
* `format`: File format/extension, including `jpg`, `png`, `mp4`.
* `bytes`: File size in bytes.
* `width`, `height`: Asset dimensions (when applicable).
  
**For folder-related events** (such as `create_folder`, `delete_folder`, or `move_or_rename_asset_folder`), the filter can also reference:

* `folder_path`: Full folder hierarchy for the containing folder and all its parents (for example, **products**->**campaigns**->**winter** as shown in the Media Library folder tree). 
* `folder_name`: The folder’s own name (the last segment of the hierarchy in `folder_path`, for example, **winter**). 

> **NOTE**:
>
> :title=Folder modes

> * For product environments using [dynamic folder mode](folder_modes), `folder_path` and `folder_name` reflect the Media Library folder hierarchy and labels, don't affect the asset's `public_id` path, and support the `move_or_rename_asset_folder` event type.

> * For product environments using the legacy [fixed folder mode](dam_folder_modes), `folder_path` and `folder_name` match the folder portion of the `public_id`, for example a `folder_path` such as `products/campaigns/winter` and `folder_name` `winter`.

**For notifications that apply to one asset at a time**, you can also reference `tags`, `context` (contextual metadata), and `metadata` (structured metadata) in the filter when those values are present for that asset. For bulk notifications (for example bulk delete), `tags`, `context`, and `metadata` aren't included when the filter runs; other supported fields are still evaluated when present in the payload.

The following **custom JSONLogic operators** are supported in addition to the standard operators: `startsWith`, `endsWith`, `contains`, and `matches` (regular expression).

#### event_type possible values
> **NOTE**:
>
> The **Value** corresponds to the **Notification type(s)** in the [Webhook Notifications](https://console.cloudinary.com/app/settings/webhooks) page of the Console Settings and the `notification_type` in the response.

{table:class=small-1stcol-regfont}Value | Description | Source
---|---|---
`all` | Any of the event types. |
`access_control_changed` | Access control for an asset is changed. | - [resources](admin_api#update_details_of_an_existing_resource) method of the Admin API - Console UI operation
`bulk_refresh_auto_fetch` | Refresh of fetched assets is completed. | - For more information, see [Refreshing fetched assets (images only)](fetch_remote_images#deleting_and_refreshing_fetched_assets)
`create_folder` | A new folder is created. | - [create_folder](admin_api#create_folder) method of the Admin API  - Console UI operation
`delete` | An asset is deleted. | - [destroy](image_upload_api_reference#destroy) method of the Upload API - [resources](admin_api#update_details_of_an_existing_resource) method of the Admin API - Console UI operation
`delete_by_token` | An asset is deleted using a deletion token. | - [delete_by_token](client_side_uploading#deleting_client_side_uploaded_assets) method of the jQuery SDK
`delete_folder` | A folder is deleted. | - [delete_folder](admin_api#delete_folder) method of the Admin API call  - Console UI operation
`eager` | An eager transformation is requested and completed. | - [eager] (eager_and_incoming_transformations#eager_transformations) transformation included in an [upload](image_upload_api_reference#upload) method API call
`error` | An error occurs during upload. | - [upload](image_upload_api_reference#upload) API call  - Console UI operation 
`explode` | Derived images are created from a multi-page file. | - [explode](image_upload_api_reference#explode) method of the upload API
`generate_archive` | An archive file is generated. | - [generate_archive](image_upload_api_reference#generate_archive) method of the Admin API
`info` | Actions that involve gathering information about an asset (such as background removal and auto-tagging) are completed. | - Add-ons applied during a call to the [upload](image_upload_api_reference#upload) method  - Console UI operation
`invalidate_custom_cdn` | Cached copies of an asset are invalidated from a customer owned CDN. | - [upload](image_upload_api_reference#upload) API call |
`moderation` | An asset is approved or rejected. | - Moderations applied during a call to the [upload](image_upload_api_reference#upload) method - Console UI operation
`moderation_summary` | An asset is marked for multiple moderations is approved or rejected. | - Multiple moderations applied during a call to the [upload](image_upload_api_reference#upload) method  - Console UI operation
`move` | An asset is moved between folders (not relevant if your product environment is using the legacy fixed folder mode). | - [resources](admin_api#update_details_of_an_existing_resource) method of the Admin API  - Console UI operation
`move_or_rename_asset_folder` | A folder is moved to a different location within the folder hierarchy or renamed (not relevant if your product environment is using the legacy fixed folder mode). | - Console UI operation
`multi` | Animated image, video or PDF is created from multiple assets. | - [multi](image_upload_api_reference#multi) method of the upload API
`proof_status_changed` | The status of a proof changes during the approval flow. | - Console UI operation
`publish` | A public link is generated for sharing an asset via a dedicated website. | - Console UI operation
`rename` | An asset is renamed (or, if your product environment is using the legacy fixed folder mode, moved to a different folder). | - [rename](image_upload_api_reference#rename) method of the Upload API - [resource](admin_api#update_details_of_an_existing_resource) method of the Admin API (fixed folder mode only)  - Console UI operation 
`report` | A last access report is created.| - [resources last access reports](admin_api#resources_last_access_reports)
`related_assets` | Asset relationships are added or removed. | - [add_related_assets](admin_api#add_related_assets) method of the Admin API - [delete_related_assets](admin_api#delete_related_assets) method of the Admin API - Console UI operation
`resource_context_changed` | Contextual metadata is changed. | - [resource](admin_api#update_details_of_an_existing_resource) method of the Admin API  - Console UI operation 
`resource_display_name_changed` | An asset's display name is changed (not relevant if your product environment is using the legacy fixed folder mode). | - [resource](admin_api#update_details_of_an_existing_resource) method of the Admin API  - Console UI operation 
`resource_metadata_changed` | Structural metadata is changed. | - [resource](admin_api#update_details_of_an_existing_resource) method of the Admin API  - Console UI operation
`resource_tags_changed` | Tags are changed. | - [resource](admin_api#update_details_of_an_existing_resource) method of the Admin API  - Console UI operation
`restore_asset_version` | A previous version of an asset is restored within the Media Library. | - Console UI operation
`upload` | An asset is uploaded. | - [upload](image_upload_api_reference#upload) API call - Console UI operation

> **NOTE**: The response for the `explicit` method is sent to the notification URL that handles the action specified in the call.

#### Example
##### 1. URI and event type only

Set up `https://mysite.example.com/my_notification_endpoint` to receive a notification whenever an **`upload`** completes:

```multi

|curl
curl 'https://<API_KEY>:<API_SECRET>@api.cloudinary.com/v1_1/<CLOUD_NAME>/triggers' \
--header 'Content-Type: application/json' \
--data '{
    "uri": "https://mysite.example.com/my_notification_endpoint",
    "event_type": "upload"
}'

```

##### Sample response
The response body returns the created trigger, including the fields you set and any server-side defaults (shape is the same as each object in the [Get triggers sample response](#get_triggers_sample_response)):

```json
{
  "id": "f8a3c9012d4e5f6789ab01cd34ef56ab",
  "product_environment_id": "a1b2c3d4e5f67081928394a5b6c7d8e",
  "uri_type": "webhook",
  "uri": "https://mysite.example.com/my_notification_endpoint",
  "event_type": "upload",
  "additive": false,
  "created_at": "2026-05-06T12:00:00Z",
  "updated_at": "2026-05-06T12:00:00Z",
  "auth_scheme": "default"
}
```

##### 2. JSONLogic filter and additive trigger

Receive **`upload`** notifications only for **image** assets whose folder path starts with `products/campaigns/`. This example sets **`additive`**: `true` so the trigger still runs when an Upload API call includes **`notification_url`** ([Notification URLs and global triggers](notifications#notification_urls_and_global_triggers)):

```multi

|curl
curl 'https://<API_KEY>:<API_SECRET>@api.cloudinary.com/v1_1/<CLOUD_NAME>/triggers' \
--header 'Content-Type: application/json' \
--data '{
    "uri": "https://mysite.example.com/my_notification_endpoint",
    "event_type": "upload",
    "additive": true,
    "filter": {
      "and": [
        { "==": [{ "var": "resource_type" }, "image"] },
        { "startsWith": [{ "var": "folder" }, "products/campaigns/"] }
      ]
    }
}'

```

##### Sample response
```json
{
  "id": "b7e6d5c4b3a291807263544556677889aa00bbccddeeff0011223344556677",
  "product_environment_id": "a1b2c3d4e5f67081928394a5b6c7d8e",
  "uri_type": "webhook",
  "uri": "https://mysite.example.com/my_notification_endpoint",
  "event_type": "upload",
  "additive": true,
  "created_at": "2026-05-06T12:01:00Z",
  "updated_at": "2026-05-06T12:01:00Z",
  "filter": {
    "and": [
      { "==": [{ "var": "resource_type" }, "image"] },
      { "startsWith": [{ "var": "folder" }, "products/campaigns/"] }
    ]
  },
  "filter_language": "jsonlogic",
  "auth_scheme": "default"
}
```

##### 3. Custom payload template and authentication scheme

Receive **`upload`** webhooks with a **Mustache** JSON body and **EdDSA v2** signing only (no legacy HMAC header). For Mustache namespaces and header behavior, see [**Custom webhook payload templates**](notifications#trigger_payload_templates) and [**Per-trigger webhook signing**](notifications#trigger_auth_scheme).

```multi

|curl
curl 'https://<API_KEY>:<API_SECRET>@api.cloudinary.com/v1_1/<CLOUD_NAME>/triggers' \
--header 'Content-Type: application/json' \
--data '{
    "uri": "https://mysite.example.com/my_notification_endpoint",
    "event_type": "upload",
    "auth_scheme": "eddsa_v2",
    "payload_template": {
        "event": "{{event.type}}",
        "asset_id": "{{asset.id}}",
        "public_id": "{{asset.public_id}}",
        "dimensions": {
            "width": "{{asset.width}}",
            "height": "{{asset.height}}"
        },
        "received_at": "{{event.timestamp}}"
    }
}'

```

##### Sample response
```json
{
  "id": "c1d2e3f40506070809101112131415161718191a1b1c1d1e1f202122",
  "product_environment_id": "a1b2c3d4e5f67081928394a5b6c7d8e",
  "uri_type": "webhook",
  "uri": "https://mysite.example.com/my_notification_endpoint",
  "event_type": "upload",
  "additive": false,
  "created_at": "2026-05-07T14:00:00Z",
  "updated_at": "2026-05-07T14:00:00Z",
  "payload_template": {
    "event": "{{event.type}}",
    "asset_id": "{{asset.id}}",
    "public_id": "{{asset.public_id}}",
    "dimensions": {
      "width": "{{asset.width}}",
      "height": "{{asset.height}}"
    },
    "received_at": "{{event.timestamp}}"
  },
  "auth_scheme": "eddsa_v2"
}
```

---

### Update a trigger

Updates a notification URL for a trigger. 

> **NOTE**: You can't update the `event_type` for a trigger. If you want to update an `event_type` for a specific notification URL, delete the relevant trigger and then create a new one.

#### Syntax
`PUT /triggers/:id`

#### Required parameters
| Parameter | Type | Description |
|---|---|---|
| id | String | Identifies the trigger to update; same value as the **`id`** property on trigger objects from [**Create a trigger**](#create_a_trigger_syntax) or [**Get triggers**](#get_triggers_syntax) responses. |

#### Optional parameters
| Parameter | Type | Description |
|---|---|---|
| new_uri | String | The updated URL that will receive the notification response. |
| additive | Boolean | When `true`, this trigger still fires when the Upload API call or upload preset supplies an explicit [`notification_url`](notifications#upload_api_notifications) for the same `event_type` (in addition to that URL). Default: `false`. See [Notification URLs and global triggers](notifications#notification_urls_and_global_triggers). |
| filter | Object | [JSONLogic](https://jsonlogic.com/) expression evaluated against the notification payload at send time. If omitted or empty, no filter is applied. |
| auth_scheme | String | Same values as [**create_a_trigger optional parameters**](#create_a_trigger_optional_parameters). See [**Per-trigger webhook signing**](notifications#trigger_auth_scheme). |
| payload_template | Object or String | Same as [**create_a_trigger optional parameters**](#create_a_trigger_optional_parameters). See [**Custom webhook payload templates**](notifications#trigger_payload_templates). |

#### Example
Update only the notification URL for trigger ID `1ajkfl2389740vml` using multipart form parameters:

```multi

|curl
curl --request PUT 'https://<API_KEY>:<API_SECRET>@api.cloudinary.com/v1_1/<CLOUD_NAME>/triggers/1ajkfl2389740vml' \
--form 'new_uri="https://mysite.example.com/my_new_notification_endpoint"'

```

Update `additive`, `filter`, or other JSON-friendly fields using a JSON body:

```multi

|curl
curl --request PUT 'https://<API_KEY>:<API_SECRET>@api.cloudinary.com/v1_1/<CLOUD_NAME>/triggers/1ajkfl2389740vml' \
--header 'Content-Type: application/json' \
--data '{
    "new_uri": "https://mysite.example.com/my_new_notification_endpoint",
    "additive": true,
    "filter": {"==": [{"var": "resource_type"}, "image"]}
}'

```

Update **`payload_template`** and **`auth_scheme`** on an existing trigger (JSON body):

```multi

|curl
curl --request PUT 'https://<API_KEY>:<API_SECRET>@api.cloudinary.com/v1_1/<CLOUD_NAME>/triggers/1ajkfl2389740vml' \
--header 'Content-Type: application/json' \
--data '{
    "auth_scheme": "default",
    "payload_template": {
        "kind": "{{event.type}}",
        "ref": "{{asset.public_id}}",
        "meta": {
            "w": "{{asset.width}}",
            "h": "{{asset.height}}"
        }
    }
}'

```

#### Sample response
```javascript
{
  "message" : "ok"
}

```

---



### Test a trigger's filter

Runs the trigger’s stored **[JSONLogic filter](#trigger_jsonlogic_filters)** against **`sample_data`** (the field values you supply) and returns whether it would pass, without sending a webhook. Use this when you already have a trigger ID and want to confirm whether plausible payloads would match the stored filter.

#### Syntax
`POST /triggers/:id/test`

#### Required parameters
| Parameter | Type | Description |
|---|---|---|
| id | String | Identifies the trigger whose filter you are testing; same value as the **`id`** property on trigger objects from [**Create a trigger**](#create_a_trigger_syntax) or [**Get triggers**](#get_triggers_syntax) responses. |
| sample_data | Object | Field values representing a sample webhook payload fragment to evaluate. Use **[supported payload fields](#trigger_jsonlogic_filters)** for the trigger's event type—for example **`resource_type`**, **`folder`**, **`type`** (delivery type), and **`format`**. |

#### Sample response fields
| Field | Type | Description |
|---|---|---|
| trigger_id | String | The tested trigger identifier. |
| filter_present | Boolean | `true` if this trigger has a filter configured; `false` if it doesn't. |
| filter_result | Boolean | If **`filter_present`** is **`false`**, this is always **`true`**. Otherwise, **`true`** if the **`sample_data`** satisfies the stored JSONLogic rule, or **`false`** if it does not. |

#### Example
Test trigger **`xyzxy123123`**’s filter to see if it has a match for an upload-style payload with **`resource_type`**: **`image`**, **`folder`**: **`sample`**, **`type`**: **`upload`**, **`format`**: **`jpg`**.

```multi

|curl
curl --request POST 'https://<API_KEY>:<API_SECRET>@api.cloudinary.com/v1_1/<CLOUD_NAME>/triggers/xyzxy123123/test' \
--header 'Content-Type: application/json' \
--data '{
  "sample_data": {
    "resource_type": "image",
    "folder": "sample",
    "type": "upload",
    "format": "jpg"
  }
}'

```

#### Sample response
```json
{
  "trigger_id": "xyzxy123123",
  "filter_present": true,
  "filter_result": true
}
```

---

### Delete a trigger

Deletes a trigger.

#### Syntax
`DELETE /triggers/:id`

#### Required parameters
| Parameter | Type | Description |
|---|---|---|
| id | String | Identifies the trigger to delete; same value as the **`id`** property on trigger objects from [**Create a trigger**](#create_a_trigger_syntax) or [**Get triggers**](#get_triggers_syntax) responses. |

#### Example
Delete the trigger with ID `1ajkfl2389740vml`:

```multi

|curl
curl --request DELETE 'https://<API_KEY>:<API_SECRET>@api.cloudinary.com/v1_1/<CLOUD_NAME>/triggers/1ajkfl2389740vml'

```

#### Sample response
```javascript
{
  "message" : "ok"
}

```
