Custom Event Automation Discovery Workflow
This workflow discovers all pipelines (automations) triggered by Custom Events and generates sample Custom Events that match both the trigger criteria and any handlebars template requirements in the pipeline outcomes.
Prerequisites
- Airship account with API access
- OAuth token with
plnscope (for pipelines API) - OAuth token with
evtscope (for custom events API) - Test user identifier (named_user_id or channel_id) for submitting sample events
Skills Required
- Pipelines - List and filter pipelines
- Custom Events - Submit custom events
Step 1: List Pipelines with Custom Event Triggers
Use the filtered pipelines endpoint to get all pipelines triggered by Custom Events:
GET /api/pipelines/filtered?triggers=CUSTOM_EVENT&enabled=true&limit=50
Authorization: Bearer <token>
Accept: application/vnd.urbanairship+json; version=3
Optional filtering:
- Add
enabled=trueto get only enabled pipelines (note: this includespendingpipelines ifactivation_timeis in the future) - To get only currently active ("live") pipelines: filter by
enabled=truevia API, then filter client-side by checkingstatus === "live"or verifying current time is betweenactivation_timeanddeactivation_time
Handle pagination:
- Check
next_pagelink in response to get additional pages - Or use
startandlimitparameters for manual pagination
Response example:
{
"ok": true,
"pipelines": [
{
"uid": "abc123-def456-ghi789",
"name": "Purchase Event Automation",
"enabled": true,
"status": "live",
"immediate_trigger": {
"custom_event": {
"key": "name",
"value": {
"equals": "purchased"
}
}
},
"outcome": {
"push": {
"audience": "triggered",
"device_types": ["ios", "android"],
"notification": {
"alert": "Thank you for purchasing {{custom_event.properties.product_name}}! Your order total was ${{custom_event.value}}."
}
}
}
}
],
"total_count": 1,
"next_page": null
}
Step 2: Extract Custom Event Criteria from Triggers
For each pipeline, examine the immediate_trigger.custom_event selector to extract matching criteria.
Simple Selector
If the trigger is a simple selector:
{
"custom_event": {
"key": "name",
"value": {
"equals": "purchased"
}
}
}
Extract:
- Event name:
"purchased"(fromkey: "name"withvalue.equals)
Complex Selector with AND
If the trigger uses AND logic:
{
"custom_event": {
"and": [
{
"key": "name",
"value": {
"equals": "purchased"
}
},
{
"key": "value",
"value": {
"greater_than": 50
}
}
]
}
}
Extract:
- Event name:
"purchased" - Value constraint: must be greater than 50
Selector with Property Constraints
If the trigger checks properties:
{
"custom_event": {
"and": [
{
"key": "name",
"value": {
"equals": "purchased"
}
},
{
"key": "category",
"scope": "properties",
"value": {
"equals": "electronics"
}
}
]
}
}
Extract:
- Event name:
"purchased" - Property constraint:
properties.categorymust equal"electronics"
Handling OR and NOT Operators
For OR selectors, extract all possible values. For NOT selectors, note the exclusion criteria.
Step 2a: Extract Handlebars References from Pipeline Outcome
Examine the pipeline's outcome object for handlebars template syntax. Look for handlebars patterns in:
- Push notifications:
notification.alert - Email:
notification.email.subject,notification.email.html_body,notification.email.plaintext_body - SMS:
notification.sms - Any other templated fields in the outcome
Handlebars Pattern Examples
Extract references matching these patterns:
{{custom_event.properties.<property_name>}}- Property reference{{custom_event.value}}- Event value reference{{custom_event.name}}- Event name reference{{custom_event.<field>}}- Other field references{{custom_event.properties.product.name}}- Nested property access
Example: Extract from Notification Alert
Given this outcome:
{
"outcome": {
"push": {
"notification": {
"alert": "Thank you for purchasing {{custom_event.properties.product_name}}! Your order total was ${{custom_event.value}}."
}
}
}
}
Extract handlebars references:
{{custom_event.properties.product_name}}→ requiresproperties.product_name{{custom_event.value}}→ requiresvaluefield
Example: Extract from Email Body
Given this outcome:
{
"outcome": {
"push": {
"notification": {
"email": {
"subject": "Order Confirmation",
"html_body": "<h1>Thank you, {{custom_event.properties.customer_name}}!</h1><p>Your order {{custom_event.properties.order_id}} is confirmed.</p>"
}
}
}
}
}
Extract handlebars references:
{{custom_event.properties.customer_name}}→ requiresproperties.customer_name{{custom_event.properties.order_id}}→ requiresproperties.order_id
Step 3: Generate Sample Custom Events
For each pipeline, create a sample Custom Event that:
- Matches the trigger criteria (from Step 2)
- Includes properties needed for handlebars substitution (from Step 2a)
Example 1: Simple Trigger with Handlebars
Pipeline trigger:
{
"custom_event": {
"key": "name",
"value": {
"equals": "purchased"
}
}
}
Pipeline outcome:
{
"notification": {
"alert": "Thank you for purchasing {{custom_event.properties.product_name}}! Total: ${{custom_event.value}}."
}
}
Generated sample event:
[{
"user": {
"named_user_id": "test-user-123"
},
"body": {
"name": "purchased",
"value": 99.99,
"properties": {
"product_name": "Sample Product"
}
}
}]
Why each field:
name: "purchased"- Matches trigger requirementvalue: 99.99- Referenced in handlebars ({{custom_event.value}})properties.product_name- Referenced in handlebars ({{custom_event.properties.product_name}})
Example 2: Complex Trigger with Multiple Properties
Pipeline trigger:
{
"custom_event": {
"and": [
{
"key": "name",
"value": {
"equals": "purchased"
}
},
{
"key": "category",
"scope": "properties",
"value": {
"equals": "electronics"
}
},
{
"key": "value",
"value": {
"greater_than": 50
}
}
]
}
}
Pipeline outcome:
{
"notification": {
"alert": "Your {{custom_event.properties.category}} purchase of ${{custom_event.value}} is confirmed!"
}
}
Generated sample event:
[{
"user": {
"named_user_id": "test-user-123"
},
"body": {
"name": "purchased",
"value": 75.00,
"properties": {
"category": "electronics"
}
}
}]
Why each field:
name: "purchased"- Matches trigger requirementvalue: 75.00- Matches trigger constraint (greater_than: 50) AND referenced in handlebarsproperties.category: "electronics"- Matches trigger constraint AND referenced in handlebars
Example 3: Nested Properties
Pipeline outcome:
{
"notification": {
"alert": "Product {{custom_event.properties.product.name}} from {{custom_event.properties.product.brand}} is ready!"
}
}
Generated sample event:
[{
"user": {
"named_user_id": "test-user-123"
},
"body": {
"name": "product_ready",
"properties": {
"product": {
"name": "Sample Product",
"brand": "Sample Brand"
}
}
}
}]
Step 4: Submit Sample Custom Events
Use the custom-events skill to submit the generated events:
POST /api/custom-events
Authorization: Bearer <token>
X-UA-Appkey: <application_key>
Accept: application/vnd.urbanairship+json; version=3
Content-Type: application/json
[
{
"user": {
"named_user_id": "test-user-123"
},
"body": {
"name": "purchased",
"value": 99.99,
"properties": {
"product_name": "Sample Product"
}
}
}
]
Best practices:
- Submit events as an array (up to 100 events per request)
- Use a test user identifier that won't affect real users
- Include
occurredtimestamp if testing historical scenarios - Set
unique_idif testing sequence triggers to prevent duplicate sends
Complete Workflow Example
Input: List of Pipelines
{
"pipelines": [
{
"name": "Purchase Automation",
"immediate_trigger": {
"custom_event": {
"key": "name",
"value": {
"equals": "purchased"
}
}
},
"outcome": {
"push": {
"notification": {
"alert": "Thanks for buying {{custom_event.properties.product_name}}!"
}
}
}
}
]
}
Output: Generated Sample Events
[
{
"user": {
"named_user_id": "test-user-123"
},
"body": {
"name": "purchased",
"properties": {
"product_name": "Sample Product"
}
}
}
]
Result
When submitted, this event will:
- ✅ Trigger the "Purchase Automation" pipeline (matches trigger criteria)
- ✅ Render the notification as: "Thanks for buying Sample Product!" (handlebars resolve correctly)
Outcomes
- All pipelines with Custom Event triggers identified
- Trigger criteria extracted and documented
- Handlebars template requirements identified
- Sample Custom Events generated that match both trigger criteria and template needs
- Sample events submitted to test automations
Use Cases
- Testing automations: Generate test events to verify pipeline behavior
- Documentation: Document what events trigger which automations
- Integration planning: Understand event requirements before implementation
- Debugging: Create sample events to troubleshoot pipeline issues
- Onboarding: Help developers understand automation setup
Best Practices
- Use test users: Always use test named_user_id or channel_id when submitting sample events
- Extract all criteria: Include both trigger constraints AND handlebars references
- Handle complex selectors: Properly parse AND/OR/NOT operators in triggers
- Check nested properties: Look for nested property access in handlebars (e.g.,
properties.product.name) - Use meaningful sample values: Choose sample property values that demonstrate the templating
- Handle pagination: Process all pipelines across multiple pages
- Filter by status: Consider filtering to only "live" pipelines if testing active automations
- Document findings: Keep track of which events trigger which pipelines
Related Workflows
- Complete User Onboarding - Uses custom events in a multi-step workflow
Troubleshooting
Issue: Sample event doesn't trigger pipeline
- Check: Verify event name matches trigger criteria exactly (case-sensitive, lowercase only)
- Check: Ensure value constraints are met (e.g.,
greater_than,equals) - Check: Verify property constraints match (if trigger checks properties)
Issue: Handlebars don't render correctly
- Check: Ensure all referenced properties are included in the event
- Check: Verify property paths match handlebars references (e.g.,
properties.product_namevsproperties.product.name) - Check: Ensure nested properties are structured correctly
Issue: Pipeline not found in filtered results
- Check: Verify pipeline has
enabled: trueif usingenabled=truefilter - Check: Ensure trigger type is correctly identified as
CUSTOM_EVENT - Check: Pipeline may be on a different page (handle pagination)