How to Integrate Enerflo with my CRM
Overview
This guide is designed for Enerflo Partners building custom integrations with the Enerflo platform using Enerflo's APIs and Webhook Events. We'll walk through common business use cases and best practices to help make the integration more approachable. Not every stage will apply to every use case — review each one and implement what's relevant to your objectives.
⚠️ This guide covers the Enerflo side of the integration — data exchanges, endpoints, and events. CRM-specific connectors, field mapping, and surrounding business logic are outside its scope and are left to your team.
💡 If you're interested in engaging Enerflo's Professional Services team for a custom integration, please reach out to Enerflo Support to schedule a free discovery conversation.
Before You Begin
Before starting your integration, make sure you have the following in place:
- Enerflo API credentials — You'll need an API key to authenticate REST API requests. Contact Enerflo Support if you don't have one yet.
- Webhook Event Subscription — Any outbound data flow (Enerflo → 3rd-party) requires an active webhook subscription. See Enerflo 1.0 Events or Enerflo 2.0 Events to set one up.
- A middleware or integration platform (optional but recommended) — Tools like Zapier, Make, or a custom service can simplify data mapping and transformation between Enerflo and your CRM.
- Familiarity with your CRM's API — This guide covers the Enerflo side only. Your team will need to handle the corresponding CRM-side logic.
New integrations should use Enerflo 2.0 Events where available. v1 events are still supported but v2 events offer richer payloads and improved reliability. Each stage below notes which version applies.
Integration Flow
The six stages below represent the full lifecycle of a solar project — from lead capture through change orders. They are designed to be implemented independently, so you only build what your use case requires.
flowchart LR
S1[Stage 1: Leads] --> S2[Stage 2: Project Submission]
S2 --> S3[Stage 3: Milestones]
S3 --> S4[Stage 4: Statuses]
S4 --> S5[Stage 5: Notes]
S5 --> S6[Stage 6: Change Orders]
Which Stages Do I Need?
Use the table below to identify which stages are most relevant to your integration scenario.
| Scenario | Recommended Stages |
|---|---|
| My CRM is the source of truth for leads and I want to push them into Enerflo | 1.1 |
| Enerflo creates customers and I want them synced to my CRM | 1.2 |
| I want to notify my CRM when a project is submitted or received | 2 |
| My CRM tracks installation milestones and should update Enerflo | 3.1 |
| Enerflo tracks milestones and should update my CRM | 3.2 |
| I need to update an Enerflo project status from my CRM | 4.1 |
| I need my CRM to react when an Enerflo project status changes | 4.2 |
| I want project notes to sync from my CRM into Enerflo | 5.1 |
| I want Enerflo project notes to appear in my CRM | 5.2 |
| I need my CRM to reflect signed change orders from Enerflo | 6 |
Glossary of Common Stages
| Stage | Description |
|---|---|
| Stage 1: Leads | Get your lead/customer data into Enerflo to work and sign a deal. |
| Stage 2: Enerflo Project Submission & Resubmission | When a contract is signed and a project is ready to proceed to installation, ship your Enerflo data to an external system. |
| Stage 3: Updating Install Project Milestones | As project milestones are reached during installation, keep CRMs and Enerflo milestone synchronized. |
| Stage 4: Updating Install Project Statuses | As the overall status of the install project changes, keep CRMs and Enerflo's project status synchronized. |
| Stage 5: Updating Install Project Notes | Keep project notes synchronized between your CRM and Enerflo. |
| Stage 6: Change Orders | Process equipment or adder changes to an existing signed agreement. |
Stage 1: Leads
1.1) 3rd-party >> Enerflo
Use case | Push lead & customer information from a 3rd-party into Enerflo |
Source of truth | 3rd-party |
Data destination | Enerflo |
Data exchange tool | Enerflo REST API: POST: /api/v1/partner/action/lead/add |
Resources | Documentation for /api/v1/partner/action/lead/addNotable callout: this endpoint is multi-faceted and can also be used to create an appointment or to start a deal associated with the new lead. |
Trigger | Determined by the user or 3rd-party |
Possible design patterns | WHEN a webform processes a new lead, THEN deliver the lead to Enerflo WHEN the status of a lead in my CRM is changed to 'qualified', THEN deliver the lead to Enerflo and create a deal. |
Data handling tips | Ensure all required fields (first name, last name, email, address) are present and validated before sending. Phone numbers should be formatted as digits only with no dashes or parentheses. |
Example request body:
{
"first_name": "Jane",
"last_name": "Doe",
"email": "[email protected]",
"phone": "5551234567",
"address": "123 Solar Way",
"city": "San Diego",
"state": "CA",
"zip": "92101"
}Fields shown are illustrative. See the full endpoint documentation for all available fields and requirements.
1.2) Enerflo >> 3rd-party
Use case | Push lead & customer information from Enerflo to a 3rd-party |
Source of truth | Enerflo |
Data destination | 3rd-party (such as CRM) |
Data exchange tool | Enerflo Event (such as v1 new_customer) |
Resources | Definition of Enerflo 1.0 Events Definition of Enerflo 2.0 Events Create an Event Subscription in Enerflo 1.0 or Enerflo 2.0 |
Trigger | Enerflo event * *Requires an active Enerflo Webhook Event Subscription |
Possible design patterns | WHEN a new_customer event occurs in Enerflo, THEN push the lead to my CRM. |
Data handling tips | The event payload contains customer contact and address data. Map fields to your CRM's schema before writing — field names and formats will differ between systems. |
Example event payload:
{
"webhook_event": "new_customer",
"id": 2860314,
"external_id": null,
"first_name": "Test",
"last_name": "RCustomer",
"full_name": "Test RCustomer",
"email": "[email protected]",
"phone": "(000) 000-0000",
"address": {
"street": "123 Example St",
"city": "Sample City",
"state": "EX",
"zip": "12345",
"county": "Example County",
"full_address": "123 Example St, Sample City, EX 12345",
"latitude": 12.345678,
"longitude": -98.765432
},
"customer_timezone": "America/Chicago",
"lead_source": "",
"timestamps": {
"deleted_at": null,
"created_at": "2025-01-14 15:47:29",
"updated_at": "2025-01-14 15:47:29",
"timezone": "UTC"
}
}See the Enerflo 1.0 Events documentation for the full payload schema.
Stage 2: Enerflo Project Submission & Resubmission
When a deal in Enerflo satisfies all submission requirements and is submitted by a user, Enerflo fires project submission events. This stage covers how to receive those events and push the project data to your CRM.
Use case | Push data from an Enerflo Install Project to a 3rd-party when a project is submitted or resubmitted |
Source of truth | Enerflo |
Data destination | 3rd-party (such as CRM) |
Data exchange tool | Enerflo 2.0 Event |
Resources | Definition of Enerflo 2.0 Events Create an Event Subscription in Enerflo 2.0 |
Trigger | Enerflo 2.0 event(s) *:deal.projectReceived — For installer organizations, indicating a project has been received from an internal or external sales organization.deal.projectSubmitted — For sales organizations, indicating a project has been submitted to an installer organization.*Requires an active Enerflo Webhook Event Subscription These events fire when a deal is submitted via the Enerflo UI (see Figure 2.1.1 below). If an install has been voided and is now being resigned, the Re-submit action (Figure 2.1.2) will trigger both projectSubmitted and projectReceived. |
Possible design patterns | As a Sales Org, WHEN we submit a project to one of our Installers, THEN push the install to my CRM. As an Installer, WHEN a Sales Org submits a project for me to fulfill, THEN push the install to my CRM and email my Ops Director. WHEN a previously voided install has been resigned and re-submitted, THEN push the newest resigned information to my CRM. |
Data handling tips | 👀 The project submission event payload includes a payload.deal.id field. In many cases you'll want to hydrate this with a follow-up API call to retrieve the full install object:Step 1: Receive the projectSubmitted or projectReceived event.Step 2: Extract the v2 deal ID from payload.deal.id.Step 3: Use that ID in a GET request to api/v3/installs/find/{id} to retrieve the complete install object. (Documentation) |
Example event payload (deal.projectSubmitted):
{
"event": "deal.projectSubmitted",
"payload": {
"targetOrg": "88888888-0e5f-4996-8f74-28c75ddb48b9",
"initiatedBy": "296af00b-3c04-45bd-82a4-a2ece88171eb",
"deal": {
"id": "59886cce-2504-4da8-b63a-25b088e97b46",
"shortCode": "b9sqedcvp",
"state": {
"hasSubmittedProject": true,
"hasApprovedDesign": true,
"hasCreatedProposal": true
}
},
"customer": {
"id": "f6ac5e81-ef2d-4981-863a-86bbb4590601",
"firstName": "Firsty",
"lastName": "Lasty"
}
}
}Example hydration request (Step 3):
GET /api/v3/installs/find/59886cce-2504-4da8-b63a-25b088e97b46See the Enerflo 2.0 Events documentation for the full payload schema, including
deal.projectReceived.
Stage 3: Updating Install Project Milestones
A project milestone is a specific checkpoint in an install project that marks progress toward completion. A milestone is associated with key dates (such as a start date, due date, and a completion date). Multiple milestones can be active simultaneously, each tracking an essential step within the project timeline.
3.1) 3rd-party >> Enerflo
Use case | Update an Enerflo install project milestone based on data from a 3rd-party |
Source of truth | 3rd-party |
Data destination | Enerflo |
Data exchange tool | Enerflo REST API: PUT: /api/v3/installs/{id}/milestones/{milestoneId} |
Resources | Documentation for /api/v3/installs/{id}/milestones/{milestoneId} |
Trigger | Determined by the user or 3rd-party |
Possible design patterns | WHEN a rep updates my Monday.com project and sets a project's status to permitting complete, THEN update the Enerflo record and set the permitting milestone to completed using today's date. |
Data handling tips | You'll need the milestoneId for the milestone you're updating — retrieve the full list of milestone IDs for a project via GET: /api/v3/installs/{id}/milestones. Ensure all date values are formatted as YYYY-MM-DD before sending. |
Example request body:
PUT /api/v3/installs/67890/milestones/3
{
"completed_date": "2024-08-15"
}Only pass the fields you intend to update. The endpoint accepts partial updates.
3.2) Enerflo >> 3rd-party
Use case | Push updated milestone data from Enerflo to a 3rd-party when it changes in Enerflo |
Source of truth | Enerflo |
Data destination | 3rd-party (such as CRM) |
Data exchange tool | Enerflo 1.0 Event: project_milestone_updated |
Resources | Definition of Enerflo 1.0 Events Definition of Enerflo 2.0 Events Create an Event Subscription in Enerflo 1.0 or Enerflo 2.0 |
Trigger | Enerflo 1.0 event: project_milestone_updated **Requires an active Enerflo Webhook Event Subscription |
Possible design patterns | WHEN a milestone is edited in Enerflo, THEN check to see if the milestone now has a completion date and if so, push that date into Salesforce. |
Data handling tips | The project_milestone_updated event fires on any milestone edit, not just completions. Build conditional logic to check whether the completed_date field is now populated before triggering downstream actions in your CRM. The payload also includes the milestone name and type, which you can use to filter for specific milestones you care about. |
Example event payload:
{
"body": {
"sales_milestone": [],
"install_milestone": {
"id": 1234,
"sequence": 1,
"title": "Project Submitted",
"description": "Initial milestone indicating the project has been submitted.",
"assigned_user": null
},
"details": {
"id": 56789,
"install_id": 4453459,
"title": "Project Submitted",
"completed_on": "2024-09-30",
"estimated_completion_date": null,
"start_date": null,
"updated_at": "2024-09-30 13:58:09"
},
"eventName": "project_milestone_updated"
}
}See the Enerflo 1.0 Events documentation for the full payload schema, including the nested
installobject.
Stage 4: Updating Install Project Statuses
An Install Project's status reflects its overall lifecycle state in Enerflo. Common statuses include Active, On Hold, and Completed. This stage covers keeping that status synchronized between Enerflo and your CRM in both directions.
4.1) 3rd-party >> Enerflo
Use case | Something happens outside of Enerflo and I want to update the status of the Enerflo Install Project. |
Source of truth | 3rd-party |
Data destination | Enerflo |
Data exchange tool | Enerflo REST API: PUT: /api/v3/installs/{id}/ |
Resources | Documentation for /api/v3/installs/{id} |
Trigger | Determined by the user or 3rd-party |
Possible design patterns | WHEN my Ops team completes the final milestone in our CRM, THEN set the Enerflo Install Project status to Completed |
Data handling tips | The status_id field controls the install project status. Refer to the API documentation for the complete list of valid status IDs and their labels. Only pass fields you intend to update — the endpoint accepts partial updates. |
Example request body:
PUT /api/v3/installs/67890/
{
"status_id": 5
}4.2) Enerflo >> 3rd-party
Use case | Inform a 3rd-party CRM when the Enerflo Install project status changes (e.g., On Hold, Completed, Voided). |
Source of truth | Enerflo |
Data destination | 3rd-party (such as CRM) |
Data exchange tool | Enerflo Event (v1 update_install) |
Resources | Definition of Enerflo 1.0 Events Definition of Enerflo 2.0 Events Create an Event Subscription in Enerflo 1.0 or Enerflo 2.0 |
Trigger | Enerflo event * *Requires an active Enerflo Webhook Event Subscription |
Possible design patterns | WHEN the update_install event occurs in Enerflo, THEN inspect the event payload's status_id field and update my CRM record to reflect the new status.WHEN the status changes to On Hold, THEN flag the record in my CRM and notify the account owner.WHEN the status changes to On Hold, THEN pause any active CRM workflows and notify the account owner. |
Data handling tips | The update_install event fires on many types of install updates, not only status changes. Always check the status_id field first and only trigger downstream CRM logic when the status has actually changed to a value you care about. |
Example event payload:
{
"body": {
"id": 4453459,
"epc_company_id": 1234,
"company_id": 1234,
"status_id": 4,
"created_at": "2024-08-09 15:31:41",
"updated_at": "2024-08-09 15:31:41",
"deleted_at": null,
"agreement_url": "https://s3-us-west-2.amazonaws.com/assets.enerflo.io/agreements/agreement.pdf",
"customer": { "...": "see full customer object in event docs" },
"eventName": "update_install"
}
}Stage 5: Updating Install Project Notes
Project notes allow teams to leave contextual comments on an install project. This stage covers keeping notes synchronized between Enerflo and your CRM so all stakeholders have visibility regardless of which system they're working in.
5.1) 3rd-party >> Enerflo
Use case | A note or comment is created in my CRM and I want the same note to push into Enerflo so the Sales Rep can see it. |
Source of truth | 3rd-party |
Data destination | Enerflo |
Data exchange tool | Enerflo REST API: POST: /api/v3/installs/{id}/notes |
Resources | Documentation for /api/v3/installs/{id}/notes |
Trigger | Determined by the user or 3rd-party |
Possible design patterns | WHEN my Ops team comments on the project in CRM, THEN replicate the note in the Enerflo Install tracker. |
Data handling tips | The notes endpoint accepts a plain-text body field. If your CRM stores rich text or HTML, strip the formatting before sending. Notes in Enerflo are attributed to the API user, so consider prefixing the body with the originating author's name for context — e.g., [From John Smith in Salesforce]: ... |
Example request body:
POST /api/v3/installs/67890/notes
{
"body": "[From Sarah Johnson in Salesforce]: Customer confirmed roof access is available starting Aug 20."
}5.2) Enerflo >> 3rd-party
Use case | A note is created on an Enerflo Install Project and I want the same note to sync to my 3rd-party CRM. |
Source of truth | Enerflo |
Data destination | 3rd-party (such as CRM) |
Data exchange tool | Enerflo Event (v1 new_install_note) |
Resources | Definition of Enerflo 1.0 Events Definition of Enerflo 2.0 Events Create an Event Subscription in Enerflo 1.0 or Enerflo 2.0 |
Trigger | Enerflo event * *Requires an active Enerflo Webhook Event Subscription |
Possible design patterns | WHEN the new_install_note event occurs in Enerflo, THEN pass the note into my CRM. |
Data handling tips | The new_install_note payload includes the note body and the Enerflo user who created it. When writing the note to your CRM, include the author's name to preserve context for your team. Be aware that this event fires for all notes on all installs — filter by project ID to ensure you're updating the correct CRM record. |
Example event payload:
{
"webhook_event": "new_install_note",
"id": 2626212,
"note": "Permitting approved. Ready to schedule installation.",
"has_file": false,
"file": null,
"user_id": 40773,
"install_id": 4453459,
"deal_id": 2459008,
"milestone_id": null,
"is_complete": false,
"timestamps": {
"deleted_at": null,
"created_at": "2025-01-14 18:48:54",
"updated_at": "2025-01-14 18:48:54",
"timezone": "UTC"
}
}Stage 6: Change Orders
A Change Order modifies the terms of an existing signed agreement — for example, updating panel type, count, battery configuration, or adders. Change Orders are always initiated and signed within Enerflo, so this stage only covers the outbound direction (Enerflo → 3rd-party). There is no inbound API path to create a Change Order from an external system.
Use case | A Change Order is processed and signed in Enerflo and I need my CRM record to remain synchronized with the same data. |
Source of truth | Enerflo |
Data destination | 3rd-party (such as CRM) |
Data exchange tool | Enerflo Event (v1 signed_change_order) |
Resources | Definition of Enerflo 1.0 Events Definition of Enerflo 2.0 Events Create an Event Subscription in Enerflo 1.0 or Enerflo 2.0 |
Trigger | Enerflo event * *Requires an active Enerflo Webhook Event Subscription |
Possible design patterns | WHEN a change order is signed, THEN pass the data into my CRM and update the relevant deal fields. |
Data handling tips | When you process the event payload, be sure to extract relevant information about the change order, such as: updated panel type, updated panel count, updated battery configuration, and updated adders. |
Example event payload:
{
"body": {
"id": 6543210,
"status": "complete",
"status_id": 4,
"install": { "...": "see full install object in event docs" },
"change_orders": [ { "...": "see change_orders array in event docs" } ],
"signer": { "...": "signer details" },
"change_values": { "...": "before/after values for updated fields" },
"created_at": "2024-08-07 23:59:41",
"signed_at": "2024-09-16 18:40:42",
"pdf_url": "https://assets.enerflo.io/docflo_pdfs/executed/change_order.pdf",
"eventName": "signed_change_order"
}
}See the Enerflo 1.0 Events documentation for the full payload schema.
Updated 20 days ago
