Trigger Node
Trigger nodes are the entry points for workflows in Xentom. They listen for external events and initiate workflow execution when those events occur. Trigger nodes can invoke other nodes but cannot be invoked themselves, making them the starting point of any automation flow.
Key Characteristics
- Workflow Entry Points: Only trigger nodes can start a workflow
- Event-Driven: Respond to external events like webhooks, timers, or system events
- Cannot be Invoked: Other nodes cannot call trigger nodes directly
- Can Invoke Others: Trigger nodes can call callable nodes via execution pins
- Subscribe Pattern: Use a subscription model to listen for events
Basic Structure
import * as i from '@xentom/integration-framework';
export const onWebhook = i.nodes.trigger({
// Optional: group your node in the UI
group: 'External/HTTP',
// Optional: custom display name
displayName: 'Webhook Receiver',
// Optional: description for users and AI assistance
description: 'Receives HTTP requests and processes the payload',
// Configuration inputs from the user
inputs: {
path: i.pins.data({
control: i.controls.text({
label: 'Webhook Path',
placeholder: '/webhook',
defaultValue: '/webhook',
}),
}),
},
// Data outputs when triggered
outputs: {
payload: i.pins.data({
displayName: 'Request Payload',
description: 'The parsed request body',
}),
headers: i.pins.data({
displayName: 'HTTP Headers',
description: 'Request headers as key-value pairs',
}),
},
// Subscribe function: sets up event listeners
subscribe({ next, webhook, inputs, state, variables }) {
// Set up event listening logic
const unsubscribe = webhook.subscribe(async (req) => {
try {
const payload = await req.json();
// Emit outputs and start workflow
next({
payload,
headers: Object.fromEntries(req.headers),
});
return new Response('OK', { status: 200 });
} catch (error) {
return new Response('Bad Request', { status: 400 });
}
});
// Always return cleanup function
return () => unsubscribe();
},
});Configuration Options
Prop
Type
The Subscribe Function
The subscribe function is the heart of a trigger node. It sets up event listeners and returns a cleanup function:
Parameters
The subscribe function receives an options object with:
Prop
Type
Return Value
The subscribe function must return a cleanup function (or a promise that resolves to one) that will be called when the workflow stops or reconfigures.
Common Trigger Patterns
Webhook Triggers
Handle incoming HTTP requests:
export const onWebhook = i.nodes.trigger({
inputs: {
secretKey: i.pins.data({
control: i.controls.text({
label: 'Webhook Secret',
description: 'Secret key for webhook verification',
sensitive: true,
}),
}),
},
outputs: {
verified: i.pins.exec({
outputs: {
payload: i.pins.data(),
signature: i.pins.data(),
},
}),
invalid: i.pins.exec(),
},
subscribe({ next, webhook, inputs }) {
const unsubscribe = webhook.subscribe(async (req) => {
try {
const signature = req.headers.get('X-Signature');
const payload = await req.text();
if (!verifySignature(payload, signature, inputs.secretKey)) {
next('invalid');
return new Response('Unauthorized', { status: 401 });
}
const data = JSON.parse(payload);
next('verified', { payload: data, signature });
return new Response('OK');
} catch (error) {
next('invalid');
return new Response('Bad Request', { status: 400 });
}
});
return () => unsubscribe();
},
});Timer Triggers
Execute workflows on a schedule:
export const timerTrigger = i.nodes.trigger({
inputs: {
interval: i.pins.data({
control: i.controls.select({
label: 'Interval',
options: [
{ value: 30, label: '30 seconds' },
{ value: 60, label: '1 minute' },
{ value: 300, label: '5 minutes' },
{ value: 3600, label: '1 hour' },
],
defaultValue: 60,
}),
}),
},
outputs: {
timestamp: i.pins.data({
displayName: 'Timestamp',
description: 'Current timestamp when triggered',
}),
},
subscribe({ next, inputs }) {
const intervalMs = inputs.interval * 1000;
const timer = setInterval(() => {
next({
timestamp: new Date().toISOString(),
});
}, intervalMs);
return () => clearInterval(timer);
},
});External Event Triggers
Listen to external services or databases:
export const databaseTrigger = i.nodes.trigger({
inputs: {
tableName: i.pins.data({
control: i.controls.text({
label: 'Table Name',
placeholder: 'users',
}),
}),
},
outputs: {
newRecord: i.pins.data({
displayName: 'New Record',
description: 'The newly created database record',
}),
},
subscribe({ next, inputs, state }) {
// Listen for database changes
const listener = state.database.listen(inputs.tableName, (change) => {
if (change.type === 'INSERT') {
next({
newRecord: change.record,
});
}
});
return () => listener.stop();
},
});File System Triggers
Monitor file system changes:
export const fileWatcher = i.nodes.trigger({
inputs: {
directory: i.pins.data({
control: i.controls.text({
label: 'Watch Directory',
placeholder: '/uploads',
}),
}),
pattern: i.pins.data({
control: i.controls.text({
label: 'File Pattern',
placeholder: '*.csv',
defaultValue: '*',
}),
}),
},
outputs: {
fileCreated: i.pins.exec({
outputs: {
filePath: i.pins.data(),
fileName: i.pins.data(),
size: i.pins.data(),
},
}),
fileDeleted: i.pins.exec({
outputs: {
filePath: i.pins.data(),
},
}),
},
subscribe({ next, inputs, state }) {
const watcher = state.fileSystem.watch(inputs.directory, {
pattern: inputs.pattern,
});
watcher.on('created', (file) => {
next('fileCreated', {
filePath: file.path,
fileName: file.name,
size: file.size,
});
});
watcher.on('deleted', (file) => {
next('fileDeleted', {
filePath: file.path,
});
});
return () => watcher.close();
},
});Execution Flow Control
Trigger nodes can use execution pins to create conditional or parallel execution paths:
export const conditionalTrigger = i.nodes.trigger({
outputs: {
businessHours: i.pins.exec({
outputs: {
message: i.pins.data(),
},
}),
afterHours: i.pins.exec({
outputs: {
message: i.pins.data(),
},
}),
},
subscribe({ next }) {
const timer = setInterval(() => {
const hour = new Date().getHours();
if (hour >= 9 && hour < 17) {
next('businessHours', {
message: 'Business hours workflow',
});
} else {
next('afterHours', {
message: 'After hours workflow',
});
}
}, 60000);
return () => clearInterval(timer);
},
});State Management
Trigger nodes can access and modify the shared integration state:
export const statefulTrigger = i.nodes.trigger({
outputs: {
event: i.pins.data(),
},
subscribe({ next, state }) {
// Initialize state if needed
if (!state.eventCounter) {
state.eventCounter = 0;
}
const timer = setInterval(() => {
state.eventCounter++;
next({
event: {
id: state.eventCounter,
timestamp: new Date().toISOString(),
},
});
}, 5000);
return () => clearInterval(timer);
},
});Best Practices
Always Provide Cleanup
// Good - Always return cleanup function
subscribe({ next }) {
const timer = setInterval(() => next({}), 1000);
return () => clearInterval(timer);
}
// Bad - No cleanup function
subscribe({ next }) {
setInterval(() => next({}), 1000);
// Memory leak! Timer continues after workflow stops
}Handle Async Cleanup
subscribe({ next, state }) {
state.connection.listen('event', next);
return async () => {
await state.connection.disconnect();
};
}Validate Inputs
subscribe({ next, inputs }) {
if (!inputs.apiKey) {
throw new Error('API key is required');
}
// Continue with setup...
}Use Descriptive Outputs
outputs: {
// Good - Clear and descriptive
userRegistered: i.pins.exec({
outputs: {
userId: i.pins.data(),
email: i.pins.data(),
registrationTime: i.pins.data()
}
}),
// Avoid - Generic names
event: i.pins.exec({
outputs: {
data: i.pins.data()
}
})
}Trigger nodes are the foundation of workflow automation in Xentom, providing the bridge between external events and your business logic. By following these patterns and best practices, you can create robust, reliable triggers that power your automations.
Nodes
Previous Page
Callable Node
Callable nodes are the workhorses of Xentom workflows. They perform operations with side effects, can be invoked by other nodes, and can invoke other nodes in return. Callable nodes represent the main processing steps in a workflow, handling tasks like API calls, data transformations, database operations, and business logic.