Unmeshed Logo
Back to Blog

Stop Writing Glue Code: Automate Lead Enrichment with Unmeshed and Supabase

Build a production-ready lead enrichment workflow using Unmeshed and Supabase. Validate signups, enrich domains with Hunter, verify emails with Kickbox, and route high-value leads to Slack.

Lead enrichment is a workflow problem

Most signup systems start simple and then gradually accumulate logic around them. First you save the lead. Then you enrich the company domain. Then you verify whether the address is personal, disposable, or worth following up. Then someone asks for a Slack alert for promising signups. Before long, that "small" backend feature is spread across API handlers, background jobs, retry scripts, and a few hard-to-trace conditionals.

That is exactly the kind of problem orchestration should own.

This workflow shows how to keep the entire signup qualification path in one Unmeshed process while using Supabase Postgres as the system of record. The flow validates the incoming lead, stores it immediately, enriches the email domain with Hunter, verifies the mailbox with Kickbox, classifies the lead, routes high-value signups to Slack, and writes the enrichment result back to the same user record.

What this workflow does

The process definition is named enrich_classify_and_route, and the shape is straightforward:

signup payload
  -> validate_input
  -> postgres_insert_user
  -> http_hunter_domain_search
  -> http_kickbox_verify
  -> classify_lead
  -> switch_lead_route
      -> slack_message_high_value | exit_skip_slack_low_value
  -> postgres_update_user_enrichment

Here is the workflow as it appears in Unmeshed:

Lead enrichment workflow in Unmeshed

What matters here is not just the list of steps, but the order:

  • The lead is written to Supabase before any external enrichment call runs.
  • Hunter and Kickbox add context without turning the initial signup into a brittle all-or-nothing transaction.
  • Slack only receives leads that pass the qualification rule.
  • Supabase is updated at the end so the source-of-truth row reflects the result of the workflow.

That sequencing is practical. If Hunter is slow or unavailable, you still have the signup. If Kickbox flags the email as free, the workflow records that fact and exits the alerting path cleanly.

Step-by-step walkthrough

1. Validate and normalize the incoming lead

The first JavaScript step, validate_input, expects a payload with email and name. It trims the values, lowercases the email, confirms the format is valid, and extracts the domain. If the payload is malformed, the workflow fails immediately with a clear error instead of writing incomplete data downstream.

This is a small step, but it sets the tone for the whole process: every later step receives a predictable structure.

2. Insert the lead into Supabase

postgres_insert_user persists the lead with a simple SQL statement:

INSERT INTO users (email, full_name)
VALUES (:#email, :#full_name)
RETURNING email;

Unmeshed binds the validated values directly from validate_input, so the workflow writes a clean row before it asks any third-party service for more information. That design is useful in production because enrichment vendors can fail independently of your core signup path.

Supabase fits naturally here because, for this workflow, it is standard PostgreSQL. Unmeshed connects through the Postgres integration and treats the users table as the durable record of the lead.

3. Enrich the company context with Hunter

The http_hunter_domain_search step calls Hunter's combined find API using the saved email address:

https://api.hunter.io/v2/combined/find?email={{steps.postgres_insert_user.output.results[0].email}}&api_key={{secrets.hunter_io_api_key}}

This step is marked optional, which is a thoughtful choice. Company enrichment is valuable, but it should not prevent the workflow from completing. If Hunter returns company data, the workflow can use it. If not, the process can still continue with the best information it has.

4. Verify the mailbox with Kickbox

The http_kickbox_verify step checks the same email with Kickbox:

https://api.kickbox.com/v2/verify?email={{steps.postgres_insert_user.output.results[0].email}}&apikey={{secrets.kickbox_api_key}}

The important signal in this workflow is whether the address is free or disposable. That becomes the main input to qualification in the next step.

5. Classify the lead

classify_lead merges the outputs from validation, Hunter, and Kickbox into one normalized result object:

  • email
  • full_name
  • company
  • is_free_email
  • lead_type

The current implementation uses a simple rule: if Kickbox reports free === true, the lead is classified as low_value; otherwise it becomes high_value.

That is deliberately easy to understand and extend. Today, the workflow uses mailbox quality as the qualification gate. Tomorrow, the same step can incorporate company size, industry, geography, or CRM scoring without changing the outer structure of the process.

6. Route qualified leads to Slack

The switch_lead_route step checks classify_lead.output.result.lead_type.

  • high_value goes to slack_message_high_value
  • low_value goes to exit_skip_slack_low_value

That keeps notification logic out of application code. Sales or operations teams can trust that only leads meeting the workflow rule are pushed into Slack, and the message already includes the details that matter: name, email, and company.

7. Update the user record with enrichment results

The final Postgres step writes the classification back to Supabase:

UPDATE users
SET
  company = :#company,
  is_free_email = :#is_free_email,
  lead_type = :#lead_type
WHERE email = :#email
RETURNING email;

This closes the loop neatly. The signup row starts with the basic identity fields, then the workflow appends the enrichment outcome once external checks are complete.

Why this design works well in practice

There are plenty of ways to assemble this with controllers, queue workers, and custom scripts. The problem is not whether that approach can work. It is how long it stays understandable.

With a single orchestration definition, teams get a few advantages immediately:

  • The full lifecycle of a lead is visible in one place.
  • Each step has explicit inputs, outputs, and execution history.
  • Secrets for Hunter and Kickbox stay in workflow-managed configuration.
  • Routing logic is easy to inspect and change without hunting through multiple services.
  • Database writes and notifications become part of one traceable process instead of separate concerns.

For teams running growth, onboarding, or outbound workflows, that visibility matters just as much as automation.

A few implementation details worth noticing

This workflow has several good design choices that are easy to miss on a first read:

StepWhy it matters
validate_inputNormalizes the payload early so every downstream step works with clean data.
postgres_insert_userCaptures the lead before relying on external providers.
http_hunter_domain_searchIs optional, which reduces the blast radius of enrichment failures.
http_kickbox_verifyProvides a direct signal for filtering low-intent or low-fit signups.
switch_lead_routeKeeps operational alerting declarative instead of burying it in app code.
postgres_update_user_enrichmentEnsures Supabase reflects the final classification state after orchestration completes.

This is the kind of workflow that tends to grow with a product. Once the basic pipeline is working, most teams add CRM sync, deduplication, account assignment, welcome-email branching, or human review. Starting with an orchestration makes those additions much easier to reason about.

Natural next extensions

The current version is already useful, but it is also a strong foundation for a more opinionated lead-ops pipeline. Common next steps include:

  • Add company-size or industry checks inside classify_lead for more granular scoring.
  • Write Hunter metadata such as domain confidence or organization details back to Supabase.
  • Push high-value leads into a CRM in parallel with the Slack alert.
  • Add retry policies or fallback behavior around third-party enrichment calls.
  • Store workflow outcomes in a separate audit table for reporting and sales analytics.

Because the workflow is already definition-driven, those changes stay additive instead of forcing a broader rewrite.

Final thoughts

The strongest part of this example is not that it uses Supabase, Hunter, Kickbox, or Slack. It is that the business process is explicit. A lead arrives, gets validated, gets stored, gets enriched, gets classified, and gets routed. Every step has a clear responsibility, and the resulting state is written back to the database your team already uses.

That is what good orchestration looks like in practice: less hidden glue code, fewer scattered decisions, and a cleaner path from signup to follow-up.

Turn this workflow into your own

You just saw a complete lead enrichment pipeline in action. Use Unmeshed to build the same workflow in your own stack and adapt it to your APIs, rules, and routing logic.

Use this workflow as a starting point and tailor it to your own use case.

Recent Blogs