All posts

Verify Emails and Phone Numbers in HighLevel (GoHighLevel) Workflows

··11 min read

To verify emails and phone numbers in HighLevel (GoHighLevel), add a Custom Webhook action to a workflow. Call a verification API with the contact's email and phone, send your API key as a Bearer token, and turn on Save response for this Webhook. Then use Update Contact Field to store the status and reason, add tags, and branch with If/Else: valid emails continue, risky ones go to a person, invalid ones skip every email step. For phones, branch on line type before any SMS.

HighLevel also has a built-in Email Verification action. It is a good fit in some sub-accounts and a poor fit in others. This guide covers both, then builds the webhook version step by step with SimpleVerifier's API as the example.

HighLevel's built-in email verification: what the docs say

HighLevel's help center documents an Email Verification workflow action. It checks a contact's email when the contact reaches that step. The article says the check may cover syntax, domain validity, mailbox existence and risk signals such as disposable addresses. It returns one of three outcomes: valid, risky or invalid. You branch afterwards with an If/Else on the condition isEmailVerified = true.

The enable and rebill article adds the commercial details:

Detail What HighLevel's docs say
Price $2.50 per 1,000 email verifications
Sending providers Available only for LC Email and Mailgun
Re-verification Optional; verifications older than 90 days expire and are rechecked before the next send
Invalid addresses "Emails will not be sent to this address"
Rebilling Agencies can mark up the cost to sub-accounts, depending on plan
Phone numbers Not covered

That is a fair deal for a sub-account that sends newsletters through LC Email. It leaves four gaps that agencies hit often:

  1. Other sending tools. Many agencies run cold email from Instantly, Smartlead or a separate Google Workspace, and use HighLevel as the CRM. The built-in check is tied to LC Email and Mailgun.
  2. Phone numbers. SMS is a big part of most HighLevel accounts. The email action does nothing for a landline in an SMS step.
  3. The reason. The docs name the isEmailVerified condition but no result field. A catch-all domain and a role address are both "risky" and need different handling.
  4. Many sub-accounts. Per-check billing adds up across clients. A flat plan behind one webhook is easier to price into a retainer.

If none of those apply, use the built-in action. If any do, build the webhook below.

What you will build

The finished workflow has these steps:

  1. Trigger: Contact Created, Form Submitted, or Inbound Webhook.
  2. Custom Webhook: verify the email.
  3. Update Contact Field: write the email status and reason.
  4. If/Else: branch on the email status.
  5. Custom Webhook: validate the phone (only if the contact has one).
  6. Update Contact Field: write the E.164 number, line type and carrier.
  7. If/Else and tags: route to nurture, SMS, manual review or suppression.

Step 1: Create the custom fields

In the sub-account, go to Settings > Custom Fields and create these contact fields. Single-line text is fine for all of them.

Field name Holds Example value
Email Status status risky
Email Reason reason Accepts all addresses
Phone Status phone_status valid
Phone E164 phone_e164 +14155550123
Phone Line Type phone_line_type, or phone_type if no live lookup mobile
Phone Carrier phone_carrier (carrier name)
Verified On the date of the check 2026-10-15

Fields beat tags for one reason: you can filter, export and re-check them. Add tags too, but keep the raw values in fields. Our guide on verification for agencies explains why a stored reason saves arguments with clients later.

Step 2: Add the email Custom Webhook

HighLevel's Custom Webhook documentation says the action supports GET, POST, PUT and DELETE, Bearer token authentication, custom headers, query parameters and a raw JSON body. It recommends keeping secrets in headers, not URLs. Configure it like this:

Setting Value
Event CUSTOM
Method POST
URL https://simpleverifier.com/api/v1/verify
Authorization Bearer Token: sv_live_... (your key)
Content-Type application/json
Raw Body see below
Save response for this Webhook On

Raw body, using HighLevel's custom value picker for the email:

{
  "email": "{{contact.email}}"
}

The API trims the value, so stray spaces from a form do not cause a false invalid. A GET with email as a query parameter works too. POST keeps the address out of URL logs.

Before you save, click Test Request with a real test contact. HighLevel's changelog entry on saving responses says the saved sample becomes the reference for later runs, and that the response can then be used as a custom variable and in If/Else conditions. The sample looks like this:

{
  "email": "jane@company.com",
  "status": "valid",
  "reason": "Mailbox exists",
  "mailbox_checked": true
}

status is valid, risky or invalid. The API docs list every reason:

status Possible reasons
valid Mailbox exists
risky Accepts all addresses, Role-based address, Provider hides mailbox status, Server would not confirm, Mailbox check unavailable
invalid Invalid format, No mail server, Disposable address, Mailbox not found

API access needs the Pro plan ($29.99 a month) or Email + Phone ($49.99 a month). Pay-as-you-go packs cover CSV uploads only, so a pack key will get a 402.

Step 3: Store the result

Add an Update Contact Field action. HighLevel's Update Contact Field article says the action writes values to standard or custom contact fields, and supports dynamic values from earlier steps.

  • Email Status: pick status from the Custom Webhook's saved response in the value picker.
  • Email Reason: pick reason.
  • Verified On: the current date.

Run the workflow once on a test contact and open Execution Logs. You should see the webhook's status code and the values written. If the fields are empty, the response was not saved or the wrong step's response was picked.

Step 4: Branch on the email status

Add an If/Else with three branches on the Email Status field:

Branch Condition Actions
Valid Email Status is valid Tag email-valid; continue to email nurture
Risky Email Status is risky Tag email-risky; create a task for the rep; skip automated cold email
Invalid Email Status is invalid Tag email-invalid; remove from email workflows; ask for a new address if the contact came from a form
None Email Status is empty Tag verify-retry; see Step 7

Branch on the field you wrote, not on the raw response. That keeps every later workflow and smart list working from the same value.

Risky needs care. "Accepts all addresses" means a catch-all domain: the server takes every address, so the mailbox cannot be confirmed. "Role-based address" is a shared inbox like info@. Our guide to accept-all vs unknown results explains how to treat each one.

Step 5: Validate the phone

Add an If/Else first: only continue if Phone is not empty. Then add a second Custom Webhook:

Setting Value
Event CUSTOM
Method POST
URL https://simpleverifier.com/api/v1/phone
Authorization Bearer Token: same key
Content-Type application/json
Save response for this Webhook On

Raw body:

{
  "phone": "{{contact.phone}}",
  "country": "US"
}

country is a two-letter code. It only matters for numbers written without a +. If the agency serves UK clients, set GB in that sub-account's workflow. A sample response:

{
  "input": "07911 123456",
  "phone_status": "valid",
  "phone_e164": "+447911123456",
  "phone_country": "GG",
  "phone_type": "mobile",
  "phone_carrier": "JT Group Limited",
  "phone_line_type": "mobile",
  "live_lookup": true
}

What each field tells you:

  • phone_status: whether the number fits its country's numbering plan.
  • phone_e164: the number in E.164 form, such as +447911123456. SMS providers expect this format.
  • phone_type: the type from the numbering plan. It is included on every plan. For US and Canadian numbers the plan often cannot separate mobile from landline, so it returns mobile_or_landline.
  • phone_carrier and phone_line_type: present only when live_lookup is true. On the Email + Phone plan, valid numbers get a live carrier lookup: 5,000 a month, and failed lookups do not count. Send "live": false in the body to skip it for a sub-account that does not need it.

Map these into the phone fields with a second Update Contact Field action.

One limit to state plainly. A valid result means the number is well formed and, with a live lookup, assigned to a carrier as a mobile, landline or VoIP line. It does not mean the number is in service or that the person still uses it. No lookup can tell you that.

Step 6: Route phones before SMS

Add an If/Else on Phone Line Type (or Phone Status if you skip live lookups):

Result Route
Phone Status invalid Tag phone-invalid; skip SMS and calls
Line type mobile Tag sms-ok; continue to SMS steps
Line type landline Tag call-only; skip SMS, keep for calls
Line type voip Tag phone-voip; your call, by client policy
mobile_or_landline (no live lookup) Tag phone-unknown-type; treat as not confirmed for SMS

Texting a landline wastes a message and inflates failure rates. Our guide to validating numbers before an SMS campaign covers the delivery side. Line type also matters for US consent rules; see TCPA and mobile vs landline. That article is general information, not legal advice.

Step 7: Handle errors and retries

HighLevel's Custom Webhook article lists common status codes and fixes. It does not describe an automatic retry policy or a timeout, so plan for a missed response yourself.

Code Meaning What to do in HighLevel
400 No email or phone in the request Check the custom value in the body
401 Key missing, wrong or revoked Re-enter the Bearer token
402 Subscription not active, or a pack-only account Check the plan
429 Over 120 calls a minute on one key Retry later
503 Service briefly unavailable Retry later

The simplest retry is the empty-field branch from Step 4. Contacts tagged verify-retry go into a second workflow that waits an hour, removes the tag, and runs the same Custom Webhook again.

Watch the rate limit when you import. The API allows 120 calls a minute per key. Importing 5,000 contacts into a sub-account can fire 5,000 workflow runs at once. Give each sub-account its own key, so one client's import cannot slow another's leads. For big imports, see Step 8.

Worked example: one sub-account, one month

These numbers are illustrative. Use your own volumes and check current prices in your agency billing.

A home services client gets 2,000 new contacts a month from forms and ads. All have an email. 1,500 have a phone. The agency sends email through a separate cold email tool, and SMS through HighLevel.

Webhook route:

  • Executions: 2,000 email calls + 1,500 phone calls = 3,500 a month.
  • HighLevel premium actions: the premium features article lists the standard rate at $0.01 per execution after 100 lifetime executions. That is about $35. A Workflow Pro Starter bundle at $10 a month covers 10,000 executions.
  • SimpleVerifier Email + Phone: $49.99 a month, flat. It covers the email checks and 1,500 of the 5,000 monthly live lookups. The same plan can serve other sub-accounts, each with its own key, until the shared lookup allowance gets tight.

Built-in route: 2,000 email checks at $2.50 per 1,000 is $5. But it requires LC Email or Mailgun, which this client does not send cold email through, and it gives no phone data.

For this client the webhook route is the one that works. For a newsletter-only client on LC Email, the built-in action is enough.

Step 8: Clean existing contacts with a CSV first

Workflows are for new contacts. For the contacts already in a sub-account, export them, verify the file, and import the results back into the same custom fields.

A CSV upload runs the same email checks and phone validation in bulk and returns valid, risky and invalid files. At 120 calls a minute, 20,000 contacts through webhooks would take close to three hours of workflow runs and 20,000 premium executions. A file avoids both. Pay-as-you-go packs cost $9 for 2,500 or $19 for 10,000 emails if you only need a one-off clean. Our CRM cleanup use case walks through the export and re-import pattern.

Test before you publish

Run five test contacts through the draft workflow:

  • An address you own: expect valid.
  • A made-up address at gmail.com: expect invalid, "Mailbox not found".
  • An address at a domain you know is catch-all: expect risky.
  • A UK mobile written as 07911 123456 with country set to GB: expect +447911123456.
  • A contact with no phone: expect the phone branch to be skipped.

Check Execution Logs for each one. Then publish.

The short version

HighLevel's built-in Email Verification action costs $2.50 per 1,000 checks and works only with LC Email and Mailgun. For anything else, or for phones, use a Custom Webhook: POST the email to the verification API with a Bearer token, save the response, write status and reason into custom fields, and branch with If/Else. Add a second webhook for phones and route SMS on line type. Clean existing contacts by CSV, and keep webhooks for new ones.

If you manage several client accounts, one flat plan with no per-check credits keeps verification costs predictable. See pricing for Pro and Email + Phone.

Common questions

Does GoHighLevel have built-in email verification?

Yes. HighLevel has an Email Verification workflow action and an account-level verification setting. Its help docs price verification at $2.50 per 1,000 checks and say it is available only for the LC Email and Mailgun email providers. It returns valid, risky or invalid. It does not check phone numbers.

Can HighLevel use the response from a Custom Webhook?

Yes. HighLevel's changelog says the Custom Webhook action can save its response, and the saved response can be used as a custom variable and in If/Else conditions. Send a test request first so HighLevel has a sample response to map from.

How much does the Custom Webhook action cost in HighLevel?

HighLevel lists Custom Webhooks among its premium workflow features. Each eligible sub-account gets 100 lifetime premium executions, then the standard rate is $0.01 per execution. Workflow Pro bundles start at $10 a month for 10,000 executions. Check your agency billing for current rates.

Can I verify phone numbers in HighLevel before sending SMS?

Yes, with a Custom Webhook to a phone validation API. It returns the number in E.164 format, its country and a line type from the numbering plan. On SimpleVerifier's Email + Phone plan, valid numbers also get a live carrier lookup with the real line type, so you can keep landlines out of SMS steps.

Should agencies use HighLevel's verification or an external API?

Use HighLevel's action if the sub-account sends through LC Email or Mailgun and only needs email checks. Use an external API if you send cold email from another tool, need phone checks, want the reason stored on the contact, or want one flat cost across many sub-accounts.

Verify unlimited addresses for $29.99/month

Real SMTP mailbox checks. No credits, no per-email fees.

Get Started