Verify Emails and Phone Numbers in HighLevel (GoHighLevel) Workflows
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:
- 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.
- Phone numbers. SMS is a big part of most HighLevel accounts. The email action does nothing for a landline in an SMS step.
- The reason. The docs name the
isEmailVerifiedcondition but no result field. A catch-all domain and a role address are both "risky" and need different handling. - 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:
- Trigger: Contact Created, Form Submitted, or Inbound Webhook.
- Custom Webhook: verify the email.
- Update Contact Field: write the email status and reason.
- If/Else: branch on the email status.
- Custom Webhook: validate the phone (only if the contact has one).
- Update Contact Field: write the E.164 number, line type and carrier.
- 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
statusfrom 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 returnsmobile_or_landline.phone_carrierandphone_line_type: present only whenlive_lookupis 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": falsein 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 123456withcountryset toGB: 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