
Create three EventBridge custom event bus subscribers, each using more features: filter, then retry and dead-letter queue, then a JSONata transform.
Replace the placeholders with your own ARNs. The most basic subscriber: a DATA-scoped filter that delivers only events whose detail.status equals PLACED, and drops everything else.
BUS_ARN="<EVENT_BUS_ARN>"
QUEUE_ARN="<TARGET_QUEUE_ARN>"
ROLE_ARN="<DELIVERY_ROLE_ARN>"
aws eventsv2 create-subscriber \
--name "orders-basic" \
--event-bus-arn "$BUS_ARN" \
--filter-configuration "$(cat <<EOF
{"Filters":[{"Scope":"DATA","Pattern":"{\"detail\":{\"status\":[\"PLACED\"]}}"}]}
EOF
)" \
--invoke-configuration "$(cat <<EOF
{"TargetArn":"$QUEUE_ARN","RoleArn":"$ROLE_ARN"}
EOF
)"
A more resilient subscriber. Adds --retry-policy to retry failed deliveries and --on-failure-configuration to send events that exhaust their retries to an SQS dead-letter queue. Uses a numeric-range filter.
BUS_ARN="<EVENT_BUS_ARN>"
QUEUE_ARN="<TARGET_QUEUE_ARN>"
ROLE_ARN="<DELIVERY_ROLE_ARN>"
DLQ_ARN="<DEAD_LETTER_QUEUE_ARN>"
aws eventsv2 create-subscriber \
--name "orders-resilient" \
--event-bus-arn "$BUS_ARN" \
--filter-configuration "$(cat <<EOF
{"Filters":[{"Scope":"DATA","Pattern":"{\"detail\":{\"total\":[{\"numeric\":[\">\",100,\"<=\",500]}]}}"}]}
EOF
)" \
--invoke-configuration "$(cat <<EOF
{"TargetArn":"$QUEUE_ARN","RoleArn":"$ROLE_ARN"}
EOF
)" \
--retry-policy "$(cat <<EOF
{"MaxRetryAttempts":10,"MaxEventAgeInSeconds":3600}
EOF
)" \
--on-failure-configuration "$(cat <<EOF
{"Arn":"$DLQ_ARN"}
EOF
)"
The fully featured subscriber. Adds --transformer with Type JSONATA to reshape the payload before delivery, on top of the filter, retry, and dead-letter queue. Uses an $or filter across fields.
BUS_ARN="<EVENT_BUS_ARN>"
QUEUE_ARN="<TARGET_QUEUE_ARN>"
ROLE_ARN="<DELIVERY_ROLE_ARN>"
DLQ_ARN="<DEAD_LETTER_QUEUE_ARN>"
aws eventsv2 create-subscriber \
--name "orders-full" \
--event-bus-arn "$BUS_ARN" \
--filter-configuration "$(cat <<EOF
{"Filters":[{"Scope":"DATA","Pattern":"{\"detail\":{\"\$or\":[{\"priority\":[\"HIGH\"]},{\"total\":[{\"numeric\":[\">=\",1000]}]}]}}"}]}
EOF
)" \
--invoke-configuration "$(cat <<EOF
{"TargetArn":"$QUEUE_ARN","RoleArn":"$ROLE_ARN"}
EOF
)" \
--retry-policy "$(cat <<EOF
{"MaxRetryAttempts":10,"MaxEventAgeInSeconds":3600}
EOF
)" \
--on-failure-configuration "$(cat <<EOF
{"Arn":"$DLQ_ARN"}
EOF
)" \
--transformer "$(cat <<EOF
{"Type":"JSONATA","JsonataConfiguration":{"Expression":"{% { \"orderId\": \$events.Data.detail.orderId, \"total\": \$events.Data.detail.total } %}"}}
EOF
)"
Five DATA-scoped filter values using EventBridge comparison operators: numeric range, anything-but, begins-with (prefix), exists, and $or across fields. Swap any one into the --filter-configuration of a subscriber above.
# Numeric (range): total > 100 and <= 500.
FILTER='{"Filters":[{"Scope":"DATA","Pattern":"{\"detail\":{\"total\":[{\"numeric\":[\">\",100,\"<=\",500]}]}}"}]}'
# Anything-but: status is any value except "CANCELLED".
FILTER='{"Filters":[{"Scope":"DATA","Pattern":"{\"detail\":{\"status\":[{\"anything-but\":\"CANCELLED\"}]}}"}]}'
# Begins with (prefix): region starts with "us-".
FILTER='{"Filters":[{"Scope":"DATA","Pattern":"{\"detail\":{\"region\":[{\"prefix\":\"us-\"}]}}"}]}'
# Exists: the couponCode field is present.
FILTER='{"Filters":[{"Scope":"DATA","Pattern":"{\"detail\":{\"couponCode\":[{\"exists\":true}]}}"}]}'
# Or across fields ($or): priority is "HIGH" OR total is >= 1000.
FILTER='{"Filters":[{"Scope":"DATA","Pattern":"{\"detail\":{\"$or\":[{\"priority\":[\"HIGH\"]},{\"total\":[{\"numeric\":[\">=\",1000]}]}]}}"}]}'