Signup Form Validation Checklist

Take every field ContactLint returns and give it one decision: Accept, Warn, or Block. Fill this in once and keep it next to your form code. The next time someone asks what the form does with an info@ address, the answer is already written down.

How to use this sheet. Each check names the response field as it appears in GET /openapi.json, says what it tells you and what it does not, and gives the default ContactLint suggests where one exists. Tick one decision per check and write down why.

Accept: the form submits normally. Warn: the form submits, but shows a hint or flags the record for review. Block: the form does not submit until the value changes.

The one limit to remember. ContactLint never opens an SMTP connection to the mailbox. Nothing on this sheet tells you that a specific inbox exists or that a person reads it. Section 3 is where you plan for that.

0. Form setup

ItemYour answer
Form or page this sheet covers
Email endpointPOST https://contactlint.com/v1/email/validate, body {"email": "..."}
Phone endpointPOST https://contactlint.com/v1/phone/validate, body {"phone": "...", "country": "US"}
Default country value for phone checks (two-letter code; "US" is the documented example)
Where the API call runsServer sideServerless function
Keep the key out of browser code. You are responsible for all use of your key, and it is shown only once at signup. If a key is exposed, email support@contactlint.com so it can be disabled.
When the check firesOn submitOn field blurBoth
Every call uses one check, so checking on blur can spend more checks per visitor than checking on submit.
Auth header you will sendAuthorization: Bearer YOUR_KEYx-api-key
Key label used at signup (optional)
Owner of this sheet   Date:

1. Email checks

These fields live in the result object returned by POST /v1/email/validate.

1.1 syntax_valid (true / false)
Tells you: whether the address is in a usable format under practical RFC rules.
Does not tell you: that the address exists.
ContactLint default: Block when false. This is one of the clear failures.
When syntax_valid is false: AcceptWarnBlock
Message shown to the user:
Reason for this decision:
1.2 mx_found and a_found (true / false each)
Tells you: whether the domain has mail (MX) or address (A) records, looked up through Cloudflare DNS-over-HTTPS.
Does not tell you: that this specific mailbox exists on that domain.
ContactLint default: Block when the domain has no mail DNS.
Related field: deliverable_domain comes back in the same object. Read its definition in GET /openapi.json before you key a rule on it.
When mx_found is false and a_found is false: AcceptWarnBlock
When mx_found is false but a_found is true: AcceptWarnBlock
Field your rule keys on: mx_found / a_founddeliverable_domain
Message shown to the user:
Reason:
1.3 disposable (true / false)
Tells you: whether the domain is on the disposable-email-domains list (CC0 1.0).
Does not tell you: whether a new throwaway domain that is not on the list yet is a throwaway.
ContactLint default: Decide based on your business. Many signup forms block them. ContactLint's own signup page does.
When disposable is true: AcceptWarnBlock
Message shown to the user:
Reason:
1.4 role_address (true / false)
Tells you: whether the address is a shared role inbox such as admin@ or info@.
Does not tell you: whether a person actually reads it.
ContactLint default: Flag, don't block, unless you have a clear reason. Plenty of real customers use them.
When role_address is true: AcceptWarnBlock
If Warn, where the flag is stored (CRM field, tag, column):
Reason:
1.5 free_provider (true / false)
Tells you: whether the domain is a free mail provider.
Does not tell you: whether the person is a real customer or a good lead.
ContactLint default: Flag, don't block, unless you have a clear reason, such as a form that only wants work addresses.
When free_provider is true: AcceptWarnBlock
Does this form require a work address? YesNo
Reason:
1.6 verdict shortcut (valid / risky / invalid / unknown)
Rather branch on one field than five? Map each verdict to an action here, and keep the per-field rules above as the record of why.
verdictActionNote
validAcceptWarnBlock
riskyAcceptWarnBlock
invalidAcceptWarnBlock
unknownAcceptWarnBlock

Results are best effort. They come from public DNS records, open-source lists, and phone metadata at the time of the check, so they can be wrong or out of date. Do not use a result as the only basis for a decision that seriously affects a person.

2. Phone checks

These fields live in the result object returned by POST /v1/phone/validate. Parsing uses libphonenumber metadata. Carrier lookups are not offered today. Send a country value with every request.

2.1 parsed (true / false)
Tells you: whether ContactLint could parse the input as a phone number.
Does not tell you: that anyone will answer it.
When parsed is false: AcceptWarnBlock
Message shown to the user:
2.2 valid (true / false)
Tells you: the valid flag, based on libphonenumber metadata.
Does not tell you: that the phone will be answered. A "valid" result does not mean that.
When valid is false: AcceptWarnBlock
Reason:
2.3 possible (true / false)
Tells you: the possible flag, returned alongside valid and also based on libphonenumber metadata. Read both definitions in GET /openapi.json and decide how the two combine on your form.
When possible is true and valid is false: AcceptWarnBlock
When possible is false: AcceptWarnBlock
2.4 type (line type, where the data supports it)
Tells you: the line type, where the metadata supports it. Expect it to be missing for some numbers.
Does not tell you: the current carrier. Carrier lookups are not offered.
Line type values you Accept:
Line type values you Warn on:
Line type values you Block:
When type is missing: AcceptWarnBlock
Copy the exact value strings from GET /openapi.json so your comparison matches what the API returns.
2.5 region
Tells you: the region for the number, where the data supports it. Compare it with the country you sent.
Regions you Accept:
When region is not on that list: AcceptWarnBlock
2.6 e164 and the other formats
What it gives you: the number in E.164, national, and international formats. Store one so every record looks the same.
Format stored in your database: e164NationalInternational
Format shown back to the user:

3. What ContactLint does not check, and your plan for it

ContactLint never connects to the mailbox. It does not confirm that a mailbox exists or that a person will receive mail. If you need that, make it a separate step. Sending a confirmation email to the address is one way.

QuestionYour answer
Do you send a confirmation email after signup?YesNoOnly when verdict is risky or unknown
What happens to a record that never confirms?
Do you confirm phone numbers some other way, such as a code the user enters?YesNo
Which decisions on this sheet seriously affect a person, and what second signal do you check before acting?

4. Errors, limits, and what the form does when the API cannot answer

Four codes cover it. Decide now whether the form fails open (accepts the input and flags it) or fails closed (asks the user to try again).

CodeMeaningForm behavior
400Bad input.
401Missing or invalid key.Fail open and alertFail closed Alert goes to:
402Free checks used up and no credits.Fail open and alertFail closed Alert goes to:
429More than 60 requests per minute per key.Retry after a short wait. Wait length: Max retries:
Timeout or network errorNo response from the API.Timeout value: Then: Fail open and flagFail closed

The 60 per minute limit is per key. If the same key also runs CRM cleanup or bulk jobs, count those requests together with the form and pace them.

5. Volume and credits worksheet

Every key gets 100 free checks per calendar month, and unused free checks do not roll over. One check is one API or MCP call to a validation tool. Email and phone checks draw from the same allowance.

LineYour number
A. Expected form submissions per month
B. Checks per submission (1 for email only, 2 for email and phone, more if you check on blur)
C. Other checks on this key per month (CRM cleanup, agents via MCP)
D. Total checks per month = (A times B) plus C
E. Checks beyond the free 100 = D minus 100 (write 0 if negative)
F. Months you want one purchase to cover
G. Credits to buy = E times F
PlanChecksPrice (USD)Covers your G?
Credit pack5,000$9
Credit pack25,000$35
Credit pack100,000$99

Credits are used after the monthly free checks run out, and they do not expire. Unused credits are refundable within 14 days of purchase: email support@contactlint.com. Used credits are not refundable. GET /v1/usage returns free checks used this month and your credit balance.

Alert me when the credit balance drops below:   Checked by: Scheduled jobManual

6. Notes for your own privacy policy

What you can say about the vendor side, taken from the ContactLint privacy policy and terms:

ItemYour answer
Where your privacy policy names ContactLint as a processor
Do you log the full API response, or only the fields you act on?Full responseSelected fields:
Retention for those logs

7. Embed spec: ContactLint's free checkers on your page

ContactLint has two free on-page tools. Put them on the page where this checklist lives, or in your docs or internal wiki, so anyone can try a single value by hand before the code ships.

ToolURL
Disposable email checkerhttps://contactlint.com/disposable-email-checker
Phone number validatorhttps://contactlint.com/phone-number-validator

7.1 Link card (no scripts, works anywhere)

<section class="cl-tools" aria-label="Free ContactLint checkers">
  <h2>Try a value by hand</h2>
  <p>Paste one email or phone number into a free checker.</p>
  <ul>
    <li><a href="https://contactlint.com/disposable-email-checker"
           rel="noopener">Disposable email checker</a></li>
    <li><a href="https://contactlint.com/phone-number-validator"
           rel="noopener">Phone number validator</a></li>
  </ul>
  <p>Ready to automate it?
     <a href="https://contactlint.com/signup">Get a free API key</a>:
     100 checks a month, no card required.</p>
</section>

7.2 Inline frame (optional)

Only use this after you have checked in a browser that the tool page actually renders inside a frame. If it does not, ship the link card from 7.1 instead. Tested and working on:

<iframe
  src="https://contactlint.com/disposable-email-checker"
  title="ContactLint disposable email checker"
  loading="lazy"
  width="100%"
  height="520"
  style="border:1px solid #d0d7de;border-radius:6px;">
  <a href="https://contactlint.com/disposable-email-checker">
    Open the disposable email checker</a>
</iframe>

<iframe
  src="https://contactlint.com/phone-number-validator"
  title="ContactLint phone number validator"
  loading="lazy"
  width="100%"
  height="520"
  style="border:1px solid #d0d7de;border-radius:6px;">
  <a href="https://contactlint.com/phone-number-validator">
    Open the phone number validator</a>
</iframe>

Place the frames below the checklist so the sheet comes first. On screens narrower than 768px, show the link card only.

7.3 A first API call to paste next to the tools

curl -X POST https://contactlint.com/v1/email/validate \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "content-type: application/json" \
  -d '{"email":"someone@example.com"}'

Sign-off

StepDone
Every check in sections 1 and 2 has one decision ticked
Section 3 confirmation plan is written down
Section 4 fail-open or fail-closed choices are in the code
Section 5 credit purchase or balance alert is set
Key is stored server side, not in the browser bundle
Reviewed by   Date: