npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

truval

v0.4.4

Published

Email verification API and API infrastructure for AI agents

Readme

truval.dev sdk

npm version License: MIT Better Stack Badge

Production email verification built for apps and AI agents — one HTTP API, rich structured results (not just “valid/invalid”), and a small MIT-licensed client so you can ship with confidence.

truval.dev verifies addresses with layered checks (syntax, disposable signals, MX, SMTP where possible) and returns ordinal confidence, catch-all and smtp_blocked signals, and actionable errors so your product — or your LLM — can make the right call.


Why this SDK is open source

  • Trust — Inspect exactly what runs in your stack: thin fetch wrapper, no hidden telemetry in the client.
  • Agents — Public code trains and assists coding tools; copy-paste examples “just work” in Cursor, Copilot, and Claude.
  • Integration — TypeScript types match the live API; pair with our OpenAPI and docs for audits and codegen.

The verification engine runs on truval.dev infrastructure (EU-hosted API). This repo is the official client — the part you embed in your app.


Features

| Capability | What you get | |------------|----------------| | Single verify | verify() or createClient().verify() → full VerifyResult | | Batch | verifyBatch() — auto-chunks to 50 emails per request, sequential calls to avoid rate-limit spikes; results in input order | | Streaming | verifyStream() — NDJSON stream, results as they finish (completion order, not input order) | | Async + webhook | verifyAsync()202 + job_id; result POSTed to your HTTPS webhook | | Rate limits | Optional retryOnRateLimit using API reset_at | | Management API | createManagementClient() — account, keys, usage, Stripe billing portal (provisioning key) | | Runtime | Global fetch (Node 18+, Bun, Deno, Cloudflare Workers, etc.). API keys must stay server-side — see warning below. |

Warning — never expose API keys in the browser
sk_live_... and sk_mgmt_... are secret. Do not put TRUVAL_API_KEY (or provisioning keys) in React/Vue/Svelte client components, public Next.js "use client" bundles, or any code shipped to the browser — keys can be extracted and your quota billing and account are at risk.
Call this SDK only from trusted server environments: HTTP APIs, Server Actions / Route Handlers / API routes, Edge Functions, Workers, cron jobs, etc. If the browser must trigger a check, add a backend endpoint you control that holds the key and proxies to truval.dev (or use async verify + webhook so the client never sees the key).
truval.dev does not offer a separate “publishable” or domain-restricted browser key; treat standard keys like database passwords.


Installation

npm install truval
pnpm add truval
yarn add truval

TypeScript: types are included. Node: use v18+ (native fetch).


Quick start

import { createClient } from 'truval'
import type { VerifyResult } from 'truval'

const truval = createClient(process.env.TRUVAL_API_KEY!, {
  retryOnRateLimit: true,
  maxRetries: 3,
})

const result: VerifyResult = await truval.verify('[email protected]')
console.log(result.status, result.confidence, result.smtp_blocked)

Get an API key at dash.truval.dev.

TypeScript types

Use the exported types in your own signatures without digging through node_modules:

import type { VerifyResult, TruvalError, ApiError, AsyncVerifyResult } from 'truval'

Other useful exports include TruvalClient, TruvalClientOptions, and management response types from the same entry.


Usage

One-off call (no client instance)

import { verify } from 'truval'

const result = await verify('[email protected]', process.env.TRUVAL_API_KEY!)
console.log(result.status, result.confidence)

Client instance

import { createClient } from 'truval'

const apiKey = process.env.TRUVAL_API_KEY!

const truval = createClient(apiKey, {
  // Optional: on 429, wait until reset_at then retry
  retryOnRateLimit: true,
  maxRetries: 3,
  // Optional: default https://api.truval.dev
  // baseUrl: 'https://api.truval.dev',
})

const result = await truval.verify('[email protected]')
console.log(result.status)        // 'deliverable' | 'undeliverable' | 'unknown' | 'catch_all' | 'invalid'
console.log(result.valid)         // do not use alone (see agent decision guide below)
console.log(result.confidence)    // ordinal 0–1 (not a probability)
console.log(result.smtp_blocked)  // true for Gmail/Outlook/Yahoo (expected)
console.log(result.catch_all)     // true when the domain accepts any recipient

Batch and streaming

import { createClient } from 'truval'

const truval = createClient(process.env.TRUVAL_API_KEY!)

const results = await truval.verifyBatch(['[email protected]', '[email protected]']) // auto-chunked (50 max per request)
for (const r of results) console.log(r.email, r.status)

for await (const r of truval.verifyStream(['[email protected]', '[email protected]'])) {
  // Yields in completion order (not necessarily input order)
  console.log(r.email, r.status)
}

Async verification (webhook)

import { createClient } from 'truval'

const truval = createClient(process.env.TRUVAL_API_KEY!)

const job = await truval.verifyAsync('[email protected]', 'https://your-app.com/truval-webhook')
console.log(job.job_id, job.status) // { status: "pending" }

Response shape (VerifyResult)

The API returns structured data so agents and humans can reason beyond a single boolean.

| Field | Type | Description | |------|------|-------------| | email | string | Address that was verified | | valid | boolean | true for deliverable/catch-all paths; false also for many “unknown” cases — use status + confidence | | status | string | deliverable · undeliverable · unknown · catch_all · invalid | | confidence | number | Ordinal 0–1 (not P(mailbox exists)). Typical: ~0.97 deliverable, ~0.75 major providers with smtp_blocked, ~0.65 catch-all, ~0.50 unknown with MX but SMTP inconclusive, ~0.02 undeliverable | | failed_check | string \| null | Same as the API: syntax · disposable · no_mx · smtp · smtp_timeout, or null when verification finished without failing a layer (deliverable, catch-all, unknown including smtp_blocked, inconclusive SMTP). See Verification layers in the docs. Enum matches OpenAPI VerifyEmailResult. | | disposable | boolean | Throwaway domain | | role | boolean | Role-style local part (admin@, info@, …) | | free_provider | boolean | Large free-mail domains | | catch_all | boolean | Domain accepts arbitrary recipients | | smtp_blocked | boolean | Provider blocks SMTP probe — expected for Gmail/Outlook/Yahoo; use confidence | | mx_found | boolean | MX records present | | mx_host | string \| null | Primary MX host | | suggestion | string \| null | Typo hint (e.g. gmail.com for gnail.com) | | latency_ms | number | Round-trip processing time |


Agent decision guide (recommended)

Do not gate UX only on valid. Suggested order:

  1. suggestion set → offer a corrected address.
  2. disposable → reject.
  3. invalid / undeliverable → reject or ask for another address.
  4. catch_all → treat as higher risk; confirm with user or policy.
  5. smtp_blocked → often ~0.75 confidence — acceptable for many signups.
  6. unknown + mx_found + not smtp_blocked → SMTP inconclusive (common on org/M365); ~0.50 — confirm with user, not auto-reject.

Full matrix: Agent decision guide.


Error handling

Non-success HTTP responses throw TruvalError (extends Error). On 429, resetAt is set when the body includes reset_at.

import { createClient, TruvalError } from 'truval'

const truval = createClient(process.env.TRUVAL_API_KEY!)

try {
  const result = await truval.verify('[email protected]')
  console.log(result.status)
} catch (err) {
  if (err instanceof TruvalError) {
    console.error(err.status, err.resetAt, err.apiError?.error)
  }
  throw err
}

Management API client

For provisioning keys (sk_mgmt_...): lifecycle for standard keys (sk_live_...), usage, and billing portal.

import { createManagementClient } from 'truval'

const mgmt = createManagementClient(process.env.TRUVAL_PROVISIONING_KEY!)

const account = await mgmt.account.get()
const keys = await mgmt.keys.list()
const created = await mgmt.keys.create({ label: 'CI bot' })
await mgmt.keys.revoke('key_...')
const daily = await mgmt.usage.daily()
const summary = await mgmt.usage.summary() // free tier: quota-based calls_remaining; paid: billable
const { url } = await mgmt.billing.portal({ return_url: 'https://your-app.com/billing' })

Ecosystem

| Resource | URL | |----------|-----| | Docs | docs.truval.dev | | Dashboard & keys | dash.truval.dev | | OpenAPI 3.1 | api.truval.dev/openapi.json | | MCP server (Claude / Cursor) | docs.truval.dev/integrations/mcp | | npm package | npmjs.com/package/truval |


Issues

  • This SDK (types, docs, fetch client, npm packaging): open a GitHub issue on truval-dev/truval-sdk (also linked from npm).
  • API behavior, quotas, verification results, or downtime: see documentation and status first; use product support channels there if documented.

Include SDK version, runtime (Node/Bun/etc.), and a minimal code snippet when reporting bugs.

Pull requests

  1. Fork the repo and create a short-lived branch from main (e.g. fix/readme-typo, feat/better-error-message).

  2. Keep each PR focused — one logical change; split unrelated edits.

  3. In the description, say what changed and why, and link Fixes #123 if it closes an issue.

  4. Verify locally (from a checkout that contains this package):

    pnpm install
    pnpm run build
    pnpm run test

    (Adjust if you use npm: npm run build / npm test.)

  5. Match existing style (TypeScript, formatting, tone of docs). Avoid drive-by refactors outside the PR scope.

Contributing

  • Contributions are welcome under the same MIT license as this package; by opening a PR you agree your changes are licensed under MIT.
  • Improvements to types, README, error messages, and small ergonomic fixes are especially appreciated.
  • Verification logic and API semantics live on truval.dev’s servers; client PRs should not claim to change server behavior — use issues/docs for product feedback.

License

MIT