How a phone call becomes a CRM record
Call log ingestion, device capability resolution, and the honest truth about recording — what works on which phones, and what the CRM can never record.
How a phone call becomes a CRM record
Your team calls from their phones all day. Where do those calls end up? Every call the app can see becomes a CRM record — who called whom, when, which direction, how long — matched to the lead where possible. Recording is a different story: Android allows it on some phones, not others, and this page is honest about exactly which.
flowchart TD
A[Call on the phone] --> B{How was it made?}
B -->|Normal SIM call| C[App scans the call log every ~15 min]
B -->|CRM Phone mode dialer| D[Live call event from the app]
C --> E["Batch POST /api/v1/mobile/call-events (≤100, idempotency key)"]
D --> E
E --> F[Validation: exclusions, direction, dedupe]
F --> G[Call record in the CRM + lead match + timeline]
H[Device capability snapshot] --> I{Recording mode for this phone}
I -->|NATIVE_RECORDING| J[App records; optional upload]
I -->|IMPORTABLE_RECORDING| K[Import recordings from another recorder]
I -->|METADATA_ONLY| L[Call details only — no audio]
I -->|UNKNOWN| M[Detected on first recordings/attempts]
The call journey in plain language
- A call happens on the salesperson's phone — incoming, outgoing or missed.
- The app collects it. For normal SIM calls the app scans the phone's call log periodically (about every 15 minutes); in CRM Phone mode (app set as the default dialer) events come live.
- A batch is uploaded to the mobile API — up to 100 events per batch, each with an idempotency key so retries never double-create.
- Exclusions and direction are respected: numbers the user excluded (personal calls) never leave the phone's filter; directions are incoming / outgoing / missed / unknown.
- The CRM matches and stores. A call record is created, matched to a lead where the number matches, and written to the timeline.
- Recording — only where the phone allows. The app resolves the phone's capability and works within it (see below). If recording is possible and enabled, the audio is uploaded through the recordings endpoint and retained for 30 days by default (
leadhub:purge-recordings).
Device capability — the honest matrix
| Mode | Meaning |
|---|---|
NATIVE_RECORDING |
The phone can record calls for the app (some OEM dialers allow it) — recording may be available |
IMPORTABLE_RECORDING |
Another recorder on the phone writes files the app can import |
METADATA_ONLY |
Only call details (who/when/duration) — no audio, by platform design |
UNKNOWN |
Not yet determined — the app resolves it as it learns the device |
Tracking is also graded: FULL (call log access granted, everything flows) or LIMITED (some events unavailable).
The app cannot record on stock Android 10+ Android itself blocks third-party call recording on stock Android 10 and newer. On those phones the app logs call details only (METADATA_ONLY). No CRM setting can override this — it is an operating-system restriction. OEM dialers (some Samsung, Xiaomi, etc.) may permit recording, which is why capability is resolved per device.
CRM Phone mode is a dialer, not a recorder Setting LeadHub as your default dialer gives you live call events and call-from-CRM convenience. It does not grant recording powers the operating system does not allow.
Troubleshooting notes
| Symptom | Likely cause | Fix |
|---|---|---|
| Calls missing from the CRM | Call log permission denied, or only LIMITED tracking | Grant Call log access in Android settings; check Device Health |
| Some calls missing (personal numbers) | Exclusions are active by design | Review exclusions in the app — they are per user |
| Calls appear twice | Very rare; idempotency guards normally prevent it | Report with the call times; duplicates are traceable via the idempotency key |
| No recordings on a phone | The phone is METADATA_ONLY (stock Android 10+) |
Expected — see the matrix above; use an OEM recorder phone or accept metadata-only |
| Recordings disappear after ~a month | 30-day retention policy | Download anything you need to keep before it expires |
| Call events stop arriving | Battery optimisation killed the app's background scan | Exclude the app from battery optimisation |
Technical details
- Call ingestion:
App\Http\Controllers\Api\Mobile\CallEventController— batch max 100, per-tenant idempotency, exclusion backstop, allowed directions incoming/outgoing/missed/unknown; app scans every ~15 minutes (android/README.mddocuments the operational setup). - Capabilities:
App\Http\Controllers\Api\Mobile\CapabilityController—POST devices/capabilities, values fromDeviceCapabilitySnapshot::RECORDING_MODES(NATIVE_RECORDING/IMPORTABLE_RECORDING/METADATA_ONLY/UNKNOWN) and tracking modes FULL/LIMITED; snapshots are append-only, max 20 per device. - Recordings (when available) upload via the mobile recordings endpoint (multipart); server retention is 30 days, enforced by
leadhub:purge-recordings. - App internals: Kotlin/Compose
com.leadhub.sales, offline Room queue + WorkManager sync; deep linkscrm://.
Related guides
Was this page helpful?
Thanks — noted. ✦