WinFactor Docs

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

Get notified in Slack when a customer accepts a quote. This takes about 2 minutes to set up.

  1. In ActivePieces, create a new workflow
  2. Add a Webhook trigger
  3. Add a Router step with a branch for quote.accepted
  4. 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'] }}
  5. 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 sent

What 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 InformationWhat It Means
versionFormat version of this message (currently "1.0")
eventTypeWhat happened (e.g., "quote.accepted")
timestampWhen it happened (date and time)
orgLocaleYour organization's preferred language ("en", "de", or "nl")
customerLocaleThe customer's language (if applicable)
organizationYour company information
dataThe actual event information (varies by event type)

Your Organization Information

Found in every event message:

Piece of InformationWhat It Means
idYour organization's unique ID
nameYour organization's display name
slugURL-friendly version of your name
emailYour billing email address
phoneYour contact phone number
logoUrlLink 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:

FieldWhat It Means
data.submission.idUnique ID of the submission
data.submission.createdAtWhen the submission was created
data.customer.nameCustomer's full name
data.customer.emailCustomer's email address
data.customer.phoneCustomer's phone number (null if not provided)
data.customer.companyNameCustomer's company (if provided)
data.template.nameName of the product template they configured
data.configuration.widthWidth in millimeters
data.configuration.heightHeight in millimeters
data.configuration.fragmentCountNumber of components in the configuration
data.urls.submissionDetailLink 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:

FieldWhat It Means
data.quote.idUnique ID of the quote
data.quote.numberHuman-readable quote number
data.quote.versionVersion number (starts at 1)
data.quote.statusCurrent status ("draft", "sent", "viewed", "accepted", "rejected", "expired")
data.quote.totalTotal price as decimal (e.g., 15000.00 = €15,000.00)
data.quote.currencyCurrency code ("EUR", "USD", "GBP", "CHF")
data.submission.idOriginal submission ID
data.lineItemsList of items in the quote
data.lineItems[].descriptionDescription of the line item
data.lineItems[].quantityQuantity ordered
data.lineItems[].unitPricePrice per unit as decimal
data.lineItems[].totalTotal for this line item as decimal
data.lineItems[].itemTypeType 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:

FieldWhat It Means
data.quote.viewTokenToken for public quote access
data.submission.templateNameName of the product template
data.submission.dimensions.widthWidth in millimeters
data.submission.dimensions.heightHeight in millimeters
data.customer.addressCustomer's address (null if not provided)
data.customer.postalCodePostal/ZIP code (null if not provided)
data.customer.cityCity (null if not provided)
data.customer.countryCountry (null if not provided)
data.pricing.subtotalSubtotal as decimal
data.pricing.taxRateTax percentage (e.g., 20 = 20%)
data.pricing.taxAmountTax amount as decimal
data.pricing.currencySymbolSymbol for display ("€", "$", "£", "Fr")
data.validity.validUntilWhen quote expires (timestamp)
data.validity.validUntilFormattedExpiry date in DD-MM-YYYY format
data.notesNotes added to the quote (null if not provided)
data.termsPayment terms (null if not provided)
data.urls.viewQuotePublic URL for customer to view quote
data.urls.pdfDownloadPDF download URL (if available)
data.sentToList 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:

FieldWhat It Means
data.viewedAtWhen the customer viewed the quote
data.quote.numberQuote number for easy reference
data.quote.totalTotal value as decimal
data.quote.currencyCurrency 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:

FieldWhat It Means
data.acceptance.acceptedAtWhen the quote was accepted
data.acceptance.acceptedByNameName of person who accepted (null if not provided)
data.acceptance.ipAddressIP address of the acceptor (for audit trail)
data.acceptance.userAgentBrowser/device information
data.urls.submissionDetailLink 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:

FieldWhat It Means
data.rejection.rejectedAtWhen the quote was rejected
data.rejection.reasonCustomer's reason for rejecting (null if not provided)
data.rejection.ipAddressIP address for audit trail
data.rejection.userAgentBrowser/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:

FieldWhat It Means
data.expiry.validUntilWhen the quote expires (timestamp)
data.expiry.validUntilFormattedExpiry date in DD-MM-YYYY format
data.expiry.daysRemainingAlways 3 (this event fires 3 days before expiry)
data.urls.viewQuotePublic 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:

FieldWhat It Means
data.expiry.validUntilWhen the quote was set to expire
data.expiry.expiredAtWhen 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:

FieldWhat It Means
data.lead.idUnique ID of the lead
data.lead.createdAtWhen the lead was created
data.contact.nameContact person's name
data.contact.emailContact's email
data.contact.phonePhone number (null if not provided)
data.contact.messageFull message from contact form
data.contact.messagePreviewFirst 100 characters of message
data.urls.leadsPageLink 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:

  1. In your Router, add a branch for quote.accepted
  2. 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'] }}
  3. Add another branch for quote.rejected with:
    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:

  1. 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:

  1. Find the deal by quote ID
  2. Update the deal stage to "Closed Won"

Email: Automated Follow-Up

Send a follow-up email 3 days after a quote is sent.

Steps:

  1. In the quote.sent branch, add a delay step
  2. 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']

Google Sheets: Log All Submissions

Keep a record of all submissions in a Google Sheet.

Branch for submission.created:

  1. 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

Microsoft Teams: High-Value Quote Alerts

Post to Teams when a quote over a certain amount is accepted.

Steps:

  1. In the quote.accepted branch, add a condition
  2. Check if total amount is greater than your threshold
  3. Post a message with quote details and link

Quick Reference

Event TypeWhen It FiresKey Data AvailableCommon Use Cases
submission.createdCustomer submits configurationCustomer info, template, dimensionsCreate CRM lead, notify sales team
quote.createdTeam creates quoteQuote number, line items, totalInternal notification, task creation
quote.sentQuote sent to customerFull quote details, pricing, validityUpdate CRM, start follow-up sequence
quote.viewedCustomer opens quote (first time)Quote number, customer, totalNotify sales, update deal stage
quote.acceptedCustomer accepts quoteQuote details, acceptance infoStart production, create order, "Closed Won"
quote.rejectedCustomer rejects quoteQuote details, rejection reasonFollow up, update CRM, analyze feedback
quote.expiring_soon3 days before expiry (daily check)Quote details, expiry dateSend reminder, notify sales
quote.expiredQuote has expired (every 6 hours)Quote details, expiry infoArchive, renewal offer
lead.createdContact form submittedContact info, messageCreate 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)

On this page