How KPI sync works
When you save or manually resync a connected KPI, Elevale calls the highlevel_kpi_sync edge function with the KPI ID and workspace context.
The function loads the KPI, OAuth connection, and data-point configuration from oauth_provider_endpoints.
Your access token is decrypted server-side and sent to HighLevel at services.leadconnectorhq.com with API version header 2021-07-28.
The returned value is written to kpi_history and the KPI current field is updated. Connection sync status is updated on success or failure.
Scheduled syncs use the same path with a service-role context.
Opportunity metrics - status logic
Most opportunity KPIs use GET /opportunities/search with location_id (snake_case) as a query parameter. HighLevel status values are open, won, lost, and abandoned. Elevale maps legacy config value active to open automatically.
All Opportunities - total count across every status (no status filter).
Live Opportunities / Open Deals (Live) - count where status = open.
Won Deals - count where status = won.
Lost Deals - count where status = lost.
Abandoned Opportunities - count where status = abandoned.
Win Rate - won ÷ (won + lost), expressed as a percentage.
Loss Rate - lost ÷ (won + lost), expressed as a percentage.
Abandonment Rate - abandoned ÷ all opportunities, expressed as a percentage.
Opportunity value metrics
Pipeline Value / Open Pipeline Value - sum of monetaryValue for open opportunities.
Won Opportunity Value - sum of monetaryValue for won opportunities.
Lost Opportunity Value - sum of monetaryValue for lost opportunities.
Abandoned Opportunity Value - sum of monetaryValue for abandoned opportunities.
Average Deal Value - average monetaryValue across opportunities returned in the API response.
Value sums paginate through opportunity pages (100 per page) and add monetaryValue from each record.
Lost opportunities by reason
When you select a HighLevel connection in the KPI form, Elevale loads your account's configured lost reasons from the HighLevel API.
Choose the Lost Reason data point, then use the secondary Lost reason filter dropdown to track All lost opportunities or a specific reason (for example Price too high).
Granular reasons are no longer listed as separate top-level data points - this keeps the picker tidy while still supporting per-reason KPIs.
Specific filters sync using endpoint keys of the form lost_reason_{id}. The all-opportunities option uses the existing lost_deals sync path.
If the HighLevel API supports server-side lost_reason_id filtering, Elevale uses meta.total for a fast count. Otherwise it paginates lost opportunities and matches lostReasonId client-side.
Lost reasons are specific to your HighLevel location - different sub-accounts may show different reason lists.
Contact, conversation, and appointment metrics
Total Contacts - GET /contacts/ with locationId; count uses meta.total or the contacts array.
Active Contacts - intended to count contacts with recent activity. The HighLevel list endpoint does not accept a hasRecentActivity filter today, so sync returns total contact count from the first page/meta until a search-based filter is added.
New Contacts This Month - contact count; date-filtered contact queries are not yet wired to the search API.
Lead Conversion Rate - percentage metric; requires contact-level fields that may not be present on basic list responses.
Total Conversations, SMS Sent, Email Sent, Response Rate - conversation endpoints; date filters apply only when explicitly configured.
Total Appointments, Appointment Show Rate, No-Show Rate - calendar appointment endpoints with date range support.
Payment and revenue metrics
Total Revenue, Monthly Revenue, Average Transaction Value - payment transaction endpoints.
Subscription Revenue / One-Time Payment Revenue - filtered transaction sums by type.
Transaction endpoints support startDate/endDate when the data point declares a date_filter in configuration.
Data point categories
HighLevel-family KPI data points are grouped by purpose in the KPI form:
Sales - pipeline and deal metrics (opportunities, win/loss rates, appointments, lost-by-reason counts).
Marketing - audience and outbound comms metrics (contacts, SMS/email sent, conversations, response rate).
Finance - payment and revenue metrics (total/monthly revenue, subscription and one-time revenue).
Known limitations
Edge function timeout (150 seconds) - value-sum syncs paginate opportunities. Pagination is capped at 20 pages (2,000 opportunities). Very large pipelines may return a partial sum if more than 2,000 open records exist.
Opportunity pagination safety - sync stops when meta.total is reached, when a page returns fewer than 100 rows, or when the API repeats a pagination cursor.
Count vs sum accuracy - count metrics (live deals, won deals, etc.) use meta.total from a single API call and are accurate for totals reported by HighLevel. Sum metrics require fetching each opportunity row.
Active Contacts filter - hasRecentActivity is configured but not yet sent to HighLevel; the metric may reflect total contacts rather than recently active contacts.
Contact date filters - GET /contacts/ rejects startDate/endDate query parameters (422). Date-filtered contact KPIs need the contacts search API in a future update.
Duplicate KPI titles - creating a KPI with the same title as an existing workspace KPI may return HTTP 409; use a unique title.
Token refresh - if the access token expires and refresh fails, reconnect the integration from Workspace Settings.
One connection per brand - each workspace connection is tied to one location. Multi-location reporting requires separate connections or manual KPIs per location.
How sync works
Each data point maps to a provider API query executed by the integration sync engine.
On save or scheduled sync, Elevale fetches the latest value and appends to KPI history.
Connection status on the KPI shows the last successful sync or error message.
Setup and troubleshooting: Setup & usage