WinFactor Docs

CRM Integration Guide

Practical patterns for syncing WinFactor with HubSpot, Salesforce, or any CRM/ERP

Patterns for the four things every CRM integration wants: new business in, contact data in sync, quotes pushed out, and IDs linked both ways. Each pattern works in ActivePieces, in your own services, or as a scheduled script.

Self-configure your connector

Start every integration by reading the organization profile — locale, unit system, and currency drive how you format everything downstream:

curl -s "$WINFACTOR_URL/api/v1/organization" -H "Authorization: Bearer $WINFACTOR_KEY"

Pattern 1 — Submission intake (deals/opportunities)

Trigger: submission.created webhook. Enrich: fetch the full submission — the API adds resolvedConfiguration, the human-readable version of what the customer built (component names, option names, colors, dimensions), perfect for a deal description:

curl -s "$WINFACTOR_URL/api/v1/submissions/$SUBMISSION_ID" \
  -H "Authorization: Bearer $WINFACTOR_KEY"
{
  "id": "k57…",
  "customer": { "name": "Jane Doe", "email": "[email protected]", "phone": "+31 6 …" },
  "dimensions": { "width": 2400, "height": 1800 },
  "resolvedConfiguration": {
    "componentSelections": [
      { "componentName": "Lift-slide door", "componentType": "door",
        "width": 1185, "height": 1740,
        "selectedOptions": [{ "code": "HRPP", "name": "HR++ glass", "optionGroup": "glass" }] }
    ],
    "insideColor": { "name": "Anthracite" }, "outsideColor": { "name": "White" },
    "selectedOptions": [{ "code": "HRPP", "name": "HR++ glass" }], "notes": "…"
  },
  "externalPricing": { "subtotal": 1390.5, "…": "your frozen line items, if the live loop priced it" },
  "latestQuoteId": null,
  "externalRef": null
}

Write back the link: stamp your CRM record ID onto the submission so the relationship survives in both systems:

curl -X PATCH "$WINFACTOR_URL/api/v1/submissions/$SUBMISSION_ID" \
  -H "Authorization: Bearer $WINFACTOR_KEY" -H "Content-Type: application/json" \
  -d '{"externalRef": "hubspot:deal:9912345"}'

Backfill / reconcile: GET /api/v1/submissions?createdAfter=<ms> pages through history — your safety net if a webhook was ever missed.

Pattern 2 — Two-way contact sync

WinFactor auto-creates contacts from submissions. Keep them aligned with your CRM:

  • CRM → WinFactor: upsert by email (idempotent — safe to run on every CRM change):

    curl -X POST "$WINFACTOR_URL/api/v1/contacts" \
      -H "Authorization: Bearer $WINFACTOR_KEY" -H "Content-Type: application/json" \
      -d '{"email": "[email protected]", "name": "Jane Doe", "companyName": "Doe BV",
           "externalRef": "hubspot:contact:3314"}'
  • WinFactor → CRM: on submission.created, look the contact up (GET /api/v1/contacts?email=…); if it has no externalRef, create it in your CRM and PATCH the ref back.

submissionCount and lastUsedAt on each contact tell you who your repeat customers are.

Pattern 3 — Quote lifecycle out

Mirror the quote pipeline into CRM stages using the quote events (quote.createdsentviewedaccepted/rejected/expired) — each maps naturally to a deal stage.

You can also drive quotes from the CRM/ERP:

# Create a draft quote — with YOUR breakdown in one call (no intermediate wrong-priced draft)
curl -X POST "$WINFACTOR_URL/api/v1/submissions/$SUBMISSION_ID/quotes" \
  -H "Authorization: Bearer $WINFACTOR_KEY" -H "Content-Type: application/json" \
  -d '{"lineItems": [
        {"description": "Lift-slide door (SKU WW-451)", "quantity": 2, "unitPrice": 512.0, "itemType": "door"},
        {"description": "Mounting", "quantity": 1, "unitPrice": 250.0, "itemType": "labor"}
      ],
      "reference": "ERP order 5512"}'

# Revise after sending (versions the quote, mirrors in-app editing)
curl -X PUT "$WINFACTOR_URL/api/v1/quotes/$QUOTE_ID/line-items" \
  -H "Authorization: Bearer $WINFACTOR_KEY" -H "Content-Type: application/json" \
  -d '{"revise": true, "lineItems": [ … ]}'

# Send it to the customer (same email path the app uses)
curl -X POST "$WINFACTOR_URL/api/v1/quotes/$QUOTE_ID/send" \
  -H "Authorization: Bearer $WINFACTOR_KEY" -H "Content-Type: application/json" \
  -d '{"recipients": ["[email protected]"]}'

Omit lineItems on create and WinFactor calculates them — preferring any frozen external pricing from the live loop. GET /api/v1/quotes/{id} exposes pdf.status and a download url once the PDF has been generated (PDFs are produced when the quote is prepared or sent in the app) — archive it on the CRM deal.

Pattern 4 — Leads

Contact-form leads from your public page (lead.created event) are fetchable too: GET /api/v1/leads?status=new — route them into your CRM's lead inbox and mark progress in WinFactor from the dashboard.

Operational notes

  • Idempotency: dedup webhooks on X-WinFactor-Delivery; contact upsert is idempotent by email; quote line-item PUT is a full replace.
  • Recovery: the delivery log + redelivery replays anything your endpoint missed; list endpoints with createdAfter reconcile bulk gaps.
  • Linking: externalRef exists on submissions, quotes, contacts, and individual adjustment line items — use a consistent system:type:id convention.
  • Security: verify webhook signatures; use a read-only key for anything that only reads.

On this page