TypeScript / JavaScript SDK
The truval package is the official TypeScript/JavaScript client. It wraps the same HTTP API as Email verify and the Management API with types that match the live OpenAPI spec.
Installation
Section titled “Installation”npm install truvalpnpm add truvalTypes are included. You need a runtime with global fetch (Node.js 18+, Bun, Deno, Cloudflare Workers, etc.).
Keep API keys server-side
Section titled “Keep API keys server-side”sk_live_... and sk_mgmt_... are secret. Do not put them in browser bundles, public client components, or any code shipped to end users. Call the SDK only from trusted server environments (API routes, Server Actions, Workers, cron). If the browser must trigger a check, use your own backend that holds the key, or async verify with a webhook so the client never sees the key.
Quick start
Section titled “Quick start”import { createClient } from 'truval'
const truval = createClient(process.env.TRUVAL_API_KEY!, { retryOnRateLimit: true, maxRetries: 3,})
const result = await truval.verify('user@example.com')console.log(result.status, result.confidence, result.smtp_blocked)Get a key at dash.truval.dev.
One-off call (no client instance)
Section titled “One-off call (no client instance)”import { verify } from 'truval'
const result = await verify('user@example.com', process.env.TRUVAL_API_KEY!)Client options
Section titled “Client options”| Option | Default | Purpose |
|---|---|---|
baseUrl | https://api.truval.dev | API origin (no trailing slash). |
retryOnRateLimit | false | On 429, wait until reset_at from the JSON body plus a small cushion (to avoid racing the window edge), then retry. The SDK adds 50ms. |
maxRetries | 3 | Max retry attempts after 429 (only when retryOnRateLimit is true). |
Verify API surface
Section titled “Verify API surface”| Method | Maps to | Notes |
|---|---|---|
verify(email) | POST /v1/email/verify | Returns a full VerifyResult. |
verifyAsync(email, webhook) | Same with webhook in body | 202 + job_id; result POSTed to your HTTPS URL. |
verifyBatch(emails) | POST /v1/email/verify/batch (repeated) | Arrays longer than 50 are split into chunks of 50. Chunks run sequentially to avoid rate-limit spikes. Results are in input order. |
verifyStream(emails) | POST /v1/email/verify/stream | NDJSON stream; yields each line as it arrives in completion order (not necessarily input order). |
How to interpret status, confidence, valid, and related fields is documented in Email verify and the Agent decision guide.
Batch example
Section titled “Batch example”const results = await truval.verifyBatch(['a@b.com', 'c@d.com'])for (const r of results) console.log(r.email, r.status)Streaming example
Section titled “Streaming example”for await (const r of truval.verifyStream(['a@b.com', 'c@d.com'])) { console.log(r.email, r.status)}Error handling
Section titled “Error handling”Non-success HTTP responses throw TruvalError (extends Error). On 429, resetAt is set when the body includes reset_at. When the API returns structured JSON, apiError may contain error, message, action, docs, and quota-related fields—see Error reference.
import { createClient, TruvalError } from 'truval'
const truval = createClient(process.env.TRUVAL_API_KEY!)
try { await truval.verify('user@example.com')} catch (err) { if (err instanceof TruvalError) { console.error(err.status, err.resetAt, err.apiError?.error) } throw err}Use exported types in your own code without digging through node_modules:
import type { VerifyResult, AsyncVerifyResult, TruvalError, ApiError, TruvalClient, TruvalClientOptions,} from 'truval'Management-related types (for example ManagementAccountResponse) are exported from the same entry point.
Management API client
Section titled “Management API client”Use a provisioning key (sk_mgmt_...) with createManagementClient for account info, API key lifecycle, usage, and Stripe billing portal URLs. Full route list and semantics: Management API.
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_id_here')
const daily = await mgmt.usage.daily()const summary = await mgmt.usage.summary()
const { url } = await mgmt.billing.portal({ return_url: 'https://your-app.com/billing',})On the free tier, usage.summary() quota semantics can differ from usage.daily() billable counts; see the JSDoc on ManagementUsageSummaryResponse in the package source or the management API docs.
Package and source
Section titled “Package and source”- npm: npmjs.com/package/truval
- OpenAPI: api.truval.dev/openapi.json
For SDK bugs and contributions: github.com/truval-dev/truval-sdk