Treat call-data reconciliation as a reporting close, not simply a search for missing CRM activities. The operational question is whether a defined population of PBX interactions is represented correctly in CRM—and whether the evidence is complete enough to trust. This article focuses on that reporting-control layer: counting rules, extraction completeness, duration semantics and sign-off. For telecom founders, product leaders and operations teams, the deliverable should be a reproducible daily statement of what agrees, what remains unexplained and which reports are safe to use.

1. Define the reporting population before comparing totals

Start with a written reconciliation contract for each integration. Specify the tenant, PBX deployment, CRM organization, reporting timezone, included directions and eligible call types. Decide whether internal calls, test traffic, voicemail-only interactions and abandoned queue attempts belong in the CRM population. Assign an owner to every exclusion. A useful contract answers a concrete question: “Which customer interactions starting during this business day should appear as CRM activities?” That is narrower and more testable than “all calls must match.”

Do not equate a PBX database row with a customer interaction. Asterisk documents that one call can produce multiple CDRs, with linkedid connecting related records; its sequence field helps distinguish individual CDR records alongside uniqueid and linkedid. Its CDR specification describes Asterisk 12-and-later behavior, so validate the actual deployed version and export configuration rather than assuming every Asterisk-based product exposes identical fields. ([docs.asterisk.org](https://docs.asterisk.org/Configuration/Reporting/Call-Detail-Records-CDR/CDR-Specification/))

Choose the reporting grain explicitly: one activity per customer interaction, per agent conversation or per outbound attempt. Consider a hypothetical inbound call answered by one agent and transferred to another. One CRM interaction and two agent-conversation records can both be correct under different contracts. Store the contract version with each reconciliation run, and group source identifiers within tenant and PBX-instance boundaries. Never silently change historical counting rules when a connector upgrade changes the available data.

    2. Make extraction completeness a prerequisite for reconciliation

    Create a run manifest before comparing records. Record the reporting interval, extraction start and finish, endpoint and API version, requested fields, page count, extracted row count and completion status. Use half-open business-time windows: start inclusive, next boundary exclusive. Maintain separate timestamps for the call event, source modification and ingestion. For change capture, use a persisted modification watermark with an overlap and deduplicate locally; for reporting, assign the interaction to its agreed business-time window.

    CRM search results require particular care. HubSpot's current search documentation describes a 10,000-result ceiling per query, up to 200 records per page and five requests per second per account. It also warns that newly created or updated records can take time to appear and that archived records are excluded. Partition large extracts into smaller windows, throttle across workers and treat an immediately absent search result as inconclusive rather than proof of a missing activity. ([developers.hubspot.com](https://developers.hubspot.com/docs/api-reference/search/guide))

    Zoho CRM V8 Get Records supports Calls and the If-Modified-Since header, with documented pagination using page tokens beyond the initial page range. Follow its more_records and token rules instead of stopping after one successful response. Treat version-specific pagination and authorization requirements as adapter configuration. If an extract stops because of an expired token, denied field or exhausted request budget, label the run incomplete; do not publish a clean reconciliation percentage from the partial population. ([zoho.com](https://www.zoho.com/crm/developer/docs/api/v8/get-records.html))

      Planning something similar?

      Let's map the integration before complexity grows.

      Tell us which platforms need to connect. We'll help turn the workflow into a clear, reliable implementation plan.

      Talk to iMingos ↗

      3. Compare meaning, not similarly named fields

      Define each comparison in a field-level contract: source field, target field, transformation, null handling and tolerance. Asterisk distinguishes duration, measured from start to end, from billsec, measured from answer to end; both are expressed in seconds. HubSpot's calls API defines hs_call_duration in milliseconds. Converting units is necessary, but not sufficient: first decide whether the target represents elapsed interaction time or an answered interval. A correctly converted value can still represent the wrong measurement. ([docs.asterisk.org](https://docs.asterisk.org/Configuration/Reporting/Call-Detail-Records-CDR/CDR-Specification/))

      For example, suppose a call rings for 15 seconds and remains answered for 90 seconds. Under an answered-duration contract, the expected CRM value is 90,000 milliseconds; under an elapsed-duration contract, it is 105,000. This is an illustrative calculation, not a vendor guarantee. For transfers and conferences, define whether duration means the sum of agent intervals or the union of customer-connected intervals. Summing overlapping legs is inappropriate when the intended metric is elapsed customer time.

      Keep transport status separate from business outcome. HubSpot exposes hs_call_status separately from hs_call_disposition, whose values use internal GUIDs. Do not infer “customer reached” solely from a completed call status. Where bridge-level interpretation is necessary, Asterisk CEL provides more detailed channel events, including bridge entry and exit, and its specification applies to Asterisk 12 and above. Verify that the deployed logging configuration actually captures and retains the events your calculation requires. ([developers.hubspot.com](https://developers.hubspot.com/docs/api-reference/crm-calls-v3/guide))

        4. Build control totals that explain disagreement

        Reconcile identity sets before reporting aggregate agreement. Prefer persisted links between source interaction identifiers and CRM activity IDs. For historical data without those links, use constrained candidate matching within the same tenant, direction and time range, and keep ambiguous candidates unresolved. Phone number plus approximate timestamp should not automatically establish identity. Compare the normalized expected set against the observed CRM set in both directions: expected interactions without activities, and integration-originated activities without eligible source interactions.

        Assign every expected interaction one exclusive primary result: matched and compliant, missing, ambiguous, or matched with field discrepancies. Track additional details—duration mismatch, outcome mismatch, association mismatch—as secondary flags. Separately count extra CRM records and suspected duplicates. Define coverage as uniquely represented expected interactions divided by eligible expected interactions, and report field correctness separately. This prevents a high presence rate from hiding incorrect durations or outcomes, while avoiding double-counting one interaction in several headline exception categories.

        Publish controls by tenant, connector version, direction and call class, not just as a global total. Include eligible interaction count, source-leg count, uniquely represented count, unresolved count and duration totals under the agreed definition. Equal counts are not proof of agreement: one missing activity and one duplicate can cancel numerically. Retain record-level differences and transformation versions so an operator can trace an aggregate discrepancy back to the underlying evidence without rerunning an undocumented spreadsheet.

          5. Close with evidence, then reopen deliberately

          Use explicit run states such as collecting, provisional, closed-with-exceptions and closed. Choose a settling interval based on observed ingestion and search visibility delays rather than an arbitrary promise. A suggested daily process is an initial comparison after the reporting boundary, a later overlapping extraction, then sign-off once both extracts are complete and exceptions have owners. Keep collection freshness separate from reconciliation quality: an old but internally consistent dataset should not receive a healthy operational status.

          Make the close package reproducible. Retain the run manifest, reconciliation contract version, normalized comparison snapshot, exception register and approval record under a defined retention policy. Restrict raw payload access and avoid copying recording URLs or unnecessary personal data into routine dashboards. If late evidence changes a closed period, publish a new revision with the reason and numerical difference. Preserve the earlier result rather than silently replacing the figures that another team already used.

          Validate the process in read-only mode before linking exceptions to corrective actions. Test transfers, simultaneous calls involving the same number, midnight boundaries, late updates, partial extraction and deliberate CRM deletion. Then decide which unresolved categories block operational reporting and which can remain disclosed exceptions. For iMingos, the practical systems-integration framing is a versioned reconciliation contract and an auditable reporting close—not a promise that every PBX counter and CRM dashboard should display the same number.

            Common questions

            Frequently asked questions

            Should PBX and CRM call counts always match?

            Only after both datasets use the same population and reporting grain. Asterisk can emit multiple CDRs for one call, so comparing raw CDR counts with CRM activity counts is not a valid completeness test. Normalize first, then compare interaction identities. ([docs.asterisk.org](https://docs.asterisk.org/Configuration/Reporting/Call-Detail-Records-CDR/CDR-Specification/))

            Can reconciliation rely entirely on CRM search?

            Not without accounting for the endpoint's limitations. HubSpot search excludes archived records and can lag recent writes. Use persisted CRM IDs for targeted investigation and establish a separate deletion or archival policy; a search miss alone does not prove the connector failed. ([developers.hubspot.com](https://developers.hubspot.com/docs/api-reference/search/guide))

            Does this design require a particular CRM edition?

            The control model does not prescribe an edition. Before implementation, verify the purchased account's API access, scopes, available fields, extraction limits and retention. Pin the adapter to a documented API version and test permissions with the actual integration credentials rather than assuming feature parity.

            What should the first implementation deliver?

            Start with one tenant, one reporting grain and a read-only daily report. Deliver a complete extraction manifest, identity-level comparison, separate presence and field-quality measures, and an owned exception register. Expand coverage only after representative call scenarios produce explainable results.

            Official resources

            docs.asterisk.org ↗www.zoho.com ↗docs.asterisk.org ↗www.zoho.com ↗www.zoho.com ↗www.zoho.com ↗