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

# Webhook notifications


Cloudinary provides a webhook notification feature for informing your backend about certain actions that have been completed, either via API method call or via user action within the Console UI. When the action is completed, an HTTP POST request is sent to a public notification URL you provide. The payload contains all the results pertinent to that particular action. 

You can use webhook notifications to:

* **Handle asynchronous calls**. By default, Cloudinary's [upload API](image_upload_api_reference) works synchronously. For example, uploaded assets are processed and eager transformations are generated synchronously during an upload API call, which means that the original asset and derived assets are available immediately for delivery and further management. However, in some cases you may need to be notified that an upload has completed, or you may want to process actions asynchronously in the background, especially actions that require a relatively long time to process and require your users to actively wait for the processing to finish.
* **Keep aligned when other users in the system make changes**. It's important to listen for changes made in your system and update accordingly to make sure there aren't any inconsistencies. You can set up code that listens for notifications, and then uses the data to make automatic updates. For example, you can set up a webhook to receive notifications when assets are renamed, and then trigger a search and replace to update the asset name anywhere it exists.
* **Integrate Cloudinary with other platforms**. If you're using Cloudinary assets from within a different platform, listen for changes being made to assets in Cloudinary in order to keep synced. For example, you can set up a structured metadata field to indicate whether assets should be published or unpublished. When you receive a notification within the other platform indicating that this metadata field was changed, trigger the appropriate action in your code. For more information about how to integrate Cloudinary with another platform, see [How to build your own integration](integrating_cloudinary_with_other_platforms).
* **Trigger another operation.** If an action must follow a specific event, you can listen for that event and use it to trigger the action. For example, use the notification that an asset has been uploaded to trigger adding the asset to your catalog, or for [user-generated content](user_generated_content) to handle the result of a moderation check, determining if it's safe to display the image or video.
    > **TIP**:
>
> :title=Examples

>     * The Cloudinary Solutions team took advantage of this option to create an [open-source library](https://github.com/cloudinary-devs/cloudinary-face-rekognition) that can [learn and then auto-tag faces with names](https://aws.amazon.com/blogs/apn/how-to-use-amazon-rekognition-on-cloudinary-to-auto-tag-faces-with-names/) using an Amazon Rekognition lambda function that's triggered by the notification following the upload of a photo to a dedicated 'training' folder in Cloudinary.

>     * The [profile picture sample project](profile_picture_sample_project) demonstrates a UGC use-case showing images moderated on upload and the use of Cloudinary webhooks to check the moderation results.

>     * The [video review sample project](video_review_sample_project) demonstrates a UGC use-case showing videos moderated on upload, the generation of eager transformations, and the use of Cloudinary webhooks to wait for the moderation, eager, auto chaptering and auto transcript notifications. The frontend waits for successful notifications before displaying the video.

## Global notification URLs

You can set one or more global notification URLs in the **Webhook Notifications** page of the [Console Settings](#from_the_console) or [programmatically](#programmatically) using the `triggers` method of the **Admin API**. 

Once you've set up either a single or multiple notification URL(s), Cloudinary automatically sends responses to the appropriate URL address(es) any time a relevant action in the [Console UI](#console_ui_notifications) is performed or a call to a relevant [Cloudinary API method](#api_method_call_notifications) is made.

If you're using a single notification URL, configure it to receive all notifications.  

> **NOTE**:
>
> Any global notification URL defined in the Upload tab (prior to June 2023) is now displayed in the **Webhook Notifications** page and is, by default, designated to receive all types of notifications.

However, adding **multiple notification URLs** enables you to specify which destination receives notifications for each type of action. This level of control makes is easy to trigger flows or sync multiple parts of your ecosystem when integrating Cloudinary with other platforms. It also allows you to:

* Dedicate a separate notification URL to handle actions relevant to each of your workflows. 
* Organize your destinations according to their purpose.
* Spread out the traffic among several endpoints to avoid performance issues.

#### Tips and considerations for adding multiple notification URLs

* Make sure you assign every notification type that you listen for in your code to at least one notification URL. 
* You can optionally set one notification URL to receive all responses as backup. 
* Each notification URL can handle several event types, and conversely the responses for a single notification type can be sent to several notification URLs.

### Managing global notification URLs

You can manage webhook notifications either from the [Webhook Notifications](https://console.cloudinary.com/app/settings/webhooks) page of the Console or using the [triggers](admin_api#triggers) method of the Admin API. You can configure up to 10 notification URLs per product environment.

In the Console, each notification URL is linked to all configured **Notification Types** (triggering events). However, when programmatically managing webhook notifications, you're working with a `trigger` — a single triggering event paired with a single notification URL. As a result, 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.

#### Managing webhook notifications from the Console

To manage multiple notification URLs via the Cloudinary Console, go to the [Webhook Notifications](https://console.cloudinary.com/app/settings/webhooks) Console Settings page. 

By default, when you add a new notification URL, the **Default - All notifications** option is selected as the default type. If you're using a single notification URL, or want to use one of your notification URLs as backup for all events, keep that default behavior.

You can also (or alternatively) add different **Notification URLs**, and specify the Console UI action and/or API method **Notification types** you'd like to receive notification about at each URL. You can configure up to 30 notification URLs per product environment.

In addition, you can select the API key for [verifying](notification_signatures) all your notification signatures. For more information, see [Dedicated API key for webhook notifications](notification_signatures#dedicated_api_key_for_webhook_notifications).

![Webhook notifications UI](https://cloudinary-res.cloudinary.com/image/upload/f_auto/q_auto/bo_1px_solid_grey/v1698334552/docs/webhook_notifications_ui_key_new.png "with_url:false, with_code:false, with_image:true, width:800, thumb: w_800,dpr_2, popup:true")

> **NOTE**:
>
> The **Notification Type** values in the list corresponds with the `notification_type` key that's returned in the notification response.

> **TIP**:
>
> You can also configure a single **Notification URL** for an [upload preset](https://console.cloudinary.com/app/settings/upload/presets) in the **Advanced** tab to receive a notification each time an upload using this preset is completed. For more information on upload presets, see [Managing upload presets using the settings UI](upload_presets#managing_upload_presets_using_the_settings_ui).

#### Managing webhook notifications programmatically

To manage notification URLs programmatically, use the [triggers](admin_api#triggers) method of the [Admin API](#admin_api). Each `trigger` denotes a unique event type linked to its notification URL. 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. 

When an event of the specified type occurs, a response is sent to its corresponding notification URL.

For example, set up the `https://mysite.example.com/my_notification_endpoint` URL to receive a notification whenever an `upload` is completed:

```multi

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

```

> **NOTES**:
>
> * If you want a trigger to receive all notifications, set its `event_type` to `all`.

> * The `event_type` values correspond with the `notification_type` key that's returned in the body of the notification response. For a full list, see [Event types](admin_api#event_types_table).

> * A dedicated API key for verifying all webhook notifications can be set programmatically via the PUT method of the Provisioning API [access key endpoint](provisioning_api#tag/access-keys), available for [Enterprise](https://cloudinary.com/pricing#pricing-enterprise) customers upon [request](https://cloudinary.com/contact?plan=enterprise).

### API method call notifications

When you call certain API methods, a response is sent to the notification URL you configured to listen for that action upon its completion. 

For a full list of possible triggering actions see this [table](admin_api#event_types_table).

For some examples of notification responses from these types of actions, see the [Notification response examples](#notification_response_examples) section.

### Console UI notifications

When a user performs any of the following actions in the Console UI, a response will be sent to the notification URL you configured to listen for that action upon its completion.

* Uploading a new asset.
* Renaming the asset's public ID. 
* Deleting an asset. Deleting a folder that contains assets will also trigger a delete notification for all individual assets in that folder. Note that deleting **empty** folders does not send a notification. 
* Updating an asset's display name. (Not relevant for product environments using the legacy fixed folder mode.)
* Moving an asset between folders changes the `asset_folder` value, and triggers a **move** notification.
  * In the legacy [fixed folder](folder_modes) mode, moving an asset to another folder in the Media Library changes the `public_id` value, and thus triggers a **rename** notification.
* Adding, removing or updating the contextual metadata for an asset.
* Adding, removing or updating the structured metadata for an asset.  
* Adding or removing a tag for an asset. 
* Adding or removing related assets relationships.
* Updating the access control setting for an asset.
* Creating a new asset folder.
* Deleting an asset folder.
* Restoring a previous asset version.
* Making a decision that changes the status of the proof during [proof review](dam_creative_approval_proofs#review_proofs) in one of the stages of the creative approval flow.

For a full list of possible triggering actions see this [table](admin_api#event_types_table).

For some examples of notification responses from these types of operations, see the [Notification response examples](#notification_response_examples) section.

## Notification Payload

When an action that triggers a notification is completed, an HTTP POST request will be sent to the notification URL you provided. The post data will contain all the result details for the action that triggered it. The body of this POST request is essentially the same information as you get in response to a standard synchronous request.
 
Here's an example POST request sent by Cloudinary after an upload completes:

```json
// in the header of the POST

POST /my_notification_endpoint HTTP/1.1
X-Cld-Timestamp: 	1719310887
X-Cld-Signature: 	f2292bdc1b0c99e16cb677af81dc94da6e36eae3
Content-Type: application/json

// in the body of the POST

{
  "notification_type": "upload",
  "timestamp": "2024-06-25T10:21:27+00:00",
  "request_id": "0cc3e0d9a2ce2703563b0c93c51c35ee",
  "asset_id": "be52027d24d3349b0e105c38f00ec597",
  "public_id": "jeans",
  "version": 1719310887,
  "version_id": "40c79d9223f1ca2797a55787b9c8f503",
  "width": 520,
  "height": 693,
  "format": "png",
  "resource_type": "image",
  "created_at": "2024-06-25T10:21:27Z",
  "tags": [],
  "bytes": 147954,
  "type": "upload",
  "etag": "ac03de878dde557f29c59e83edcbd74b",
  "placeholder": false,
  "url": "http://res.cloudinary.com/cld-docs/image/upload/v1719310887/jeans.png",
  "secure_url": "https://res.cloudinary.com/cld-docs/image/upload/v1719310887/jeans.png",
  "asset_folder": "",
  "display_name": "jeans",
  "original_filename": "jeans-1421398-1279x852",
  "api_key": "614335564976464",
  "notification_context": {
    "triggered_at": "2024-06-25T10:21:27.272126Z",
    "triggered_by": {
      "source": "api",
      "id": "614335564976464"
    }
  },
  "signature_key": "614335564976464"
}
```

Cloudinary signs all notification responses, allowing you to validate that they were not sent by a third-party. The notification includes both an `X-Cld-Signature` header and a `X-Cld-Timestamp` header for validating the notification response. For more details, see [Verifying notification signatures](notification_signatures).

For additional examples of notification responses from various API calls, see [notification response examples](#notification_response_examples).

> **NOTE**: If you would like to include the initiating client IP Address in the response sent to your notification, please [contact us](https://support.cloudinary.com/hc/en-us/requests/new).

## Notification URLs for specific API calls

In specific situations, you may want to notify your backend as soon as a method call is complete, for example when dealing with user initiated uploads from a browser or mobile device. You can tell Cloudinary to notify your application as soon as the method is complete by adding the `notification_url` parameter to the method call and setting it to any valid HTTP or HTTPS URL. 

The following upload API methods support the `notification_url` parameter: [upload](image_upload_api_reference#upload_method), [explicit](image_upload_api_reference#explicit_method), [explode](image_upload_api_reference#explode_method), [generate_archive](image_upload_api_reference#generate_archive_method), and [multi](image_upload_api_reference#multi_method).

> **INFO**:
>
> The **Sprite** feature and the **Image Collage** feature using the `create_collage` method will be deprecated as of **September 16, 2025**, and will no longer function after that date. Be sure to remove these features from any production code.
> You can continue creating collages using [overlays](image_collage_generation#create_collages_using_overlays).
For example, to add a `notification_url` to a specific upload call:

```multi
|ruby 
Cloudinary::Uploader.upload("sample.jpg", 
  notification_url: "https://mysite.example.com/my_notification_endpoint")
  
|php_2
$cloudinary->uploadApi()->upload("sample.jpg", 
  ["notification_url" => "https://mysite.example.com/my_notification_endpoint"]);

|python
cloudinary.uploader.upload("sample.jpg", 
  notification_url = "https://mysite.example.com/my_notification_endpoint")

|nodejs
cloudinary.v2.uploader
.upload("sample.jpg", 
  { notification_url: "https://mysite.example.com/my_notification_endpoint" })
.then(result=>console.log(result)); 
  
|java
cloudinary.uploader().upload("sample.jpg", 
  ObjectUtils.asMap("notification_url", "https://mysite.example.com/my_notification_endpoint"));

|csharp
var uploadParams = new ImageUploadParams(){
  File = new FileDescription(@"sample.jpg"),
  NotificationUrl = "https://mysite.example.com/my_notification_endpoint"};
var uploadResult = cloudinary.Upload(uploadParams); 

|go
resp, err := cld.Upload.Upload(ctx, "sample.jpg", uploader.UploadParams{
		NotificationURL: "https://mysite.example.com/my_notification_endpoint"})

|cli
cld uploader upload "sample.jpg" notification_url="https://mysite.example.com/my_notification_endpoint"
```  

> **NOTE**: A notification is sent to the destination you specified via the `notification_url` parameter in addition to any of the [global notification URLs](#global_notification_urls) set to handle the relevant **Notification type**.

## Eager transformation notifications

You can instruct Cloudinary to send a separate notification whenever a requested [Eager transformation](eager_and_incoming_transformations#eager_transformations) completes by adding the `eager_notification_url` parameter to the method call and setting it to any valid HTTP or HTTPS webhook URL. Eager transformations should be set up to work asynchronously in the background after an upload completes by also including the `eager_async` parameter (for more details, see [Eager asynchronous transformations](eager_and_incoming_transformations#eager_asynchronous_transformations)). This eager notification is in addition to any notification sent via the optional `notification_url` parameter. 

The following upload API methods support the `eager_notification_url` parameter: [upload](image_upload_api_reference#upload_method) and [explicit](image_upload_api_reference#explicit_method).

For example, the following method will upload the `sample.jpg` image and then eagerly generate two transformed images: 

1. Pad to a width and height of 300 pixels.
2. Crop to a width of 160 pixels and a height of 100 pixels. 

Furthermore, the transformations will be performed asynchronously after the image finishes uploading, with a callback URL to notify your application once the upload is complete, and a different callback URL to notify your application once the eager transformations are complete:

```multi
|ruby  
Cloudinary::Uploader.upload("sample.jpg",
  eager: [
    { width: 300, height: 300, crop: "pad"}, 
    { width: 160, height: 100, crop: "crop"}], 
  eager_async: true, 
  eager_notification_url: "https://mysite.example.com/eager_endpoint",
  notification_url: "https://mysite.example.com/upload_endpoint")
 
|php_2
$cloudinary->uploadApi()->upload("sample.jpg", [ 
    "eager" => [
        ["width" => 300, "height" => 300, "crop" => "pad"],
        ["width" => 160, "height" => 100, "crop" => "crop"]],
    "eager_async" => true,
    "eager_notification_url" => "https://mysite.example.com/eager_endpoint",
    "notification_url" => "https://mysite.example.com/upload_endpoint"]);

|python
cloudinary.uploader.upload("sample.jpg", 
  eager = [
    {"width": 300, "height": 300, "crop": "pad"},
    {"width": 160, "height": 100, "crop": "crop"}],
  eager_async = True,
  eager_notification_url = "https://mysite.example.com/eager_endpoint",
  notification_url = "https://mysite.example.com/upload_endpoint")

|go
resp, err := cld.Upload.Upload(ctx, "sample.jpg", uploader.UploadParams{
	NotificationURL: "https://mysite.example.com/my_notification_endpoint",
	EagerAsync:      api.Bool(true),
	Eager:           "c_pad,h_300,w_300|c_crop,h_100,w_160"})

|nodejs
cloudinary.v2.uploader
.upload("sample.jpg", 
  { eager: [
      { width: 300, height: 300, crop: "pad" }, 
      { width: 160, height: 100, crop: "crop"} ],                                   
    eager_async: true,
    eager_notification_url: "https://mysite.example.com/eager_endpoint",
    notification_url: "https://mysite.example.com/upload_endpoint" })
.then(result=>console.log(result)); 
  
|java
cloudinary.uploader().upload("sample.jpg", 
  ObjectUtils.asMap(
    "eager", Arrays.asList(
      new EagerTransformation().width(300).height(300).crop("pad"),
      new EagerTransformation().width(160).height(100).crop("crop")),
    "eager_async", true,
    "eager_notification_url", "https://mysite.example.com/eager_endpoint",
    "notification_url", "https://mysite.example.com/upload_endpoint"));

|csharp
var uploadParams = new ImageUploadParams(){
  File = new FileDescription(@"sample.jpg"),
  EagerTransforms = new List<Transformation>(){
   new EagerTransformation().Width(300).Height(300).Crop("pad"),
   new EagerTransformation().Width(160).Height(100).Crop("crop")},
  EagerAsync = true,
  EagerNotificationUrl = "https://mysite.example.com/eager_endpoint",
  NotificationUrl = "https://mysite.example.com/upload_endpoint"};
var uploadResult = cloudinary.Upload(uploadParams); 

|cli
cld uploader upload "sample.jpg" eager='[{"width": 300, "height": 300, "crop": "pad"},{"width": 160, "height": 100, "crop": "crop"}]' eager_async=true eager_notification_url="https://mysite.example.com/eager_endpoint" notification_url="https://mysite.example.com/upload_endpoint"
```

### Notification combinations with eager

The following table shows the results of adding different notification parameters when also requesting eager transformations with and without, the `eager_async` parameter.

Parameters | Result
---|---
`eager` and`notification_url` |  The upload method response and the `notification_url` are sent after BOTH the upload completes and the eager transformations have finished.
`eager` and`eager_notification_url` |  The upload method response and the `eager_notification_url` are sent after BOTH the upload completes and the eager transformations have finished.
`eager` and`eager_notification_url` and`eager_async` | - The upload method response is sent after the upload completes and include a batch\_id for tracking the eager job. - `eager_notification_url` is sent after the eager transformations have finished with a batch\_id for tracking.
`eager` and`notification_url` and`eager_notification_url` |  The upload method response and the `notification_url` are sent after BOTH the upload completes and the eager transformations have finished. The eager notification is ignored.
`eager` and`notification_url` and`eager_notification_url` and`eager_async` | - The upload method response and the `notification_url` are sent after the upload completes and include a batch\_id for tracking the eager job. - `eager_notification_url` is sent after the eager transformations have finished with a batch\_id for tracking.

### Eager notification response

When the eager transformations are completed, an HTTP POST request will be sent to the eager notification URL you provided with details about the requested eager transformations including the HTTP and HTTPS URLs for accessing the derived images. For example:

```json
{
  "notification_type": "eager",
  "timestamp": "2024-06-25T11:03:23+00:00",
  "request_id": "21904a712745ce42b9bc777d9fb0527b",
  "eager": [
    {
      "transformation": "c_pad,h_300,w_300",
      "width": 300,
      "height": 300,
      "bytes": 12031,
      "format": "jpg",
      "url": "http://res.cloudinary.com/cld-docs/image/upload/c_pad,h_300,w_300/v1719311335/fruit.jpg",
      "secure_url": "https://res.cloudinary.com/cld-docs/image/upload/c_pad,h_300,w_300/v1719311335/fruit.jpg"
    },
    {
      "transformation": "c_crop,h_160,w_100,g_south",
      "width": 100,
      "height": 160,
      "bytes": 1588,
      "format": "jpg",
      "url": "http://res.cloudinary.com/cld-docs/image/upload/c_crop,h_160,w_100,g_south/v1719311335/fruit.jpg",
      "secure_url": "https://res.cloudinary.com/cld-docs/image/upload/c_crop,h_160,w_100,g_south/v1719311335/fruit.jpg"
    }
  ],
  "batch_id": "29d1be417278820a9fe26c9b5af4956378420933c357d15de08055c880ca3a266575000c0ff5c7793732ac56ea8121f3",
  "asset_id": "e667b0855c526e0b3786f01e0445b995",
  "public_id": "fruit",
  "api_key": "614335564976464",
  "notification_context": {
    "triggered_at": "2024-06-25T11:03:22.694024Z",
    "triggered_by": {
      "source": "api",
      "id": "614335564976464"
    }
  },
  "signature_key": "614335564976464"
}
```

Cloudinary signs all notification responses, allowing you to validate that they were not sent by a third-party. The notification includes both an `X-Cld-Signature` header and a `X-Cld-Timestamp` header for validating the notification response. For more details, see [Verifying notification signatures](notification_signatures).

If the eager transformation is not generated for some reason then the notification response will include a status: failed and the reason, for example:

```json
{
  "transformation": "w_2,l_wrong,f_png",
  "status": "failed",
  "reason": "Unknown or invalid layer image wrong of type upload: Resource not found - wrong"
}
```

## Notification response examples
> **INFO**: Cloudinary may add more fields to API responses and notifications in the future, so please ensure that your response parsing remains forward compatible and won't break as a result of unknown fields.

This section provides several examples of notification responses to a variety of different API calls or Media Library operations. 
Keep in mind that this list is not comprehensive, and that the exact content of the response will depend on the options sent with the relevant API call or the exact operation performed in the Media Library. 

> **TIP**: The notification responses include a `notification_context` with information on the time the original request was triggered and the source of that request - either an email address for a UI initiated request, or the api_key of an API method call.

### Tags

```json
{
  "notification_type": "resource_tags_changed",
  "source": "ui",
  "resources": [
    {
      "asset_id": "e667b0855c526e0b3786f01e0445b995",
      "public_id": "fruit",
      "resource_type": "image",
      "type": "upload",
      "added": [
        "healthy"
      ]
    }
  ],
  "notification_context": {
    "triggered_at": "2024-06-25T11:50:36.599214Z",
    "triggered_by": {
      "source": "ui",
      "id": "john@doe.com"
    }
  },
  "signature_key": "614335564976464"
}
```

### Context

```json
{
  "notification_type": "resource_context_changed",
  "source": "api",
  "resources": {
    "fruit": {
      "added": [
        {
          "name": "color",
          "value": "peach"
        }
      ],
      "removed": [],
      "updated": [],
      "asset_id": "e667b0855c526e0b3786f01e0445b995",
      "resource_type": "image",
      "type": "upload"
    }
  },
  "notification_context": {
    "triggered_at": "2024-06-25T11:14:18.589209Z",
    "triggered_by": {
      "source": "api",
      "id": "614335564976464"
    }
  },
  "signature_key": "614335564976464"
}
```

### Metadata

#### No previous metadata

```json
{
  "notification_type": "resource_metadata_changed",
  "source": "api",
  "resources": {
    "fruit": {
      "previous_metadata": {},
      "new_metadata": {
        "campaign": [
          "winter"
        ]
      },
      "asset_id": "e667b0855c526e0b3786f01e0445b995",
      "resource_type": "image",
      "type": "upload"
    }
  },
  "notification_context": {
    "triggered_at": "2024-06-25T11:20:26.492317Z",
    "triggered_by": {
      "source": "api",
      "id": "614335564976464"
    }
  },
  "signature_key": "614335564976464"
}
```

#### With previous metadata

```json
{
  "notification_type": "resource_metadata_changed",
  "source": "api",
  "resources": {
    "jacket_3759": {
      "previous_metadata": {
        "description": "Fall line new collection orange jacket eveningwear",
        "expiry_date": "2022-12-01",
        "status": "active",
        "location": [
          "usa",
          "europe",
          "Asia"
        ],
        "campaign": [
          "summer_campaign",
          "winter_campaign"
        ]
      },
      "new_metadata": {
        "campaign": [
          "winter_campaign",
          "new_product_launch"
        ],
        "expiry_date": "2022-12-01",
        "location": [
          "usa",
          "europe",
          "asia"
        ],
        "status": "active",
        "description": "Fall line new collection orange jacket eveningwear"
      },
      "asset_id": "dafcecaf238b362eaa40b270855bc909",
      "resource_type": "image",
      "type": "upload"
    }
  },
  "notification_context": {
    "triggered_at": "2024-09-02T08:07:48.072101Z",
    "triggered_by": {
      "source": "api",
      "id": "946433333935132"
    }
  },
  "signature_key": "946433333935132"
}
```

### Rename
(Change the public ID)

```json
{
  "notification_type": "rename",
  "timestamp": "2024-06-25T11:29:10+00:00",
  "request_id": "92d1f2181fa4f5875fcbda17e9a14e10",
  "resource_type": "image",
  "type": "upload",
  "asset_id": "005b8a1aca3783a729054c1533624cbb",
  "asset_folder": "",
  "display_name": "strawberry_milk_splash-qwer129-aslk-srghta",
  "from_public_id": "strawberry_milk_splash-qwer129-aslk-srghta",
  "to_public_id": "strawberry_milk_splash",
  "notification_context": {
    "triggered_at": "2024-06-25T11:29:09.004998Z",
    "triggered_by": {
      "source": "api",
      "id": "614335564976464"
    }
  },
  "signature_key": "614335564976464"
}
```

### Change display name
Not supported for product environments using the legacy fixed folder mode.

 ```json
{
  "notification_type": "resource_display_name_changed",
  "timestamp": "2024-06-25T11:48:08+00:00",
  "request_id": "978e8b8992841eeacb8e6972987a5c30",
  "source": "ui",
  "resources": {
    "strawberry_milk_splash": {
      "previous_display_name": "strawberry_milk_splash",
      "new_display_name": "Strawberry Milk Splash Delight",
      "asset_id": "005b8a1aca3783a729054c1533624cbb",
      "public_id": "strawberry_milk_splash",
      "resource_type": "image",
      "type": "upload",
      "asset_folder": ""
    }
  },
  "notification_context": {
    "triggered_at": "2024-06-25T11:48:08.343788Z",
    "triggered_by": {
      "source": "ui",
      "id": "john@doe.com"
    }
  },
  "signature_key": "614335564976464"
}
```

### Create asset folder

```json
{
  "notification_type": "create_folder",
  "source": "ui",
  "folder_path": "clothing",
  "folder_name": "clothing",
  "notification_context": {
    "triggered_at": "2024-06-25T11:53:59.231237Z",
    "triggered_by": {
      "source": "ui",
      "id": "john@doe.com"
    }
  },
  "signature_key": "614335564976464"
}
```

### Move between asset folders
Not supported for product environments using the legacy fixed folder mode.

```json
{
  "source": "api",
  "resources": {
    "blue_sweater": {
      "asset_id": "09169cf604b03521789d1b3b8cca53d1",
      "resource_type": "image",
      "type": "upload",
      "from_asset_folder": "clothing",
      "to_asset_folder": "clothing_sale",
      "display_name": "blue_sweater"
    }
  },
  "notification_type": "move",
  "notification_context": {
    "triggered_at": "2024-06-25T12:03:35.006079Z",
    "triggered_by": {
      "source": "api",
      "id": "614335564976464"
    }
  },
  "signature_key": "614335564976464"
}
```

### Move an asset folder
Not supported for product environments using the legacy fixed folder mode.

```json
{
  "notification_type": "move_or_rename_asset_folder",
  "from_path": "folder1/my_folder",
  "to_path": "folder2/my_folder",
  "status": "success",
  "notification_context": {
    "triggered_at": "2024-06-25T12:14:09.764393Z",
    "triggered_by": {
      "source": "ui",
      "id": "john@doe.com"
    }
  },
  "signature_key": "614335564976464"
}
```

### Delete an asset

```json
{
  "notification_type": "delete",
  "resources": [
    {
      "resource_type": "image",
      "type": "upload",
      "asset_id": "1d1d8d109a08857b6a7fcea5510d1970",
      "public_id": "kids_playing_with_puppy",
      "version": 1719318204,
      "asset_folder": "",
      "display_name": "kids_playing_with_puppy"
    }
  ],
  "notification_context": {
    "triggered_at": "2024-06-25T12:24:29.599817Z",
    "triggered_by": {
      "source": "api",
      "id": "614335564976464"
    }
  },
  "signature_key": "614335564976464"
}
```

### Delete an asset folder

Not supported for product environments using the legacy fixed folder mode.

```json
{
  "notification_type": "delete_folder",
  "source": "ui",
  "folder_path": "clothing",
  "folder_name": "clothing",
  "notification_context": {
    "triggered_at": "2024-06-25T12:26:18.528535Z",
    "triggered_by": {
      "source": "ui",
      "id": "john@doe.com"
    }
  },
  "signature_key": "614335564976464"
}
```

### Multi generation

```json
{
  "url": "http://res.cloudinary.com/cld-docs/image/multi/f_webp/v1719323739/logo.webp",
  "secure_url": "https://res.cloudinary.com/cld-docs/image/multi/f_webp/v1719323739/logo.webp",
  "asset_id": "fa441e2c3968794333afd86663c7936f",
  "public_id": "logo,webp,f_webp",
  "version": 1719323739,
  "notification_type": "multi",
  "notification_context": {
    "triggered_at": "2024-06-25T13:55:39.047359Z",
    "triggered_by": {
      "source": "api",
      "id": "614335564976464"
    }
  },
  "signature_key": "614335564976464"
}
```

### Proof status changed

When the status of a [creative approval](dam_creative_approval_proofs) proof reaches a decision (for example, when a proof is approved or requires changes), a notification is sent with details about the proof and its new status.

```json
{
  "notification_type": "proof_status_changed",
  "timestamp": "2026-01-19T14:30:45+00:00",
  "request_id": "abc123def456ghi789jkl012mno345pq",
  "proof_id": "proof_12345abcde67890fghij",
  "proof_name": "Summer Campaign Assets",
  "previous_status": "pending_review",
  "new_status": "approved",
  "stage_name": "Final Approval",
  "stage_number": 3,
  "reviewer": {
    "id": "reviewer@example.com",
    "name": "Jane Reviewer"
  },
  "assets": [
    {
      "asset_id": "e667b0855c526e0b3786f01e0445b995",
      "public_id": "campaigns/summer/hero_image",
      "resource_type": "image",
      "type": "upload"
    },
    {
      "asset_id": "a123b456c789d012e345f678g901h234",
      "public_id": "campaigns/summer/product_banner",
      "resource_type": "image",
      "type": "upload"
    }
  ],
  "notification_context": {
    "triggered_at": "2026-01-19T14:30:45.123456Z",
    "triggered_by": {
      "source": "ui",
      "id": "reviewer@example.com"
    }
  },
  "signature_key": "614335564976464"
}
```

> **TIP**: To understand how proof decisions are calculated based on reviewer decisions, see [Understanding proof decision calculation](dam_admin_creative_approval_flows#understanding_proof_decision_calculation).

### Explode

When you include a `notification_url`, Cloudinary sends a **single** `notification_type: "explode"` notification when all derived assets have been generated, rather than one notification per derived asset.

```json
{
  "notification_type": "explode",
  "pages": 4,
  "image_infos": [
    {
      "bytes": 145646,
      "url": "http://res.cloudinary.com/cld-docs/image/upload/pg_1/v1719333585/blue_signs.png",
      "secure_url": "https://res.cloudinary.com/cld-docs/image/upload/pg_1/v1719333585/blue_signs.png"
    },
    {
      "bytes": 162386,
      "url": "http://res.cloudinary.com/cld-docs/image/upload/pg_2/v1719333585/blue_signs.png",
      "secure_url": "https://res.cloudinary.com/cld-docs/image/upload/pg_2/v1719333585/blue_signs.png"
    },
    {
      "bytes": 97552,
      "url": "http://res.cloudinary.com/cld-docs/image/upload/pg_3/v1719333585/blue_signs.png",
      "secure_url": "https://res.cloudinary.com/cld-docs/image/upload/pg_3/v1719333585/blue_signs.png"
    },
    {
      "bytes": 48313,
      "url": "http://res.cloudinary.com/cld-docs/image/upload/pg_4/v1719333585/blue_signs.png",
      "secure_url": "https://res.cloudinary.com/cld-docs/image/upload/pg_4/v1719333585/blue_signs.png"
    }
  ],
  "batch_id": "a4de8783f29b530156935f785842347bf3681954dcfe712f770e096e35b0d70612f06c88aa009c9a0eb7186f2012ca85",
  "asset_id": "b5e903cab932acc820fa1416dab52573",
  "notification_context": {
    "triggered_at": "2024-06-25T16:42:37.873884Z",
    "triggered_by": {
      "source": "api",
      "id": "614335564976464"
    }
  },
  "signature_key": "614335564976464"
}
```

### Upload (simple)

```json
{
  "notification_type": "upload",
  "timestamp": "2024-06-25T16:48:30+00:00",
  "request_id": "76308c7ee2cb6094a5780a03524e527a",
  "asset_id": "59a3bb9b5df2b3e80a1013220db70bc7",
  "public_id": "upknxfupsmqzfomzmmpv",
  "version": 1719334109,
  "version_id": "4ad82428e820c936097ad02ad265d0c4",
  "width": 750,
  "height": 160,
  "format": "png",
  "resource_type": "image",
  "created_at": "2024-06-25T16:48:29Z",
  "tags": [],
  "bytes": 20791,
  "type": "upload",
  "etag": "534e8213b282f8c2a53b600090149d08",
  "placeholder": false,
  "url": "http://res.cloudinary.com/cld-docs/image/upload/v1719334109/upknxfupsmqzfomzmmpv.png",
  "secure_url": "https://res.cloudinary.com/cld-docs/image/upload/v1719334109/upknxfupsmqzfomzmmpv.png",
  "asset_folder": "",
  "display_name": "upknxfupsmqzfomzmmpv",
  "original_filename": "cloudinary_logo",
  "api_key": "614335564976464",
  "notification_context": {
    "triggered_at": "2024-06-25T16:48:29.366010Z",
    "triggered_by": {
      "source": "api",
      "id": "614335564976464"
    }
  },
  "signature_key": "614335564976464"
}
```

### Upload (complex)

```json
{
  "notification_type": "upload",
  "timestamp": "2024-06-25T16:58:44+00:00",
  "request_id": "77b7c76220cea1939b0b249877481b3b",
  "asset_id": "9a84b9de266a8c05ce3d9a07529dbde9",
  "public_id": "myfolder/fox",
  "version": 1719334720,
  "version_id": "f8e875874898b75e6a4e965931566ec3",
  "width": 4928,
  "height": 3280,
  "format": "jpg",
  "resource_type": "image",
  "created_at": "2024-06-25T16:58:40Z",
  "tags": [
    "red fox",
    "fox",
    "canine",
    "fur"
  ],
  "pages": 1,
  "bytes": 1013122,
  "type": "upload",
  "etag": "08891030261a8104886a38f906128866",
  "placeholder": false,
  "url": "http://res.cloudinary.com/cld-docs/image/upload/v1719334720/myfolder/fox.jpg",
  "secure_url": "https://res.cloudinary.com/cld-docs/image/upload/v1719334720/myfolder/fox.jpg",
  "asset_folder": "",
  "display_name": "fox",
  "moderation": [
    {
      "kind": "aws_rek",
      "status": "approved",
      "response": {
        "moderation_labels": [],
        "moderation_model_version": "7.0"
      },
      "updated_at": "2024-06-25T16:58:42Z"
    }
  ],
  "info": {
    "categorization": {
      "imagga_tagging": {
        "status": "complete",
        "data": [
          {
            "tag": {
              "en": "red fox"
            },
            "confidence": 1
          },
          {
            "tag": {
              "en": "fox"
            },
            "confidence": 1
          },
          {
            "tag": {
              "en": "canine"
            },
            "confidence": 1
          },
          {
            "tag": {
              "en": "fur"
            },
            "confidence": 0.7615
          },
          {
            "tag": {
              "en": "feline"
            },
            "confidence": 0.5778
          },
          {
            "tag": {
              "en": "cute"
            },
            "confidence": 0.5668
          },
          {
            "tag": {
              "en": "mammal"
            },
            "confidence": 0.4334
          }
        ]
      }
    },
    "detection": {
      "aws_rek_face": {
        "status": "complete",
        "data": {
          "celebrity_faces": [],
          "unrecognized_faces": []
        }
      }
    }
  },
  "faces": [],
  "coordinates": {
    "faces": []
  },
  "original_filename": "fox",
  "api_key": "614335564976464",
  "notification_context": {
    "triggered_at": "2024-06-25T16:58:40.398807Z",
    "triggered_by": {
      "source": "api",
      "id": "614335564976464"
    }
  },
  "signature_key": "614335564976464"
}
```

### Access control

```json
{
  "notification_type": "access_control_changed",
  "source": "api",
  "resources": [
    {
      "asset_id": "d85b8af60889a2fb1b6e37c563b550a6",
      "public_id": "cloudinary_logo_white",
      "resource_type": "image",
      "type": "upload",
      "previous_access_control": {
        "access_types": [
          {
            "access_type": "token"
          }
        ]
      },
      "new_access_control": {
        "access_types": [
          {
            "access_type": "token"
          },
          {
            "access_type": "anonymous",
            "start": "2024-06-16T22:00:00Z",
            "end": "2024-07-17T22:00:00Z"
          }
        ]
      }
    }
  ],
  "notification_context": {
    "triggered_at": "2024-06-25T19:13:49.634723Z",
    "triggered_by": {
      "source": "api",
      "id": "614335564976464"
    }
  },
  "signature_key": "614335564976464"
}
```

### Related assets

#### Add related assets

```json
{
  "notification_type": "related_assets",
  "action_type": "add_related_assets",
  "asset_id": "b97f5c40561ebe3f567da17232478732",
  "total_failed": 0,
  "total_success": 1,
  "notification_context": {
    "triggered_at": "2026-01-22T14:24:14.953780Z",
    "triggered_by": {
      "source": "api",
      "id": "419393447856432"
    }
  },
  "signature_key": "419393447856432"
}
```

> **NOTE**:
>
> The `asset_id` is the primary asset to which you added or removed relationships. The webhook notification payload doesn't include the full list of related assets. To retrieve the full list of related assets, use either:

> * The response from the original [Add related assets by public ID](admin_api#add_related_assets) or [Add related assets by asset ID](admin_api#add_related_assets_by_asset_id) API call that triggered the notification

> * The [Get details of a single resource by public ID](admin_api#get_details_of_a_single_resource_by_public_id) or [Get details of a single resource by asset ID](admin_api#get_details_of_a_single_resource_by_asset_id) endpoints with the `related` parameter set to `true`

#### Delete related assets

```json
{
  "notification_type": "related_assets",
  "action_type": "delete_related_assets",
  "asset_id": "6524cbec0d2d158bd3ee71730423efbc",
  "total_failed": 0,
  "total_success": 1,
  "notification_context": {
    "triggered_at": "2026-01-22T14:24:28.573105Z",
    "triggered_by": {
      "source": "api",
      "id": "419393447856432"
    }
  },
  "signature_key": "419393447856432"
}
```

### Image inserted from Media Library widget

```json
{
  "public_id": “sample”,
  "resource_type": "image",
  "type": “upload”,
  "format": "jpg",
  "version": 1511474034,
  "url": "http://res.cloudinary.com/demo/image/upload/v1511474034/sample.jpg",
  "secure_url": "https://res.cloudinary.com/demo/image/upload/v1511474034/sample.jpg",
  "display_name": "sample",
  "asset_folder": "samples",
  "width": 864,
  "height": 576,
  "bytes": 120257,
  "duration": null,
  "tags": [],
  "metadata": [],
  "created_at": "2023-02-08T08:38:51Z",
  "derived": [
    {
      "url": "http://res.cloudinary.com/demo/image/upload/c_scale,e_grayscale,f_auto,q_auto,w_100/v1511474034/sample.jpg",
      "secure_url": "https://res.cloudinary.com/demo/image/upload/c_scale,e_grayscale,f_auto,q_auto,w_100/v1511474034/sample.jpg"
    }
  ],
  "access_mode": "public",
  "access_control": [],
  "created_by": {
    "type": "user",
    "id": “abc123def456ghiabc123def456ghi”
  },
  "uploaded_by": {
    "type": "user",
    "id": “xyz789efg456qrsxyz789efg456qrs”
  },
  "id": "ede59e6d3befdc65a8adc2f381c0f96f",
  "folder_id": "abcs432p8xyz0q532wqpoirnk0138"
```

> **NOTE**: On product environments using the legacy fixed folder mode, `asset_folder` and `display_name` keys are also not included in the response, and the `folder` key is.

## Retry policy

In the event of a failed notification URL, the HTTP response code is assessed. If the response is not `200 OK`, three additional notification attempts are initiated:

* A retry after 3 minutes.
* A second attempt after 6 minutes.
* A final retry after 9 minutes.

## Troubleshooting

Understanding how to troubleshoot notification failures and identify why notifications may not reach their destination URL is essential for seamless operation. Here, we explore common failure causes and ways to avoid potential pitfalls when working with Cloudinary webhook notifications.

### Common causes of failure

* **Payload corruption**: Payload validation in webhook notifications checks if the data meets expected formatting and matches system requirements. Failure may signal data corruption issues that affect processing. 

* **Invalid signature**: Verification of the signature may fail, resulting in webhook failures.

* **Disabled API key**: Using a disabled API key for signing the API can impact webhook functionality. To activate your API keys, go to the [API Keys](https://console.cloudinary.com/app/settings/api-keys) page of your Console Settings.

* **Invalid Webhook URL**: A webhook was configured with an incorrect or inaccessible notification URL. For example, you may have configured an endpoint that no longer exists, or changes in the URL path may not be updated in the configuration.

* **Connection Timeout**: Timeout errors may occur if your server experiences delays exceeding our 20-second limit. Retries happen for transient issues, but consistent server slowness may lead to notification failures.

### Ways to avoid potential pitfalls

While setting up and maintaining your webhooks, keep the following potential pitfalls in mind:

* **Check the signature calculation**: Make sure your [signature](authentication_signatures) calculation is accurate. This is crucial for webhook success.

* **Ensure JSON payload is stringified correctly**: JSON payload stringifying can encounter problems like data loss, invalid JSON, and character encoding mismatches. These issues can be avoided by using standard libraries, validating JSON data, and handling special characters correctly.

* **Standardize hash methods**: When different cloud platforms use different methods for securing webhook data, it can cause signature mismatches, leading to webhook failure. Avoid this by standardizing the hash algorithm or implementing flexible signature verification.

* **Avoid notification overload**: Ensure your server can handle the volume of notifications, especially when there are numerous uploads.

* **Follow HTTP header specifications**: Ensure HTTP headers are treated as case-insensitive according to the HTTP V2 specification.

* **Monitor endpoint logs**: Regularly check endpoint logs for `500` errors to identify issues with processing Cloudinary notifications.

> **NOTE**: Cloudinary currently does not disable failing endpoints to help customers troubleshoot and address notification issues.
