ActivePieces Integration
Automate workflows and connect WinFactor with your favorite tools using ActivePieces
ActivePieces User Guide: Event Data & Integrations
This guide explains how to use WinFactor events in ActivePieces to automate workflows and connect with other tools like CRM, Slack, email, and more.
Good news: The connection between WinFactor and ActivePieces is already set up for you. You can start building workflows right away.
Table of Contents
- Quick Start: Slack Notification
- How It Works
- What Every Event Contains
- Understanding Each Event Type
- More Integration Examples
- Quick Reference
- Tips
Quick Start: Slack Notification
Get notified in Slack when a customer accepts a quote. This takes about 2 minutes to set up.
- In ActivePieces, create a new workflow
- Add a Webhook trigger
- Add a Router step with a branch for
quote.accepted - Add a Slack action in that branch with this message:
Quote accepted! Number: {{ trigger['body']['data']['quote']['number'] }} Customer: {{ trigger['body']['data']['customer']['name'] }} Total: {{ trigger['body']['data']['quote']['currencySymbol'] }}{{ trigger['body']['data']['quote']['total'] }} - Save and turn on the workflow
That's it - you'll now get Slack notifications whenever a quote is accepted.
How It Works
WinFactor sends events to ActivePieces automatically whenever important actions occur. The connection is already configured.
The flow:
Customer accepts quote
↓
WinFactor sends event to ActivePieces
↓
Your workflow runs
↓
Slack message sentWhat you can do:
- Send Slack or Teams notifications for quote events
- Create deals in HubSpot, Salesforce, or Pipedrive
- Send follow-up emails automatically
- Log data to Google Sheets
- Trigger SMS or WhatsApp notifications
What Every Event Contains
Every event from WinFactor follows the same basic structure. Understanding these common pieces of information will help you work with any event type.
Key Information
| Piece of Information | What It Means |
|---|---|
version | Format version of this message (currently "1.0") |
eventType | What happened (e.g., "quote.accepted") |
timestamp | When it happened (date and time) |
orgLocale | Your organization's preferred language ("en", "de", or "nl") |
customerLocale | The customer's language (if applicable) |
organization | Your company information |
data | The actual event information (varies by event type) |
Your Organization Information
Found in every event message:
| Piece of Information | What It Means |
|---|---|
id | Your organization's unique ID |
name | Your organization's display name |
slug | URL-friendly version of your name |
email | Your billing email address |
phone | Your contact phone number |
logoUrl | Link to your logo (if you set one) |
Understanding Each Event Type
WinFactor sends 9 different event types. Each one has a specific purpose and contains the information you need for automating your work.
submission.created
When This Happens: A customer submits a new configuration request through your WinFactor configurator.
Use cases:
- Notify your sales team about a new inquiry
- Create a new lead in your CRM
- Send an acknowledgment email to the customer
- Log the submission to a spreadsheet
Example Data:
Note: This is example data for reference. You don't need to understand JSON to use ActivePieces - just copy the field names you need.
{
"version": "1.0",
"eventType": "submission.created",
"timestamp": 1704556800000,
"orgLocale": "nl",
"customerLocale": "en",
"organization": {
"id": "abc123",
"name": "Facade Solutions Inc.",
"slug": "facade-solutions",
"email": "[email protected]",
"phone": "+31201234567",
"logoUrl": "https://storage.example.com/logo.png"
},
"data": {
"submission": {
"id": "sub_456xyz",
"createdAt": 1704556800000
},
"customer": {
"name": "John Smith",
"email": "[email protected]",
"phone": "+31612345678",
"companyName": null
},
"template": {
"id": "template_789",
"name": "Modern Glass Facade",
"slug": "modern-glass-facade"
},
"configuration": {
"width": 5000,
"height": 3000,
"fragmentCount": 12
},
"urls": {
"submissionDetail": "https://app.winfactor.com/submissions/sub_456xyz"
}
}
}What Each Field Means:
| Field | What It Means |
|---|---|
data.submission.id | Unique ID of the submission |
data.submission.createdAt | When the submission was created |
data.customer.name | Customer's full name |
data.customer.email | Customer's email address |
data.customer.phone | Customer's phone number (null if not provided) |
data.customer.companyName | Customer's company (if provided) |
data.template.name | Name of the product template they configured |
data.configuration.width | Width in millimeters |
data.configuration.height | Height in millimeters |
data.configuration.fragmentCount | Number of components in the configuration |
data.urls.submissionDetail | Link to view the submission in WinFactor |
quote.created
When This Happens: Your team creates a new quote (internal notification - customer hasn't seen it yet).
Use cases:
- Notify the quote creator that it was created successfully
- Create a task for follow-up
- Log to your internal tracking system
Example Data:
Note: This is example data for reference. You don't need to understand JSON to use ActivePieces - just copy the field names you need.
{
"version": "1.0",
"eventType": "quote.created",
"timestamp": 1704556800000,
"orgLocale": "nl",
"organization": {
"id": "abc123",
"name": "Facade Solutions Inc.",
"slug": "facade-solutions",
"email": "[email protected]",
"phone": "+31201234567",
"logoUrl": "https://storage.example.com/logo.png"
},
"data": {
"quote": {
"id": "quote_789",
"number": "Q-2024-0001",
"version": 1,
"status": "draft",
"total": 15000.00,
"currency": "EUR"
},
"submission": {
"id": "sub_456xyz",
"customerName": "John Smith",
"customerEmail": "[email protected]"
},
"lineItems": [
{
"description": "Glass panels - 6mm tempered",
"quantity": 12,
"unitPrice": 500.00,
"total": 6000.00,
"itemType": "material"
},
{
"description": "Installation labor",
"quantity": 1,
"unitPrice": 9000.00,
"total": 9000.00,
"itemType": "labor"
}
],
"urls": {
"quoteDetail": "https://app.winfactor.com/quotes/quote_789"
}
}
}What Each Field Means:
| Field | What It Means |
|---|---|
data.quote.id | Unique ID of the quote |
data.quote.number | Human-readable quote number |
data.quote.version | Version number (starts at 1) |
data.quote.status | Current status ("draft", "sent", "viewed", "accepted", "rejected", "expired") |
data.quote.total | Total price as decimal (e.g., 15000.00 = €15,000.00) |
data.quote.currency | Currency code ("EUR", "USD", "GBP", "CHF") |
data.submission.id | Original submission ID |
data.lineItems | List of items in the quote |
data.lineItems[].description | Description of the line item |
data.lineItems[].quantity | Quantity ordered |
data.lineItems[].unitPrice | Price per unit as decimal |
data.lineItems[].total | Total for this line item as decimal |
data.lineItems[].itemType | Type of item ("material", "labor", "shipping", etc.) or null |
quote.sent
When This Happens: You send a quote to a customer.
Use cases:
- Notify your team that a quote was sent
- Start a follow-up reminder sequence
- Create/update a deal in your CRM with quote details
- Send an internal notification to sales manager
Example Data:
Note: This is example data for reference. You don't need to understand JSON to use ActivePieces - just copy the field names you need.
{
"version": "1.0",
"eventType": "quote.sent",
"timestamp": 1704556800000,
"orgLocale": "nl",
"customerLocale": "en",
"organization": {
"id": "abc123",
"name": "Facade Solutions Inc.",
"slug": "facade-solutions",
"email": "[email protected]",
"phone": "+31201234567",
"logoUrl": "https://storage.example.com/logo.png"
},
"data": {
"quote": {
"id": "quote_789",
"number": "Q-2024-0001",
"version": 1,
"viewToken": "vw_xyz123abc"
},
"submission": {
"id": "sub_456xyz",
"templateName": "Modern Glass Facade",
"dimensions": {
"width": 5000,
"height": 3000
}
},
"customer": {
"name": "John Smith",
"email": "[email protected]",
"phone": "+31612345678",
"companyName": "Smith Construction",
"address": "Main Street 123",
"postalCode": "1234 AB",
"city": "Amsterdam",
"country": "Netherlands"
},
"pricing": {
"subtotal": 12479.00,
"taxRate": 20,
"taxAmount": 2521.00,
"total": 15000.00,
"currency": "EUR",
"currencySymbol": "€"
},
"lineItems": [
{
"description": "Glass panels - 6mm tempered",
"quantity": 12,
"unitPrice": 500.00,
"total": 6000.00,
"itemType": "material"
}
],
"validity": {
"validUntil": 1707148800000,
"validUntilFormatted": "05-02-2024"
},
"notes": "Installation requires scaffolding.",
"terms": "Payment due within 14 days of acceptance.",
"urls": {
"viewQuote": "https://app.winfactor.com/quote/view/vw_xyz123abc",
"pdfDownload": null
},
"sentTo": ["[email protected]", "[email protected]"]
}
}What Each Field Means:
| Field | What It Means |
|---|---|
data.quote.viewToken | Token for public quote access |
data.submission.templateName | Name of the product template |
data.submission.dimensions.width | Width in millimeters |
data.submission.dimensions.height | Height in millimeters |
data.customer.address | Customer's address (null if not provided) |
data.customer.postalCode | Postal/ZIP code (null if not provided) |
data.customer.city | City (null if not provided) |
data.customer.country | Country (null if not provided) |
data.pricing.subtotal | Subtotal as decimal |
data.pricing.taxRate | Tax percentage (e.g., 20 = 20%) |
data.pricing.taxAmount | Tax amount as decimal |
data.pricing.currencySymbol | Symbol for display ("€", "$", "£", "Fr") |
data.validity.validUntil | When quote expires (timestamp) |
data.validity.validUntilFormatted | Expiry date in DD-MM-YYYY format |
data.notes | Notes added to the quote (null if not provided) |
data.terms | Payment terms (null if not provided) |
data.urls.viewQuote | Public URL for customer to view quote |
data.urls.pdfDownload | PDF download URL (if available) |
data.sentTo | List of email addresses quote was sent to |
quote.viewed
When This Happens: A customer opens a quote link (fires only once - the first time they view it).
Use cases:
- Notify sales team that customer is interested
- Start a follow-up sequence ("I see you viewed our quote...")
- Update CRM deal stage to "Quote Viewed"
Example Data:
Note: This is example data for reference. You don't need to understand JSON to use ActivePieces - just copy the field names you need.
{
"version": "1.0",
"eventType": "quote.viewed",
"timestamp": 1704556800000,
"orgLocale": "nl",
"customerLocale": "en",
"organization": {
"id": "abc123",
"name": "Facade Solutions Inc.",
"slug": "facade-solutions",
"email": "[email protected]",
"phone": "+31201234567",
"logoUrl": "https://storage.example.com/logo.png"
},
"data": {
"quote": {
"id": "quote_789",
"number": "Q-2024-0001",
"total": 15000.00,
"currency": "EUR"
},
"customer": {
"name": "John Smith",
"email": "[email protected]"
},
"viewedAt": 1704556800000,
"urls": {
"quoteDetail": "https://app.winfactor.com/quotes/quote_789"
}
}
}What Each Field Means:
| Field | What It Means |
|---|---|
data.viewedAt | When the customer viewed the quote |
data.quote.number | Quote number for easy reference |
data.quote.total | Total value as decimal |
data.quote.currency | Currency code |
quote.accepted
When This Happens: A customer accepts and signs a quote.
Use cases:
- Notify your team to start production
- Create an order in your ERP system
- Send a confirmation email to the customer
- Update CRM deal to "Closed Won"
- Trigger project management workflows
Example Data:
Note: This is example data for reference. You don't need to understand JSON to use ActivePieces - just copy the field names you need.
{
"version": "1.0",
"eventType": "quote.accepted",
"timestamp": 1704556800000,
"orgLocale": "nl",
"customerLocale": "en",
"organization": {
"id": "abc123",
"name": "Facade Solutions Inc.",
"slug": "facade-solutions",
"email": "[email protected]",
"phone": "+31201234567",
"logoUrl": "https://storage.example.com/logo.png"
},
"data": {
"quote": {
"id": "quote_789",
"number": "Q-2024-0001",
"version": 1,
"total": 15000.00,
"currency": "EUR",
"currencySymbol": "€"
},
"customer": {
"name": "John Smith",
"email": "[email protected]",
"phone": "+31612345678",
"companyName": "Smith Construction"
},
"acceptance": {
"acceptedAt": 1704556800000,
"acceptedByName": "John Smith",
"ipAddress": "203.0.113.42",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)..."
},
"urls": {
"quoteDetail": "https://app.winfactor.com/quotes/quote_789",
"submissionDetail": "https://app.winfactor.com/submissions/sub_456xyz"
}
}
}What Each Field Means:
| Field | What It Means |
|---|---|
data.acceptance.acceptedAt | When the quote was accepted |
data.acceptance.acceptedByName | Name of person who accepted (null if not provided) |
data.acceptance.ipAddress | IP address of the acceptor (for audit trail) |
data.acceptance.userAgent | Browser/device information |
data.urls.submissionDetail | Link to the original submission |
quote.rejected
When This Happens: A customer rejects a quote.
Use cases:
- Notify sales team to follow up
- Update CRM deal to "Closed Lost"
- Send a feedback request email
- Log rejection reason for analysis
Example Data:
Note: This is example data for reference. You don't need to understand JSON to use ActivePieces - just copy the field names you need.
{
"version": "1.0",
"eventType": "quote.rejected",
"timestamp": 1704556800000,
"orgLocale": "nl",
"customerLocale": "en",
"organization": {
"id": "abc123",
"name": "Facade Solutions Inc.",
"slug": "facade-solutions",
"email": "[email protected]",
"phone": "+31201234567",
"logoUrl": "https://storage.example.com/logo.png"
},
"data": {
"quote": {
"id": "quote_789",
"number": "Q-2024-0001",
"total": 15000.00,
"currency": "EUR"
},
"customer": {
"name": "John Smith",
"email": "[email protected]"
},
"rejection": {
"rejectedAt": 1704556800000,
"reason": "Price is too high. We found a cheaper alternative.",
"ipAddress": "203.0.113.42",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)..."
},
"urls": {
"quoteDetail": "https://app.winfactor.com/quotes/quote_789"
}
}
}What Each Field Means:
| Field | What It Means |
|---|---|
data.rejection.rejectedAt | When the quote was rejected |
data.rejection.reason | Customer's reason for rejecting (null if not provided) |
data.rejection.ipAddress | IP address for audit trail |
data.rejection.userAgent | Browser/device information |
quote.expiring_soon
When This Happens: A quote is about to expire in 3 days. This check runs daily at 9 AM UTC.
Use cases:
- Send a reminder email to the customer
- Notify sales to follow up before expiry
- Update CRM with upcoming expiry alert
Example Data:
Note: This is example data for reference. You don't need to understand JSON to use ActivePieces - just copy the field names you need.
{
"version": "1.0",
"eventType": "quote.expiring_soon",
"timestamp": 1704556800000,
"orgLocale": "nl",
"customerLocale": "en",
"organization": {
"id": "abc123",
"name": "Facade Solutions Inc.",
"slug": "facade-solutions",
"email": "[email protected]",
"phone": "+31201234567",
"logoUrl": "https://storage.example.com/logo.png"
},
"data": {
"quote": {
"id": "quote_789",
"number": "Q-2024-0001",
"total": 15000.00,
"currency": "EUR",
"currencySymbol": "€",
"viewToken": "vw_xyz123abc"
},
"customer": {
"name": "John Smith",
"email": "[email protected]"
},
"expiry": {
"validUntil": 1704816000000,
"validUntilFormatted": "08-02-2024",
"daysRemaining": 3
},
"urls": {
"viewQuote": "https://app.winfactor.com/quote/view/vw_xyz123abc"
}
}
}What Each Field Means:
| Field | What It Means |
|---|---|
data.expiry.validUntil | When the quote expires (timestamp) |
data.expiry.validUntilFormatted | Expiry date in DD-MM-YYYY format |
data.expiry.daysRemaining | Always 3 (this event fires 3 days before expiry) |
data.urls.viewQuote | Public URL for the quote |
quote.expired
When This Happens: A quote has expired (check runs every 6 hours).
Use cases:
- Archive expired quotes in your CRM
- Send a "would you like to renew?" email
- Update internal reporting
Example Data:
Note: This is example data for reference. You don't need to understand JSON to use ActivePieces - just copy the field names you need.
{
"version": "1.0",
"eventType": "quote.expired",
"timestamp": 1704556800000,
"orgLocale": "nl",
"customerLocale": "en",
"organization": {
"id": "abc123",
"name": "Facade Solutions Inc.",
"slug": "facade-solutions",
"email": "[email protected]",
"phone": "+31201234567",
"logoUrl": "https://storage.example.com/logo.png"
},
"data": {
"quote": {
"id": "quote_789",
"number": "Q-2024-0001",
"total": 15000.00,
"currency": "EUR"
},
"customer": {
"name": "John Smith",
"email": "[email protected]"
},
"expiry": {
"validUntil": 1704556800000,
"expiredAt": 1704556800000
},
"urls": {
"quoteDetail": "https://app.winfactor.com/quotes/quote_789"
}
}
}What Each Field Means:
| Field | What It Means |
|---|---|
data.expiry.validUntil | When the quote was set to expire |
data.expiry.expiredAt | When the expiry was detected |
lead.created
When This Happens: Someone submits a contact form through your organization's public page.
Use cases:
- Notify sales team of new lead
- Create lead in CRM
- Send auto-responder email
- Post to a Slack channel for quick follow-up
Example Data:
Note: This is example data for reference. You don't need to understand JSON to use ActivePieces - just copy the field names you need.
{
"version": "1.0",
"eventType": "lead.created",
"timestamp": 1704556800000,
"orgLocale": "nl",
"customerLocale": "nl",
"organization": {
"id": "abc123",
"name": "Facade Solutions Inc.",
"slug": "facade-solutions",
"email": "[email protected]",
"phone": "+31201234567",
"logoUrl": null
},
"data": {
"lead": {
"id": "lead_123",
"createdAt": 1704556800000
},
"contact": {
"name": "Jane Johnson",
"email": "[email protected]",
"phone": "+31698765432",
"message": "Hi, we're interested in your glass facades for a new project. Can you send us a catalog?",
"messagePreview": "Hi, we're interested in your glass facades for a new project. Can you send..."
},
"urls": {
"leadsPage": "https://app.winfactor.com/leads"
}
}
}What Each Field Means:
| Field | What It Means |
|---|---|
data.lead.id | Unique ID of the lead |
data.lead.createdAt | When the lead was created |
data.contact.name | Contact person's name |
data.contact.email | Contact's email |
data.contact.phone | Phone number (null if not provided) |
data.contact.message | Full message from contact form |
data.contact.messagePreview | First 100 characters of message |
data.urls.leadsPage | Link to leads page in WinFactor |
More Integration Examples
Here are more ways to use WinFactor events in ActivePieces with popular services.
Slack: Notifications for Accepted and Rejected Quotes
Get notified in Slack when quotes are accepted or rejected.
Steps:
- In your Router, add a branch for
quote.accepted - Add a Slack action with this message:
Quote accepted! Number: {{ trigger['body']['data']['quote']['number'] }} Customer: {{ trigger['body']['data']['customer']['name'] }} Total: {{ trigger['body']['data']['quote']['currencySymbol'] }}{{ trigger['body']['data']['quote']['total'] }} - Add another branch for
quote.rejectedwith:Quote rejected Number: {{ trigger['body']['data']['quote']['number'] }} Customer: {{ trigger['body']['data']['customer']['name'] }} Reason: {{ trigger['body']['data']['rejection']['reason'] }}
HubSpot: Create Deals from Quotes
Create a new deal in HubSpot when a quote is sent, then update it when accepted.
Branch for quote.sent:
- Create a HubSpot deal with:
- Name: Use the quote number and customer name from the event data
- Amount: Use
trigger['body']['data']['pricing']['total'] - Stage: "Quote Sent"
Branch for quote.accepted:
- Find the deal by quote ID
- Update the deal stage to "Closed Won"
Email: Automated Follow-Up
Send a follow-up email 3 days after a quote is sent.
Steps:
- In the
quote.sentbranch, add a delay step - Add an email action with:
- To: Use
trigger['body']['data']['customer']['email'] - Subject: Include the quote number from the event
- Body: Include the quote link from
trigger['body']['data']['urls']['viewQuote']
- To: Use
Google Sheets: Log All Submissions
Keep a record of all submissions in a Google Sheet.
Branch for submission.created:
- Add a row to your sheet with:
- Date: Use
trigger['body']['timestamp'] - Customer: Use
trigger['body']['data']['customer']['name'] - Email: Use
trigger['body']['data']['customer']['email'] - Template: Use
trigger['body']['data']['template']['name'] - Dimensions: Combine width and height from the configuration
- Date: Use
Microsoft Teams: High-Value Quote Alerts
Post to Teams when a quote over a certain amount is accepted.
Steps:
- In the
quote.acceptedbranch, add a condition - Check if total amount is greater than your threshold
- Post a message with quote details and link
Quick Reference
| Event Type | When It Fires | Key Data Available | Common Use Cases |
|---|---|---|---|
submission.created | Customer submits configuration | Customer info, template, dimensions | Create CRM lead, notify sales team |
quote.created | Team creates quote | Quote number, line items, total | Internal notification, task creation |
quote.sent | Quote sent to customer | Full quote details, pricing, validity | Update CRM, start follow-up sequence |
quote.viewed | Customer opens quote (first time) | Quote number, customer, total | Notify sales, update deal stage |
quote.accepted | Customer accepts quote | Quote details, acceptance info | Start production, create order, "Closed Won" |
quote.rejected | Customer rejects quote | Quote details, rejection reason | Follow up, update CRM, analyze feedback |
quote.expiring_soon | 3 days before expiry (daily check) | Quote details, expiry date | Send reminder, notify sales |
quote.expired | Quote has expired (every 6 hours) | Quote details, expiry info | Archive, renewal offer |
lead.created | Contact form submitted | Contact info, message | Create lead, auto-responder, Slack notification |
Tips
- Use a Router: Add a Router step to handle different event types in branches
- Test your workflows: Use the example data in this document to test before going live
- Check for empty fields: Some fields may be empty - check before using them in your workflow
- Format dates: Convert timestamps to readable dates using date formatting
- Format currency: Combine the symbol and amount from the event data
- Handle errors: Add error handling steps to catch and log any issues
- Use branches: Each event type gets its own branch in the Router
- Remember information: Use ActivePieces memory to track information between events (like which quotes have been viewed)