Zodiac Tech CRM Docs

Leads not entering the CRM

The full guided path for a Meta lead that never becomes a CRM lead — connection, page access, ad account, form allowlist, webhook, permissions, test lead and assignment.

admin manager super-admin ad-specialist Medium ⏱ 30 min Updated 2026-10-05

Leads not entering the CRM

Meta says the lead happened; the CRM says nothing did. This is the flagship troubleshooting path — follow it top to bottom and you will find the exact stage where the lead stopped: the connection, the page's access, the ad account, the form allowlist, the webhook, the app permissions, or assignment inside the CRM.

Who this is for: the admin or ad specialist who owns lead flow, with the super admin on standby for platform-level checks.

Problem

A lead exists in Meta (Lead Center, a form's results, or a notification) but never appears in the CRM — or it appears unassigned, or under the wrong owner.

What you see

Symptom Most likely stage
Nothing at all in Webhook Logs for the time of the lead The lead never reached the CRM — connection, page, ad account or webhook
A rejected row in Webhook Logs The connection was inactive or the source is not registered
An invalid_signature row The app secret and the connector disagree
Webhook rows accepted, but no lead Allowlist filter, permissions on the page read, or assignment/visibility
The lead exists but "no one owns it" Routing/assignment rules
Everything worked yesterday Tokens expire; start at the top of the diagram

The decision path

flowchart TD
    A["Meta shows the lead, CRM does not"] --> B{"Meta connection healthy?"}
    B -- "No / expiring" --> C["Reconnect the Page: Admin -> Lead Source Connections"]
    B -- "Yes" --> D{"Page access token stored for the connection?"}
    D -- "No" --> C
    D -- "Yes" --> E{"Form belongs to this Page / ad account, and is in the allowlist?"}
    E -- "No" --> F["Select the form on the connection (allowlist) or connect the right Page/ad account"]
    E -- "Yes" --> G{"Did the webhook reach the CRM?"}
    G -- "No rows in Webhook Logs" --> H["Fix the webhook URL / verify token, then retest"]
    G -- "Yes" --> I{"WebhookLog status?"}
    I -- "invalid_signature" --> J["Align the app secret (connection record / platform Meta settings)"]
    I -- "rejected" --> K["Connection inactive or source not registered"]
    I -- "accepted" --> L{"Lead readable? (permissions / page token valid)"}
    L -- "Read failed" --> C
    L -- "Read OK" --> M{"Assigned to someone?"}
    M -- "No" --> N["Fix routing / assignment rules"]
    M -- "Yes" --> O["Lead is in the CRM - clear filters / search by phone"]

Likely causes

In the order to check them:

  1. Meta connection unhealthy, expired or disconnected — the most common cause.
  2. No page token — the Page was never selected after OAuth (the CRM tells you this explicitly when it tries to read the lead).
  3. Wrong Page or ad account — the form belongs to a different Page/ad account than the one connected; those leads go elsewhere.
  4. Allowlist — the connection is set to selected forms only, and this form is not selected.
  5. Webhook not reaching the CRM — wrong URL, wrong verify token, or Meta's webhook subscription changed.
  6. Signature mismatch — app secret changed on one side only.
  7. Permissions — the page read needs leads_retrieval and friends (see Meta won't connect).
  8. Assignment — the lead arrived, but routing rules left it unowned or assigned to an inactive user, so nobody sees it in "my leads".
  9. Visibility — filters, saved views, or searching the wrong thing. Search by phone number before declaring the lead missing.

Quick fix

  1. Open Admin → Lead Source Health Report (/admin/lead-source-health-report): if the connection is not healthy, reconnect now (see Meta won't connect).
  2. Open Admin → Webhook Logs (/admin/webhook-logs): filter to the lead's time.
    • No row at all → the webhook stage (go to Step 4 below).
    • invalid_signature → secret mismatch (Step 5).
    • rejected → inactive connection (reconnect).
    • accepted → the lead reached the CRM; the problem is later in the pipeline (Steps 6–8).

Step-by-step fix

  1. Meta connection — Admin → Lead Source Connections (/admin/lead-source-connections). Status must be healthy/connected, and the connection must point at the Page that actually runs the lead form.
  2. Page access — run Select Page on the connection and pick the exact Page. If the CRM later reports "No Page access token is stored for this connection. Reconnect the Facebook Page so LeadHub can read the lead.", this step is what fixes it.
  3. Ad account check — campaigns created outright in Meta Ads Manager must still belong to the same Page and ad account context the connection covers; if the ads team moved the campaign to another ad account or Page, connect that one too (or move the form back). The CRM's own Meta ads sync refreshes ad data daily (leadhub:sync-meta-ads --days=30) — that sync is about ads data, not a substitute for the webhook path.
  4. Webhook — the CRM's inbound endpoint is POST|GET /webhook/{tenant}/meta/{token} (the same pipeline handles Instagram lead sources). In Meta's webhook settings, the callback URL must exactly match, subscribed to the Leadgen events, and the verify token must equal the token stored on the connection. A GET request with the right token returns Meta's hub_challenge immediately. Warning: an unknown token gives a silent HTTP 200 and only a log line (Webhook: unknown token) — so "Meta says the webhook verified" is not proof. Watch Webhook Logs while you test.
  5. Signature — every leadgen webhook is verified with X-Hub-Signature-256 (HMAC-SHA256 over the payload, using the connection's app secret; the platform secret is a fallback). If invalid_signature appears, the two sides hold different secrets: align the connection record's secret (or, for shared platforms, the super admin's Meta settings).
  6. Permissions — reading the lead after the webhook needs the Page read permissions (leads_retrieval, pages_show_list, pages_read_engagement, pages_manage_ads). Missing one typically shows as a connection that can OAuth but not read — reconnect and grant everything (see Meta won't connect).
  7. Test lead — generate one deliberately: Meta's Lead Center test tool on the form, or a real test submission. Then watch Admin → Webhook Logs in real time:
    • Row appears accepted → the pipeline works; move to assignment.
    • Row rejected / invalid_signature → fix as above and repeat.
    • No row → the connection/Page/webhook stage is still wrong; do not proceed until a row appears.
  8. Assignment — if the test lead lands but is unowned, check your routing rules and assignment settings (see Lead routing): is there a rule matching this form/source, is the target user active, and does round-robin include them? Also clear lead-list filters and search by the test phone number — it may be sitting assigned to someone else.

The shortest useful habit When a lead is reported missing, open Webhook Logs first. Three seconds of reading tells you which half of the system the problem is in — outside the CRM (no/odd rows) or inside it (accepted rows). Then use the diagram.

Admin fix

  • Reconnect, select the Page, and fix the allowlist yourself (all three are admin-panel actions).
  • If the form is set to be ignored, the connection shows an allowlist of selected forms only and skipped events are marked Skipped: … — make sure the form you care about is on the list.
  • After any change, always repeat the test lead (Step 7). Do not wait for a real campaign lead to discover you are still broken.

Developer fix

  • Inbound routing: POST|GET /webhook/{tenant}/{source}/{token} (webhook.inbound / webhook.inbound.get), handled by InboundWebhookController; sources are registered in ConnectorRegistry (meta, instagram).
  • Unknown token: silent 200 + Webhook: unknown token log. Inactive connection / unregistered source: WebhookLog with status rejected. Bad signature: invalid_signature.
  • MetaConnector handles leadgen change events; Graph version v22.0 unless META_GRAPH_VERSION is set; allowlist skips are marked Skipped: in logs and the connection's selected-forms list is surfaced as Allowlist (selected forms only): ….
  • An empty app secret disables signature verification entirely — check this before blaming Meta for signature failures.
  • Ads-side refresh: leadhub:sync-meta-ads --days=30 (daily 04:30); ops scan every 30 minutes; connection health every 6 hours (leadhub:meta-health).

Logs to check

  • Admin → Webhook Logs (/admin/webhook-logs) — the single best source; error_message says why no lead was created.
  • storage/logs/laravel.log — Webhook: unknown token, signature failures, Meta read errors, [leadhub:meta-health] unhealthy Meta connections detected.
  • Super Admin → Meta Ads → Needs Attention — open CRITICAL issues on the connection.

When to escalate

  • Webhook rows accepted but no lead is ever created for any form — the read path is failing silently; a developer should trace the connector.
  • The same lead repeats as duplicates across reconnects, or arrives but with missing field mappings.
  • Meta-side changes beyond your control: app blocked, permissions revoked by review, or webhook subscription changes that require the app owner's action in Meta's dashboard.

Was this page helpful?