This skill should be used when the user asks about "build trigger", "webhook trigger", "poll trigger", "dynamic webhook", "static webhook", "hybrid trigger", "dedup", "trigger_limit", "closure", or needs to implement triggers for a Workato custom connector.
From workato-connector-sdknpx claudepluginhub grailautomation/claude-plugins --plugin workato-connector-sdkThis skill uses the workspace's default tool permissions.
references/guides__building-triggers.mdreferences/guides__building-triggers__dynamic-webhook.mdreferences/guides__building-triggers__hybrid-triggers.mdreferences/guides__building-triggers__poll.mdreferences/guides__building-triggers__securing-webhooks.mdreferences/guides__building-triggers__static-webhook.mdreferences/guides__trigger-limit.mdGuide for building triggers in Workato custom connectors. Triggers start recipes when new data is available.
Workato supports three trigger types:
triggers: {
new_record: {
title: 'New record',
subtitle: 'Triggers when a new record is created',
description: lambda do |input, pick_list_label|
"New <span class='provider'>#{pick_list_label['object_type'] || 'record'}</span>"
end,
input_fields: lambda do
[
{ name: 'object_type', control_type: 'select', pick_list: 'object_types' }
]
end,
poll: lambda do |connection, input, closure|
# Polling logic
end,
dedup: lambda do |record|
record['id']
end,
output_fields: lambda do |object_definitions|
object_definitions['record']
end
}
}
Periodically fetch new records.
new_record: {
title: 'New record',
input_fields: lambda do
[{ name: 'since', type: 'date_time', optional: true }]
end,
poll: lambda do |connection, input, closure|
# closure persists between polls
since = closure || input['since'] || Time.now.iso8601
records = get('/api/records')
.params(created_after: since, order: 'created_at')['items']
next_since = records.last&.[]('created_at') || since
{
events: records,
next_poll: next_since, # Stored in closure for next poll
can_poll_more: records.size >= 100
}
end,
dedup: lambda do |record|
record['id'] # Unique identifier for deduplication
end,
output_fields: lambda do
[
{ name: 'id' },
{ name: 'name' },
{ name: 'created_at', type: 'date_time' }
]
end
}
The closure parameter persists state between polls:
poll: lambda do |connection, input, closure|
closure ||= { page_token: nil, since: input['since'] }
response = get('/api/records').params(
since: closure['since'],
page_token: closure['page_token']
)
{
events: response['items'],
next_poll: {
since: response['items'].last&.[]('created_at') || closure['since'],
page_token: response['next_page_token']
},
can_poll_more: response['has_more']
}
end
Receive real-time notifications from the API.
Webhook URL is fixed per connection:
new_event_webhook: {
title: 'New event (webhook)',
webhook_subscribe: lambda do |connection, input, webhook_url|
post('/api/webhooks').payload(
url: webhook_url,
events: ['record.created']
)
end,
webhook_unsubscribe: lambda do |connection, webhook|
delete("/api/webhooks/#{webhook['id']}")
end,
webhook_notification: lambda do |connection, input, payload|
payload['data'] # Return the event data
end,
dedup: lambda do |event|
event['id']
end,
output_fields: lambda do
[{ name: 'id' }, { name: 'type' }, { name: 'data', type: 'object' }]
end
}
Webhook URL changes per recipe:
new_event_dynamic: {
title: 'New event (real-time)',
webhook_subscribe: lambda do |connection, input, recipe_id, webhook_url|
post('/api/webhooks').payload(
url: webhook_url,
events: input['event_types'],
metadata: { recipe_id: recipe_id }
)
end,
webhook_unsubscribe: lambda do |connection, webhook|
delete("/api/webhooks/#{webhook['id']}")
end,
webhook_notification: lambda do |connection, input, payload, headers|
# Verify webhook signature
signature = headers['X-Webhook-Signature']
expected = workato.hmac_sha256(payload.to_json, connection['webhook_secret'])
error('Invalid signature') unless signature == expected
payload['events']
end,
dedup: lambda do |event|
event['event_id']
end
}
Combine polling for historical data with webhooks for real-time:
new_record_hybrid: {
title: 'New record (real-time)',
# Poll for historical/missed records
poll: lambda do |connection, input, closure|
since = closure || input['since'] || Time.now.iso8601
records = get('/api/records').params(created_after: since)['items']
{
events: records,
next_poll: records.last&.[]('created_at') || since,
can_poll_more: records.size >= 100
}
end,
# Subscribe to webhook for real-time
webhook_subscribe: lambda do |connection, input, recipe_id, webhook_url|
post('/api/webhooks').payload(url: webhook_url, events: ['record.created'])
end,
webhook_unsubscribe: lambda do |connection, webhook|
delete("/api/webhooks/#{webhook['id']}")
end,
webhook_notification: lambda do |connection, input, payload|
[payload['record']] # Return as array
end,
dedup: lambda do |record|
record['id']
end
}
The dedup lambda returns a unique identifier to prevent duplicate processing:
# Simple ID dedup
dedup: lambda do |record|
record['id']
end
# Composite dedup
dedup: lambda do |record|
"#{record['type']}_#{record['id']}_#{record['version']}"
end
webhook_notification: lambda do |connection, input, payload, headers|
# HMAC verification
signature = headers['X-Signature']
computed = workato.hmac_sha256(payload.to_json, connection['secret'])
error('Invalid webhook signature') unless signature == computed
payload['data']
end
Some APIs require allowlisting Workato's IPs. Refer to Workato documentation for current IP ranges.
For APIs that don't track "since" timestamps:
new_record: {
poll: lambda do |connection, input, closure|
records = get('/api/records').params(limit: 100)['items']
{
events: records.first(workato.trigger_limit || 100),
can_poll_more: false
}
end
}
Provide sample data for recipe building:
sample_output: lambda do |connection, input|
get('/api/records').params(limit: 1)['items'].first || {
id: 'sample_123',
name: 'Sample Record',
created_at: Time.now.iso8601
}
end
For detailed documentation:
references/guides__building-triggers.md - Triggers overviewreferences/guides__building-triggers__poll.md - Poll trigger patternsreferences/guides__building-triggers__static-webhook.md - Static webhooksreferences/guides__building-triggers__dynamic-webhook.md - Dynamic webhooksreferences/guides__building-triggers__hybrid-triggers.md - Hybrid triggersreferences/guides__building-triggers__securing-webhooks.md - Webhook securityreferences/guides__trigger-limit.md - Trigger limits and quotas