Recommendation (short):
Build a single Zap with these logical phases: 1) ingest (Webhook/form), 2) normalize & validate, 3) enrich, 4) de-duplicate, 5) create/update HubSpot contact with owner assignment, and 6) safe-fallback + retry queue. Use Zapier’s Webhooks + HubSpot apps and Storage/Formatter/Delay utilities to implement deterministic dedupe and retry behavior.
Concrete Zap steps (one Zap, linear flow with Paths where needed):
1) Trigger — Webhooks by Zapier “Catch Hook” (or native form app trigger). Include raw payload and a source_id (form_id + submission_id).
2) Formatter by Zapier — Normalize fields: trim, lowercase email, remove non-digits from phone, normalize country codes.
3) Filter by Zapier — Continue only if (email OR phone) exists. Optional: discard test submissions by filtering source or known test emails.
4) (Optional) Enrichment — Call Clearbit/FullContact via “Create Request” (Webhooks) or the provider app. Map company, title, domain, logo. Keep enrichment asynchronous (don’t block HubSpot write on long enrichments).
5) De-duplicate lookup — HubSpot “Find Contact” by email (primary). If no email, run “Find Contact” by phone. Also maintain a custom dedupe key: combine email||phone||form_id and store it in “Storage by Zapier” with a TTL (e.g., 24–72 hours) to prevent double-processing of rapid duplicate submissions.
6) Path A (Contact found) — Update Contact: merge fields (only overwrite lower-trust fields if source_priority allows). Add an engagement or note with form source and enrichment data. Optionally update lifecycle stage.
7) Path B (Contact not found) — Create Contact in HubSpot. Populate a custom property “lead_source” and the dedupe key. Create an associated Company record if enrichment returned domain/company.
8) Owner assignment — Use one of: a) simple round-robin via “Storage by Zapier” counter that rotates owner IDs, b) territory routing via Formatter/Lookup Table keyed on country/region/domain, or c) HubSpot workflow to reassign owners based on properties. Use HubSpot owner IDs when calling Create/Update.
9) Success/fallback handling — On success, write a “processed” record to Storage or a “Leads processed” Google Sheet row. On API error, add to a retry queue (Google Sheet or “Storage by Zapier” list) and trigger a secondary Zap that retries those rows on a schedule with exponential backoff.
Retry patterns to avoid missed leads:
- Immediate: rely on Zapier’s automatic retry for transient 5xx errors. Keep idempotency by using dedupe key saved before calling HubSpot.
- Secondary: on any non-recoverable API error, write the lead to a “Failed Leads” Google Sheet with error details and a retry_count column.
- Scheduled retry Zap: runs every 15–60 minutes, picks failed rows with retry_count = 5.
Decision criteria (which choices depend on):
- Budget: paid Zapier plan + enrichment services (Clearbit) needed for enrichment and Storage limits. If budget limited, skip enrichment or use free APIs.
- Skill level: round-robin with Storage is medium difficulty; use HubSpot workflows if you prefer low-code.
- Team size/workflow stage: small teams can assign a default owner; larger teams need territory/round-robin.
Best-for / Avoid-if:
- Best-for: teams needing deterministic dedupe and simple owner routing without building a custom middleware.
- Avoid-if: very high volume (10k+/day) — use message queue + middleware or native integration to avoid Zapier task explosion.
Practical checklist before you turn on Zap:
- Map required HubSpot properties and create custom dedupe_key property.
- Implement Formatter normalization tests (emails, phones).
- Test all Paths with: new email, duplicate email, phone-only, and enrichment failure scenarios.
- Add fallback Google Sheet + scheduled retry Zap.
- Enable notifications for Zap failures and test escalation.
If you want, I can write the exact field mappings and a sample Storage key format (e.g., dedupe_key = md5(email|phone|form_id)) or provide the Clearbit webhook example.
Compare Zapier and Make