Create and Filter Notification Subscriptions
Use the Notifications API to create and filter subscriptions with CEL-based filter expressions.
Learn how to use the Notifications API to create subscriptions with filter expressions that control which event notifications you receive. The filterExpression field accepts a Common Expression Language (CEL) expression that evaluates against each event's payload and returns only the events that evaluate to true.
When an event is generated, the filter expression is evaluated against the event payload, and only events that satisfy the filter criteria are forwarded to your endpoint.
Prerequisites
To complete this tutorial, you need:
- Authorization from the selling partners for whom you are making calls. Refer to Authorizing Selling Partner API applications for more information.
Eligible notification types
The following notification types support filterExpression:
| Notification type | filterExpression supported |
|---|---|
ACCOUNT_STATUS_CHANGED | Yes |
ANY_OFFER_CHANGED | Yes |
B2B_ANY_OFFER_CHANGED | Yes |
DETAIL_PAGE_TRAFFIC_EVENT | Yes |
EXTERNAL_FULFILLMENT_SHIPMENT_STATUS_CHANGE | Yes |
FBA_INVENTORY_AVAILABILITY_CHANGES | Yes |
FBA_OUTBOUND_SHIPMENT_STATUS | Yes |
FEED_PROCESSING_FINISHED | Yes |
FEE_PROMOTION | Yes |
FULFILLMENT_ORDER_STATUS | Yes |
ITEM_INVENTORY_EVENT_CHANGE | Yes |
ITEM_SALES_EVENT_CHANGE | Yes |
ORDER_CHANGE | Yes |
PRICING_HEALTH | Yes |
REPORT_PROCESSING_FINISHED | Yes |
TRANSACTION_UPDATE | Yes |
LISTINGS_ITEM_ISSUES_CHANGE | No |
LISTINGS_ITEM_MFN_QUANTITY_CHANGE | No |
LISTINGS_ITEM_STATUS_CHANGE | No |
PRODUCT_TYPE_DEFINITIONS_CHANGE | No |
BRANDED_ITEM_CONTENT_CHANGE | No |
ITEM_PRODUCT_TYPE_CHANGE | No |
Note
You cannot use
filterExpressionandeventFiltertogether. Use one or the other. Use filter expressions to replace existingeventFilterconditions underprocessingDirective. If you need both aggregation and filtering, continue to useeventFilter.
Supported CEL operators
The following table lists the CEL operators that you can use in a filterExpression:
| Operator type | Supported | Not supported |
|---|---|---|
| Logical | ! (NOT), && (AND), || (OR), ? : (ternary) | N/A |
| Comparison | ==, !=, <, <=, >, >=, in | N/A |
| Comprehension macros | has(e.f), e.all(x, p), e.exists(x, p), e.exists_one(x, p) | e.filter(x, p), e.map(x, t) |
| String functions | contains(), startsWith(), endsWith(), matches(), size() | N/A |
| List/Map operations | in, size() | [] (indexing) |
| Arithmetic | N/A | +, -, *, /, % |
Step 1. Identify the notification payload fields
Before you create a filter expression, review the payload structure of the notification type you want to filter.
Note
Filter expressions can only reference fields within the notification payload. The filter returns only events that evaluate to
true. You can write filter expressions on optional fields. However, you must check whether the field is present before you use it, or the filter fails at runtime. Use thehas()macro for field presence checks.
Step 2. Write the CEL filter expression
Write a CEL expression that targets the payload fields you identified in Step 1.
Filtering on optional fields with has()
has()Some notification payloads contain optional fields that are only present under certain conditions. If your filterExpression references a field that is absent from the payload, the filter evaluation fails at runtime and the event is dropped. To safely filter on optional fields, use the has() macro to check for field presence before accessing the field.
Note
If
has()is not used as in the example below, the request will fail when FulfillmentShipment is not present:FulfillmentOrderStatusNotification.FulfillmentShipment.FulfillmentShipmentStatus == "Shipped"
The FulfillmentShipment field in the FULFILLMENT_ORDER_STATUS notification is optional. It is only present when the notification contains shipment information. If you want to filter on a field inside FulfillmentShipment, you must first check that it exists.
has(FulfillmentOrderStatusNotification.FulfillmentShipment) && FulfillmentOrderStatusNotification.FulfillmentShipment.FulfillmentShipmentStatus == "Shipped"
Step 3. Create the subscription with a filter expression
Call the createSubscription operation and include the filterExpression field in the processingDirective object.
The following examples show sample notification payloads and the corresponding createSubscription requests with filterExpression.
FULFILLMENT_ORDER_STATUS
{
"NotificationVersion": "1.0",
"NotificationType": "FULFILLMENT_ORDER_STATUS",
"PayloadVersion": "1.0",
"EventTime": "2020-01-11T00:09:53.109Z",
"Payload": {
"FulfillmentOrderStatusNotification": {
"SellerId": "A3TH9S8BH6GOGM",
"EventType": "Shipment",
"StatusUpdatedDateTime": "2020-01-11T00:09:53.109Z",
"SellerFulfillmentOrderId": "ext-order-id-12345",
"FulfillmentOrderStatus": "Complete",
"FulfillmentShipment": {
"FulfillmentShipmentStatus": "Shipped",
"AmazonShipmentId": "DZRSmwG2N",
"EstimatedArrivalDateTime": "2020-01-14T22:59:59Z",
"FulfillmentShipmentPackages": [{
"PackageNumber": 1,
"CarrierCode": "UPS",
"TrackingNumber": "1Z999AA10123456784"
}]
}
}
},
"NotificationMetadata": {
"ApplicationId": "amzn1.sellerapps.app.f1234566-aaec-55a6-b123-bcb752069ec5",
"SubscriptionId": "7d78cc50-95c8-4641-add7-10af4b1fedc9",
"PublishTime": "2020-01-11T00:02:50.501Z",
"NotificationId": "2012e8e5-b365-4cb1-9fd8-be9dfc6d5eaf"
}
}
Sample createSubscription request with filterExpression
createSubscription request with filterExpression{
"payloadVersion": "1.0",
"destinationId": "sampleId",
"processingDirective": {
"filterExpression": "FulfillmentOrderStatusNotification.EventType == \"ORDER\" && FulfillmentOrderStatusNotification.FulfillmentOrderStatus == \"COMPLETE\""
}
}
REPORT_PROCESSING_FINISHED
{
"notificationVersion": "2020-09-04",
"notificationType": "REPORT_PROCESSING_FINISHED",
"payloadVersion": "2020-09-04",
"eventTime": "2020-07-14T03:35:13.214Z",
"payload": {
"reportProcessingFinishedNotification": {
"sellerId": "A3TH9S8BH6GOGM",
"accountId": "amzn1.merchant.o.A3TH9S8BH6GOGM",
"reportId": "54517018502",
"reportType": "GET_FLAT_FILE_ACTIONABLE_ORDER_DATA",
"processingStatus": "CANCELLED",
"reportDocumentId": "amzn1.tortuga.3.edbcd0d8-3434-8222-1234-52ad8ade1208.REP4567URI9BMZ"
}
},
"notificationMetadata": {
"applicationId": "amzn1.sellerapps.app.aaccczf-4455-4b7c-4422-664ecacdd336",
"subscriptionId": "subscription-id-d0e9e693-c3ad-4373-979f-ed4ec98dd746",
"publishTime": "2020-07-13T19:45:04.284Z",
"notificationId": "d0e9e693-c3ad-4373-979f-ed4ec98dd746"
}
}
Sample createSubscription request with filterExpression
createSubscription request with filterExpression{
"payloadVersion": "1.0",
"destinationId": "sampleId",
"processingDirective": {
"filterExpression": "reportProcessingFinishedNotification.processingStatus == \"CANCELLED\" && reportProcessingFinishedNotification.reportType == \"GET_FLAT_FILE_ACTIONABLE_ORDER_DATA\""
}
}
Migrate existing subscriptions to filter expressions
This section explains how to add filtering to your existing subscriptions and how to migrate from eventFilter to filterExpression.
Important
- You cannot update an existing subscription to add a
filterExpression. You must delete the existing subscription and create a new one.- You cannot use
eventFilterandfilterExpressiontogether in the same subscription.- Existing subscriptions without a
filterExpressioncontinue to receive all events. There is no change to current behavior unless you explicitly create a new subscription with afilterExpression.
Migration approach
To avoid missing events during migration, run your new filtered subscription in parallel with your existing subscription before switching over.
-
Create a new subscription with
filterExpressionalongside your existing subscription (use a separate destination or the same destination if your processor can handle both). -
Receive and process filtered notifications in parallel but do not use them for business logic yet.
-
Confirm that filtered notifications match expectations: correct events are delivered, no unexpected gaps, and your processor handles them correctly. Run for 1–2 weeks.
-
Once validated, delete your old subscription using the
deleteSubscriptionoperation.
Note
If you cannot run two subscriptions in parallel, delete the old subscription and create the new one. Be aware there may be a brief gap in notifications during the switch.
Scenario 1: Add filtering to an existing subscription (no prior filtering)
Use this approach when you currently receive all events for a notification type and want to filter to only specific events.
Use case: You subscribe to ANY_OFFER_CHANGED and receive notifications for all offer changes. You want to receive only notifications triggered by a Featured Offer change.
Sample ANY_OFFER_CHANGED notification payload
ANY_OFFER_CHANGED notification payload{
"NotificationVersion": "1.0",
"NotificationType": "ANY_OFFER_CHANGED",
"PayloadVersion": "1.0",
"EventTime": "2020-07-13T19:42:04.284Z",
"Payload": {
"AnyOfferChangedNotification": {
"SellerId": "A3TH9S8BH6GOGM",
"OfferChangeTrigger": {
"MarketplaceId": "ATVPDKIKX0DER",
"ASIN": "B08N5WRWNW",
"ItemCondition": "New",
"TimeOfOfferChange": "2020-07-13T19:42:04.284Z",
"OfferChangeType": "FeaturedOffer"
},
"Summary": {
"NumberOfOffers": [
{
"Condition": "new",
"FulfillmentChannel": "Merchant",
"OfferCount": 10
}
],
"TotalBuyBoxEligibleOffers": 100
},
"Offers": [
{
"SellerId": "A3TH9S8BH6GOGM",
"SubCondition": "New",
"IsFulfilledByAmazon": true,
"IsFeaturedMerchant": true
}
]
}
},
"NotificationMetadata": {
"ApplicationId": "amzn1.sellerapps.app.f1234566-aaec-55a6-b123-bcb752069ec5",
"SubscriptionId": "7d78cc50-95c8-4641-add7-10af4b1fedc9",
"PublishTime": "2020-07-13T19:42:04.284Z",
"NotificationId": "d0e9e693-c3ad-4373-979f-ed4ec98dd746"
}
}
Step 1. Create a new subscription with a filter expression
Call the createSubscription operation with a filterExpression in the processingDirective.
{
"payloadVersion": "your-payload-version",
"destinationId": "your-destination-id",
"processingDirective": {
"filterExpression": "AnyOfferChangedNotification.OfferChangeTrigger.OfferChangeType == \"FeaturedOffer\""
}
}
Step 2. Run in shadow mode and validate
Run your new filtered subscription in parallel with your existing unfiltered subscription. Process the filtered notifications but do not use them for business logic yet. Confirm that the expected events are delivered, no events are unexpectedly missing, and your processor handles the filtered payload correctly.
Step 3. Delete your old subscription
After validation is complete, call the deleteSubscription operation to remove your old subscription.
DELETE /notifications/v1/subscriptions/ANY_OFFER_CHANGED
You now receive ANY_OFFER_CHANGED notifications only when the offer change is triggered by a Featured Offer change. All other offer change types (Internal, External) are filtered out.
Scenario 2: Migrate from eventFilter to filterExpression (ANY_OFFER_CHANGED)
eventFilter to filterExpression (ANY_OFFER_CHANGED)Use this approach when you currently use eventFilter and want to migrate to filterExpression for more flexible filtering.
Use case: You currently use eventFilter to filter ANY_OFFER_CHANGED notifications to a specific marketplace. You want to migrate to filterExpression to also filter by offer change type.
Your current subscription (with eventFilter):
{
"payloadVersion": "your-payload-version",
"destinationId": "your-destination-id",
"processingDirective": {
"eventFilter": {
"eventFilterType": "ANY_OFFER_CHANGED",
"marketplaceIds": ["ATVPDKIKX0DER"]
}
}
}
Step 1. Create a new subscription with filterExpression
filterExpressionConvert your eventFilter marketplace filter to a CEL expression:
{
"payloadVersion": "your-payload-version",
"destinationId": "your-destination-id",
"processingDirective": {
"filterExpression": "AnyOfferChangedNotification.OfferChangeTrigger.MarketplaceId == \"ATVPDKIKX0DER\""
}
}
To combine marketplace filtering with offer change type filtering:
{
"payloadVersion": "your-payload-version",
"destinationId": "your-destination-id",
"processingDirective": {
"filterExpression": "AnyOfferChangedNotification.OfferChangeTrigger.MarketplaceId == \"ATVPDKIKX0DER\" && AnyOfferChangedNotification.OfferChangeTrigger.OfferChangeType == \"FeaturedOffer\""
}
}
Step 2. Run in shadow mode and validate
Run your new filtered subscription in parallel with your existing eventFilter subscription. Process the filtered notifications but do not use them for business logic yet. Confirm that the expected events are delivered, no events are unexpectedly missing, and your processor handles the filtered payload correctly.
Step 3. Delete your old subscription
After validation is complete, delete your old subscription:
DELETE /notifications/v1/subscriptions/ANY_OFFER_CHANGED
You now receive ANY_OFFER_CHANGED notifications only for the US marketplace (ATVPDKIKX0DER) where the change was triggered by a Featured Offer update.
Note
If you currently rely on
aggregationSettingsin youreventFilter(for example, to limit notification frequency), you cannot replicate this behavior withfilterExpression. Aggregation is only available witheventFilter. If you need both aggregation and filtering, continue to useeventFilter.
Updated about 2 hours ago
