Using Transformations
This guide walks you through creating, testing, and managing transformations for your webhook connections.
Prerequisites
Before you begin, ensure you have:
- A Hooklistener account on the Team or Enterprise plan
- API access token (available in your account settings)
- At least one Connection created
- Basic JavaScript knowledge
Creating Your First Transformation
Step 1: Write Your Transformation Code
Start with a simple transformation that adds a timestamp to your webhook:
addHandler('transform', async (request, context) => {
// Add a processing timestamp
return {
...request,
body: {
...request.body,
processed_at: new Date().toISOString(),
processor: 'Hooklistener'
}
};
});
Step 2: Create the Transformation via API
Use the Transformations API to create your transformation:
curl -X POST https://api.hooklistener.com/api/v1/transformations \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"transformation": {
"name": "Add Processing Timestamp",
"description": "Adds timestamp and processor info to webhooks",
"code": "addHandler('\''transform'\'', async (request, context) => { return { ...request, body: { ...request.body, processed_at: new Date().toISOString(), processor: '\''Hooklistener'\'' } }; });"
}
}'
The API will return:
{
"data": {
"id": "trans_abc123",
"name": "Add Processing Timestamp",
"description": "Adds timestamp and processor info to webhooks",
"organization_id": "org_xyz789",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}
}
Step 3: Attach to a Connection
Once created, attach the transformation to a Connection destination through the Connection management interface or API.
Testing Transformations
Using the Test Endpoint
Before deploying a transformation to production, test it with sample data:
curl -X POST https://api.hooklistener.com/api/v1/transformations/test \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"transformation": {
"code": "addHandler('\''transform'\'', (req) => ({ ...req, body: { ...req.body, test: true } }));"
},
"request": {
"method": "POST",
"url": "https://example.com/webhook",
"headers": {
"content-type": "application/json"
},
"body": {
"event": "user.created",
"user_id": 12345
}
}
}'
Response:
{
"data": {
"result": {
"method": "POST",
"url": "https://example.com/webhook",
"headers": {
"content-type": "application/json"
},
"body": {
"event": "user.created",
"user_id": 12345,
"test": true
}
}
}
}
Debugging with Console Logs
Use console.log()
to debug your transformation:
addHandler('transform', async (request, context) => {
console.log('Incoming request:', JSON.stringify(request));
console.log('Organization:', context.organizationId);
// Your transformation logic
const modified = {
...request,
body: {
...request.body,
debug: 'transformation applied'
}
};
console.log('Modified request:', JSON.stringify(modified));
return modified;
});
Console output appears in transformation logs for debugging.
Managing Transformations
List All Transformations
Get all transformations for your organization:
curl -X GET https://api.hooklistener.com/api/v1/transformations \
-H "Authorization: Bearer YOUR_API_TOKEN"
Get Transformation Details
Retrieve a specific transformation including its code:
curl -X GET https://api.hooklistener.com/api/v1/transformations/trans_abc123 \
-H "Authorization: Bearer YOUR_API_TOKEN"
Update a Transformation
Modify an existing transformation:
curl -X PATCH https://api.hooklistener.com/api/v1/transformations/trans_abc123 \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"transformation": {
"name": "Enhanced Timestamp Transform",
"code": "addHandler('\''transform'\'', async (request, context) => { /* new code */ });"
}
}'
Delete a Transformation
Remove a transformation (cannot be undone):
curl -X DELETE https://api.hooklistener.com/api/v1/transformations/trans_abc123 \
-H "Authorization: Bearer YOUR_API_TOKEN"
Working with Secrets
Setting Up Secrets
First, create secrets for your organization through the Secrets API:
curl -X POST https://api.hooklistener.com/api/v1/secrets \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"secret": {
"name": "SLACK_TOKEN",
"value": "xoxb-your-slack-token"
}
}'
Using Secrets in Transformations
Access secrets via process.env
:
addHandler('transform', async (request, context) => {
// Access your organization's secrets
const slackToken = process.env.SLACK_TOKEN;
const apiKey = process.env.API_KEY;
if (!slackToken) {
console.log('Warning: SLACK_TOKEN not configured');
}
return {
...request,
headers: {
...request.headers,
'Authorization': `Bearer ${slackToken}`
}
};
});
Monitoring Transformation Execution
View Execution Logs
Get logs for a specific transformation:
curl -X GET https://api.hooklistener.com/api/v1/transformations/trans_abc123/logs \
-H "Authorization: Bearer YOUR_API_TOKEN"
Response includes:
{
"data": [
{
"id": "log_def456",
"transformation_id": "trans_abc123",
"status": "success",
"execution_time_ms": 45,
"memory_used_mb": 12,
"input_size_bytes": 1024,
"output_size_bytes": 1156,
"executed_at": "2024-01-15T11:00:00Z"
}
]
}
Get Detailed Log Entry
Retrieve full details including input/output:
curl -X GET https://api.hooklistener.com/api/v1/transformations/trans_abc123/logs/log_def456 \
-H "Authorization: Bearer YOUR_API_TOKEN"
Best Practices
1. Validate Input Data
Always validate incoming data:
addHandler('transform', async (request, context) => {
// Validate required fields
if (!request.body || typeof request.body !== 'object') {
console.log('Invalid body, returning original request');
return request;
}
if (!request.body.event_type) {
console.log('Missing event_type, skipping transformation');
return request;
}
// Proceed with transformation
return {
...request,
body: {
...request.body,
validated: true
}
};
});
2. Handle Errors Gracefully
Use try-catch blocks for robust error handling:
addHandler('transform', async (request, context) => {
try {
// Potentially error-prone transformation
const parsed = JSON.parse(request.body.data);
return {
...request,
body: {
...request.body,
parsed_data: parsed
}
};
} catch (error) {
console.log('Error parsing data:', error.message);
// Return original request on error
return request;
}
});
3. Optimize for Performance
Keep transformations lightweight:
addHandler('transform', async (request, context) => {
// Avoid expensive operations
// ❌ Don't do this:
// for (let i = 0; i < 1000000; i++) { /* ... */ }
// ✅ Do this instead:
const filtered = request.body.items
?.filter(item => item.active)
?.slice(0, 100); // Limit processing
return {
...request,
body: {
...request.body,
filtered_items: filtered || []
}
};
});
4. Use Meaningful Logging
Add contextual logging for debugging:
addHandler('transform', async (request, context) => {
const startTime = Date.now();
console.log(`Processing ${request.method} request for org ${context.organizationId}`);
// Transformation logic
const result = {
...request,
body: transformPayload(request.body)
};
const duration = Date.now() - startTime;
console.log(`Transformation completed in ${duration}ms`);
return result;
});
Common Issues and Solutions
Issue: "No handler registered"
Solution: Ensure you call addHandler('transform', ...)
in your code.
Issue: Timeout errors
Solution: Optimize your code or break complex transformations into simpler ones.
Issue: Memory limit exceeded
Solution: Reduce data processing or filter large arrays before processing.
Issue: Secrets not available
Solution: Verify secrets are created for your organization and named correctly.
Next Steps
Now that you understand how to use transformations:
- Explore real-world examples for inspiration
- Review the API reference for complete endpoint documentation
- Set up monitoring for production transformations
- Learn about advanced patterns for complex use cases
Transformations are a powerful tool for webhook automation. Start simple, test thoroughly, and gradually build more complex transformations as needed.