Webhooks v3 event filter examples

In theory, there’s almost no limit to the number – and the complexity – of filters you can add to a webhook subscription. In real life, however, most organizations will opt for a smaller and simpler set of filters that limit forwarded webhook notifications based on:

  • Application ID
  • Entity type
  • Client ID
  • A specified set of user profile attributes
  • Multiple event types

In this documentation we explain how to create filters for use with any of the preceding items; for each filter we’ll provide sample JSON code and a sample Curl command for creating the filter. The sample JSON code will look similar to this:

"filter": {
  "$schema": "http://json-schema.org/draft-07/schema",
  "properties": {
      "entityUpdated": {
        "properties": {
          "captureApplicationId": {
            "const": "zzyn9gy9r8xdy5zkru4y54syk6"
          }
        }
      }
    }
  }

To use this filter on one of your webhook subscriptions, just copy the code and paste it into the request body of your API call. The code can be used essentially as-is; all you’ll have to do (at least with this example) is replace the sample application ID with the ID of the application you want to filter on:

"const": "zzyn9gy9r8xdy5zkru4y54syk6"
"const": "ed7absqep5rffbmqx89c9mwexqvbnfnk"

It’s that simple. (And to make it even simpler, we'll be sure to list the values that you might need to change in red.)

Here are the sample filters/sample Curl commands described in this article:

  • Filtering on a Specific Application ID
  • Filtering on a Specific Entity Type
  • Filtering on a Specific Client ID
  • Filtering on User Profile Attributes
  • Filtering on Multiple Event Types
  • Removing a Filter

Important: What happens if you have multiple webhook subscriptions?

Before you begin adding filters to your webhook subscriptions it’s worth taking a brief refresher course on how the Identity Cloud processes events.

To begin with, let’s say you have two webhook subscriptions for the entityCreated event. Thanks to a filter, Subscription A only forwards entityCreated events if the entityType property is equal to user; Subscription B doesn’t have a filter, meaning that it forwards any entityCreated event. In other words:

Now, suppose an event occurs where the entityType property is equal to test. Will that event be forwarded to your listener endpoint?

If you answered “yes,” you’re absolutely right. Although this isn’t exactly the way things work, you can picture events as traveling down a conveyer belt, with all the webhook subscriptions lined up beside that belt. When our sample event comes down the line, Subscription A examines the event and decides that it’s not applicable. Why? Because the entityType property isn’t set to test.

But that doesn’t mean that the event is discarded. Instead, the event continues down the line and is inspected by your other subscriptions. When the event passes Subscription B, Subscription B correctly sees that the event is applicable (it's looking for any instances of the entityCreated event) and forwards a copy to your listener endpoint. You might have thought that you were filtering on the entityType property, but that's true only for Subscription A. Granted, Subscription A won’t forward the event, but Subscription B – which doesn’t have a filter – will.

The moral of the story? An event will always be forwarded unless it manages to reach the end of the line without being claimed by any webhooks subscription.

In other words, all your events are made available to all your webhook subscriptions, and events are forwarded if they are “claimed” by any one of those subscriptions. That means the filter you to assigned Subscription A (in order to ensure that you receive only a selected subset of eventCreated events) can be superseded by Subscription B, a subscription that forwards all eventCreated events. In turn, that means that, as much as possible, you should:

  • Limit the number of webhook subscriptions you create.

  • If you do create multiple subscriptions then do your best to ensure that those subscriptions don't accidentally conflicting with one another.

In the previous example, if you get rid of Subscription B (which forwards all entityCreated events), then your only remaining entityCreated subscription (Subscription A) will only forward the filtered events.

Just something to watch out for.


📘

In order to keep things simple, this documentation assumes that the sample webhook subscriptions and the sample filters are your only subscriptions and your only filters.


How the sample filters work

To make our sample filters as realistic (and as useful) as possible, we've written most of them so that they filter on two things: the main target of the filter (a specific entity type, a specific client ID, a specific user profile attribute) and on a specific application ID. In other words, these filters tend to do things like return all the entityUpdated events that reference the user entity type and were generated by a specific application.

We did this because this is how many organizations will want to use webhook filtering; for example, they'll want to see entityUpdated events only from their user entity type and only for their production application; they're not interested in events that occurred in their development environment. That said, however, other organizations might prefer to see entityUpdated events from the user entity type in any application:

"captureApplicationId": {
    "const": "zzyn9gy9r8xdy5zkru4y54syk6"
}

If you want to filter on both application ID and, say, entity type, then you don't have to do anything: just leave the sample code exactly as it is. And what if you don't want to filter on application ID as well as entity type? That's fine: just delete the unwanted text and you'll be ready to go.

Incidentally, many of the filters also include the required keyword:

"required": ["entityType", "captureApplicationId"]

The required keyword indicates all the properties that must be present in order for the event to be forwarded; in the preceding example, that means that an event must include both the entityType property and the captureApplicationId property in order to pass validation. The required keyword is optional: an entityUpdated event should always include both of these properties. But, you never know, and, if nothing else, the required keyword makes it obvious which properties the filter is looking for.


Filtering on a specific application ID

It’s not uncommon for organizations to have more than one Identity Cloud application; for example, many organizations have at least two such applications: one for development and one for production. This Console screenshot shows a test setup that encompasses 5 separate applications:

Organizations that have multiple applications are prime candidates for webhook filtering; if you have even two applications (like one for development and one for production) you might create a filter to ensure that you only receive events from the production application. In this section of the documentation, we’ll show you how to filter your webhook events based on the application that generated those events.

Let’s assume that you do have two applications, one for development and one for production. How hard is it to create a filter that only forwards events associated with the production application? As it turns out, it's not very hard at all: all you have to do is create a filter that:

  1. Includes the captureApplicationId property.

  2. Uses the const keyword, which ensures that events are forwarded only if the value of the clientApplicationId property exactly matches the value assigned to the const keyword.

  3. Sets the value of the const keyword to the ID of the production application (in this example, zzyn9gy9r8xdy5zkru4y54syk6):

"const": "zzyn9gy9r8xdy5zkru4y54syk6"

The following filter triggers for any entityUpdated event where the captureApplicationId property is equal to zzyn9gy9r8xdy5zkru4y54syk6. The const keyword ensures that events are forwarded only if they're associated with the specified application:

"filter": {
  "$schema": "http://json-schema.org/draft-07/schema",
  "properties": {
      "entityUpdated": {
        "properties": {
          "captureApplicationId": {
            "const": "zzyn9gy9r8xdy5zkru4y54syk6"
          }
        }
      }
    }
  },
  "additionalProperties": false

A complete Curl command for adding this filter to a webhook subscription will look similar to this:

‘https://api.multi.dev.or.janrain.com/00000000-0000-0000-0000-000000000000/webhooks/subscriptions/e2605711-1656-4b0a-977b-70b0f008134a’ \
  -H ‘Content-Type: application/merge-patch+json’ \
  -H ‘Authorization: Bearer yLKSRNXqbiIF0N9CJwwv2BgNumtN39jSMu2A8p5YaLDGag60WrZV6KLj6Rgqlips’ \
  --data-raw '{
  "filter": {
    "$schema": "http://json-schema.org/draft-07/schema",
    "properties": {
        "entityUpdated": {
          "properties": {
            "captureApplicationId”": {
              "const": "zzyn9gy9r8xdy5zkru4y54syk6"
            }
          }
        }
      }
    },
    "additionalProperties": false
  }’

For example, suppose your organization generates the following three events, events which are then run past the sample filter:

In this example, only 1 of the 3 events is forwarded to your listener endpoint: the event with the application ID zzyn9gy9r8xdy5zkru4y54syk6:


Filtering on a specific entity type

When you initially subscribe to the Identity Cloud you’re issued a single entity type (i.e., a single user profile database): the user entity type. However, you’re not limited to that default entity type; instead, you can create as many entity types as you need. A quick look at the Manage Schemas section in Console will show you all the entity types associated with an application; this test Identity Cloud implementation includes both the user entity type and a number of custom-made entity types:

In the preceding implementation, not all of the listed entity types are employed to store actual user profiles: the fact that one of these entity types is named Test might have clued you in on that. If we assume that you have multiple entity types, is there a way to construct a filter only forwards events from a selected entity type? We’re just about to find out.

In order to receive events associated with one (and only one) entity type all you have to do is:

  • Include the entityType property in your filter.

  • Use the const keyword.

  • Set the value of the const keyword to the name of the entity type you want to receive events for. For example, this syntax limits the forwarded events to events where the entityType is set to user:

"const": "user"

The following filter triggers only on entityUpdated events where the entityType is set to user (and where the captureApplicationId is equal to zzyn9gy9r8xdy5zkru4y54syk6). This is done by using the const keyword and setting the value to the desired entity type name:

"filter": {
  "$schema": "http://json-schema.org/draft-07/schema",
"properties": {
      "entityUpdated": {
        "properties": {
          "entityType": {
            "const": "user"
          },
          "captureApplicationId": {
            "const": "zzyn9gy9r8xdy5zkru4y54syk6"
          },
          "required": ["entityType", "captureApplicationId"]
        }
      }
    }
  },
  "additionalProperties": false

A complete Curl command for adding this filter to a webhook subscription will look similar to this:

curl -L -X PATCH \
  'https://api.multi.dev.or.janrain.com/00000000-0000-0000-0000-000000000000/webhooks/subscriptions/e2605711-1656-4b0a-977b-70b0f008134a' \
  -H 'Content-Type: application/merge-patch+json' \
  -H 'Authorization: Bearer yLKSRNXqbiIF0N9CJwwv2BgNumtN39jSMu2A8p5YaLDGag60WrZV6KLj6Rgqlips' \
  --data-raw '{  
  filter": {
    "$schema": "http://json-schema.org/draft-07/schema",
    "properties": {
       "entityUpdated": {
         "properties": {
           "entityType": {
             "const": "user"
           },
          "captureApplicationId": {
            "const": "zzyn9gy9r8xdy5zkru4y54syk6"
          },
          "required": ["entityType", "captureApplicationId"]
         }
       }
     }
   },
   "additionalProperties": false
 }'

For example, suppose your organization generates the following three events, events which are then run past the sample filter:

Two of these three events are forwarded to your listener endpoint; that’s because they use the entity type (user) specified by the const keyword:


Filtering on a specific client ID

Login clients (known as application clients in Hosted Login) play a key role in the user login and registration experience: login clients maintain password security and password history settings; they specify the URL for verifying emails; they help determine the language of (and the wording for) the screens employed by end users. Considering the large number of settings and options managed by a login client it shouldn’t be too surprising that even smaller organizations will typically employ multiple clients:

As for larger organizations? Those organizations – especially the ones with a multi-national presence – often have scores of login clients, which means that they also have scores of login clients to deal with when it comes to webhook events. And that can be a problem: what if there are really only a handful of clients whose events are considered important enough to track via Webhooks v3?

Fortunately, that's not an issue you need to lose sleep over: as it turns out, you can limit your webhook notifications to a single client by -- that's right: by adding a filter to your webhooks subscription.

For example, suppose you only want to receive events associated with a specific client ID. That’s fine; all you need to do is create a filter that:

  1. Includes the captureClientId property.
  2. Uses the const keyword.
  3. Sets the value of the const keyword to the allowed client ID. For example:
"const": "ay6e3qmucvdyr29hmpvxjdjupe8bcsky"

The following filter triggers for all entityUpdated events where the captureClientId property is equal to ay6e3qmucvdyr29hmpvxjdjupe8bcsky (and where the captureApplicationId is equal to zzyn9gy9r8xdy5zkru4y54syk6). The const keyword is used to ensure that one, and only one, client ID triggers the filter:

"filter": {
  "$schema": "http://json-schema.org/draft-07/schema",
  "properties": {
      "entityUpdated": {
        "properties": {
          "captureClientId": {
            "const": "ay6e3qmucvdyr29hmpvxjdjupe8bcsky"
          },
          "captureApplicationId": {
            "const": "zzyn9gy9r8xdy5zkru4y54syk6"
          },
          "required": ["captureClientId", "captureApplicationId"]
        }
      }
    }
  },
  "additionalProperties": false

A complete Curl command for adding this filter to a webhook subscription will look similar to this:

curl -L -X PATCH \
  'https://api.multi.dev.or.janrain.com/00000000-0000-0000-0000-000000000000/webhooks/subscriptions/e2605711-1656-4b0a-977b-70b0f008134a' \
  -H 'Content-Type: application/merge-patch+json' \
  -H 'Authorization: Bearer yLKSRNXqbiIF0N9CJwwv2BgNumtN39jSMu2A8p5YaLDGag60WrZV6KLj6Rgqlips' \
  --data-raw '{  
"filter": {
    "$schema": "http://json-schema.org/draft-07/schema",
"properties": {
      "entityUpdated": {
        "properties": {
          "captureClientId": {
            "const": "ay6e3qmucvdyr29hmpvxjdjupe8bcsky"
          },
          "captureApplicationId": {
            "const": "zzyn9gy9r8xdy5zkru4y54syk6"
          },
          "required": ["captureClientId", "captureApplicationId"]
        }
      }
    }
  },
  "additionalProperties": false
}'

For example, suppose your organization generates the following three events, events which are then run past the sample filter:

In this scenario, only 1 of the 3 events is forwarded to the listener endpoint. Not too surprisingly, that one event is the event that has the specified client ID (ay6e3qmucvdyr29hmpvxjdjupe8bcsky):


Filtering on user profile attributes

By default, an Identity Cloud user profile has dozens of attributes (that is, there are dozens of fields available in a user profile). If you look at the Manage Schema page in Console you can see detailed information about each entity type and the many user profile attributes that make up each entity type:


📘

This might be a good time to mention that user profile attributes are only included in entityUpdated events: user profile attributes can't be found in the entityCreated or entityDeleted events. That means that there’s no point in adding an attributes filter to an entityCreated or entityDeleted event: with those event types there will never be any attributes to filter on.


Each time a change is made to a user profile an event is generated. In turn, an entityUpdated webhook subscription that doesn't have a filter will dutifully forward each of those events to your listener endpoint..

As you might expect, there are some potential problems with that. For one, some attributes are subject to seemingly-endless changes; the foremost example of this is the lastUpdated attribute, which is modified each and every time a user logs on. If you have 100,000 users logging on each day, that means you’ll have 100,000 instances of the lastUpdated attribute being changed. That also means that you’ll have 100,000 entityUpdated events being generated and forwarded to your listener endpoint. It might be important to you to capture each of those events. But, then again, maybe it's not all that important.

Similarly, not all user profile attributes are created equal. It might be useful to know when, and how often, users change their passwords or their email addresses; it might be less useful to know how often users change their middle name. Being notified if the accountDataRequestTime or the accountDeleteRequestTime attributes change can be useful: after all, a change to either of those attributes typically means that you need to take action of some kind (i.e., send a user a copy of their data or delete a user profile). But knowing that a user has uploaded a new photo of themselves? That might be less critical.

Either way, if you don’t want to be notified about every change to every user profile attribute you can use a filter to specify the attributes that cause an event notification to be forwarded (and, by extension, which ones cause an event notification to be ignored).


📘

You’re probably already aware of this, but it’s worth repeating: a webhook event notification includes a list of all the attributes that have been changed in a user profile, but it doesn’t include either the new values or the previous values of those attributes. You’ll know that a user has changed their mobileNumber attribute, but the event notification won’t tell you the user’s old mobile number or their new mobile number.


For example, the following filter triggers on entityUpdated events where any of three attribute values email, password, or mobileNumber) are referenced. To do that, the filter:

  • Includes the attributes property.

  • Uses the contains keyword to indicate that the target attribute must be referenced in the attributes value.

  • Uses the enum keyword to specify the set of allowed attribute values. To trigger the filter, the attributes value must contain at least one of the specified values. (And yes, it can contain more than one of the attributes.)

And, most of our like other sample filters, this one also requires the captureApplicationId to be equal to zzyn9gy9r8xdy5zkru4y54syk6).

The filter itself looks like this:

"filter": {
  "$schema": "http://json-schema.org/draft-07/schema",
  "properties": {
      "entityUpdated": {
        "properties": {
          "attributes": {
            "contains": {
              "enum": ["email", "password", "mobileNumber"]
            }
          },
          "captureApplicationId": {
            "const": "zzyn9gy9r8xdy5zkru4y54syk6"
          },
          "required": ["attributes", "captureApplicationId"]
        }
      }
    }  
  },
  "additionalProperties": false

A complete Curl command for adding this filter to a webhook subscription will look similar to this:

curl -L -X PATCH \
  'https://api.multi.dev.or.janrain.com/00000000-0000-0000-0000-000000000000/webhooks/subscriptions/e2605711-1656-4b0a-977b-70b0f008134a' \
  -H 'Content-Type: application/merge-patch+json' \
  -H 'Authorization: Bearer yLKSRNXqbiIF0N9CJwwv2BgNumtN39jSMu2A8p5YaLDGag60WrZV6KLj6Rgqlips' \
  --data-raw '{  
    "filter": {
    "$schema": "http://json-schema.org/draft-07/schema",
    "properties": {
      "entityUpdated": {
        "properties": {
          "attributes": {
            "contains": {
              "enum": ["email", "password", "mobileNumber"]
            }
          },
          "captureApplicationId": {
            "const": "zzyn9gy9r8xdy5zkru4y54syk6"
          },
          "required": ["attributes", "captureApplicationId"]
        }
      }
    }  
  },
  "additionalProperties": false
}'

For example, suppose your organization generates the following three events, events which are then run past the sample filter:

In this example, all three events are forwarded to your listener endpoint. That’s because each event includes at least one of the user profile attributes (email, password, or mobileNumber) referenced by the enum keyword:

img


Filtering on multiple event types

When you create a Webhooks v3 subscription you have three event types you can monitor for: entityCreated, entityDeleted, and entityUpdated. On top of that, a single subscription can monitor for any combination of those three event types; for example, one subscription can receive event notifications any time a user profile is created or deleted or updated.

If you include multiple event types in a subscription you also have the option of associating filters with any (or all) of those event types. This is done by creating a separate filter for each type. If you subscribe to the entityCreated event you can create a filter for that event type. If the entityUpdated event is included in that same subscription then you can filter on that event type as well – provided that you create a second filter, one targeted towards the entityUpdated event. Needless to say, that's true if you're also subscribed to the entityDeleted event type.

Note that there is nothing special about these filters: they’re the same filters you use with any webhook subscription. The only difference is that you might need two or three of them.

For example, the following filter triggers on all three webhook event types: entityCreated, entityUpdated, and entityDeleted. In all three cases, the event’s captureApplicationId property must be equal to zzyn9gy9r8xdy5zkru4y54syk6: if the event references any other application ID the filter won’t be triggered.

As we mentioned a moment ago, in order to trigger on multiple event types, you might want to include separate filters for each type: that’s why this filter has one section labeled entityCreated, a second section labeled entityDeleted, and a third section labeled entityUpdated.

The filter itself looks like this:

"filter": {
    "$schema": "http://json-schema.org/draft-07/schema",
    "properties": {
        "entityCreated": {
            "properties": {
                "captureApplicationId": {
                    "const": "zzyn9gy9r8xdy5zkru4y54syk6"
                }
            }
        },
        "entityDeleted": {
            "properties": {
                "captureApplicationId": {
                    "const": "zzyn9gy9r8xdy5zkru4y54syk6"
                }
            }
        },
        "entityUpdated": {
            "properties": {
                "captureApplicationId": {
                    "const": "zzyn9gy9r8xdy5zkru4y54syk6"
                }
            }
        },
        "additionalProperties": false
    }
}

📘

Do all three of these filters have to be exactly the same? No. For example, you might want to add a section to the entityUpdated filter specifying that events must be include the password attribute in order to be forwarded. In that case, you'd be forwarded all the entityCreated and entityDeleted events, but only the entityUpdated events involving the password attribute.


A complete Curl command for adding this filter to a webhook subscription will look similar to the following:

curl -L -X PATCH \
  'https://api.multi.dev.or.janrain.com/00000000-0000-0000-0000-000000000000/webhooks/subscriptions/e2605711-1656-4b0a-977b-70b0f008134a' \
  -H 'Content-Type: application/merge-patch+json' \
  -H 'Authorization: Bearer yLKSRNXqbiIF0N9CJwwv2BgNumtN39jSMu2A8p5YaLDGag60WrZV6KLj6Rgqlips' \
  --data-raw '{  
    "filter": {
    "$schema": "http://json-schema.org/draft-07/schema",
    "properties": {
      "entityCreated": {
        "properties": {
          "captureClientId": {
            "const": "ay6e3qmucvdyr29hmpvxjdjupe8bcsky"
          }
        }
      },
      "entityDeleted": {
        "properties": {
          "captureClientId": {
            "const": "ay6e3qmucvdyr29hmpvxjdjupe8bcsky"
          }
        }
      },
      "entityUpdated": {
        "properties": {
          "captureApplicationId": {
            "const": "zzyn9gy9r8xdy5zkru4y54syk6"
          }
    }
  }'
  "additionalProperties": false
}

For example, suppose your organization generates the following three events, events which are then run past the sample filter:

In this case, all three events are forwarded to the listener endpoint. That's because each event references a monitored event type, and each event also meets the filter criterion (i.e., clientApplicationId is equal to zzyn9gy9r8xdy5zkru4y54syk6):


Removing a filter

As a general rule, webhook filters are easy to write. Yes, you can create extremely complicated filters using the JSON schema language but, as we’ve seen elsewhere in this documentation, most webhook filters involve a handful of easily-modified lines of code:

"filter": {
  "$schema": "http://json-schema.org/draft-07/schema",
  "properties": {
      "entityUpdated": {
        "properties": {
          "captureApplicationId": {
            "const": "zzyn9gy9r8xdy5zkru4y54syk6"
          }
        }
      }
    }
  }

And that's good: easy is almost always better. But what about removing a filter, what happens if you’ve added a filter to a subscription (e.g., “Show me only the entityUpdated events for Application A”) and you now want to get rid of that filter? (Leaving us with “Show me all the entityUpdated events, regardless of Application ID.”) How complicated is that going to be?

At risk of ruining the suspense, it’s not going to be complicated at all. In fact, to remove a filter from a webhooks subscription all you have to do is set the subscription’s filter property to null. In other words,:

"filter": null

Believe it or not, that’s all you have to do.

Here’s a complete Curl command for that removing a filter from a webhook subscription:

curl -L -X PATCH \
  'https://api.multi.dev.or.janrain.com/00000000-0000-0000-0000-000000000000/webhooks/subscriptions/e2605711-1656-4b0a-977b-70b0f008134a' \
  -H 'Content-Type: application/merge-patch+json' \
  -H 'Authorization: Bearer yLKSRNXqbiIF0N9CJwwv2BgNumtN39jSMu2A8p5YaLDGag60WrZV6KLj6Rgqlips' \
  --data-raw '{
    "filter": null
  }'