verifymailapi 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +160 -0
- package/dist/index.cjs +402 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +327 -0
- package/dist/index.d.ts +327 -0
- package/dist/index.js +366 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
interface ClientOptions {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
/** Defaults to https://api.verifymailapi.com */
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
/** Max retry attempts on retryable failures (429, 5xx). Default 2 (so up to 3 total tries). */
|
|
6
|
+
retries?: number;
|
|
7
|
+
/** Per-request timeout in ms. Default 30000. */
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
/** Override fetch — useful for tests or non-Node runtimes. */
|
|
10
|
+
fetch?: typeof fetch;
|
|
11
|
+
/** Default risk profile sent as X-Risk-Profile on every call (overridable per request). */
|
|
12
|
+
riskProfile?: "strict" | "balanced" | "permissive";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Response types — mirror the backend Pydantic models in app/models/check.py.
|
|
17
|
+
* Kept hand-written rather than codegen so the surface stays small and readable.
|
|
18
|
+
*/
|
|
19
|
+
type Recommendation = "allow" | "allow_with_flag" | "block";
|
|
20
|
+
type RiskLevel = "low" | "medium" | "high" | "critical";
|
|
21
|
+
type ConfidenceLevel = "low" | "medium" | "high";
|
|
22
|
+
type RiskProfile = "strict" | "balanced" | "permissive";
|
|
23
|
+
type ModelPhase = "bootstrap" | "calibrated" | "optimised";
|
|
24
|
+
type SignalDirection = "risk" | "trust";
|
|
25
|
+
interface Meta {
|
|
26
|
+
request_id: string;
|
|
27
|
+
email: string;
|
|
28
|
+
domain: string;
|
|
29
|
+
checked_at: string;
|
|
30
|
+
latency_ms: number;
|
|
31
|
+
api_version: string;
|
|
32
|
+
model_phase: ModelPhase;
|
|
33
|
+
model_version: string;
|
|
34
|
+
path_taken: string;
|
|
35
|
+
cached: boolean;
|
|
36
|
+
cache_age_seconds: number | null;
|
|
37
|
+
}
|
|
38
|
+
interface Verdict {
|
|
39
|
+
recommendation: Recommendation;
|
|
40
|
+
risk_level: RiskLevel;
|
|
41
|
+
disposable: boolean;
|
|
42
|
+
catch_all: boolean | null;
|
|
43
|
+
catch_all_checked: boolean;
|
|
44
|
+
valid_address: boolean;
|
|
45
|
+
safe_to_send: boolean;
|
|
46
|
+
summary: string;
|
|
47
|
+
degraded_mode?: boolean;
|
|
48
|
+
degraded_reason?: string | null;
|
|
49
|
+
}
|
|
50
|
+
interface ScoreComponents {
|
|
51
|
+
strong_signals: number;
|
|
52
|
+
corroborating: number;
|
|
53
|
+
trust_adjustments: number;
|
|
54
|
+
compounding_bonus: number;
|
|
55
|
+
final_clamped: number;
|
|
56
|
+
}
|
|
57
|
+
interface Thresholds {
|
|
58
|
+
block_at: number;
|
|
59
|
+
flag_at: number;
|
|
60
|
+
your_profile: RiskProfile;
|
|
61
|
+
}
|
|
62
|
+
interface CatchAllDetail {
|
|
63
|
+
detected: boolean;
|
|
64
|
+
probability: number;
|
|
65
|
+
confidence: number;
|
|
66
|
+
legitimate_use_likely: boolean;
|
|
67
|
+
type: "confirmed" | "suspected" | "cleared";
|
|
68
|
+
}
|
|
69
|
+
interface Score {
|
|
70
|
+
value: number;
|
|
71
|
+
confidence: number;
|
|
72
|
+
confidence_level: ConfidenceLevel;
|
|
73
|
+
components: ScoreComponents;
|
|
74
|
+
thresholds: Thresholds;
|
|
75
|
+
catch_all_detail: CatchAllDetail | null;
|
|
76
|
+
}
|
|
77
|
+
interface Signal {
|
|
78
|
+
name: string;
|
|
79
|
+
category: string;
|
|
80
|
+
direction: SignalDirection;
|
|
81
|
+
weight: number;
|
|
82
|
+
description: string;
|
|
83
|
+
value?: unknown;
|
|
84
|
+
unit?: string | null;
|
|
85
|
+
probe_result?: Record<string, unknown> | null;
|
|
86
|
+
extra?: Record<string, unknown>;
|
|
87
|
+
}
|
|
88
|
+
interface Compounding {
|
|
89
|
+
applied: boolean;
|
|
90
|
+
signal_count: number;
|
|
91
|
+
bonus_applied: number;
|
|
92
|
+
explanation: string;
|
|
93
|
+
}
|
|
94
|
+
interface Signals {
|
|
95
|
+
fired: Signal[];
|
|
96
|
+
trust_signals: Signal[];
|
|
97
|
+
suppressed?: {
|
|
98
|
+
name: string;
|
|
99
|
+
reason: string;
|
|
100
|
+
}[];
|
|
101
|
+
compounding: Compounding;
|
|
102
|
+
}
|
|
103
|
+
interface CheckStep {
|
|
104
|
+
name: string;
|
|
105
|
+
status: string;
|
|
106
|
+
duration_ms: number;
|
|
107
|
+
result: string | null;
|
|
108
|
+
probe_detail?: Record<string, unknown> | null;
|
|
109
|
+
}
|
|
110
|
+
interface ChecksBlock {
|
|
111
|
+
run: CheckStep[];
|
|
112
|
+
skipped?: CheckStep[];
|
|
113
|
+
failed?: CheckStep[];
|
|
114
|
+
path_explanation: string;
|
|
115
|
+
}
|
|
116
|
+
/** Full /v1/check response (5-block schema). */
|
|
117
|
+
interface CheckResponse {
|
|
118
|
+
meta: Meta;
|
|
119
|
+
verdict: Verdict;
|
|
120
|
+
score: Score;
|
|
121
|
+
signals: Signals;
|
|
122
|
+
checks: ChecksBlock;
|
|
123
|
+
}
|
|
124
|
+
interface BulkSummary {
|
|
125
|
+
total: number;
|
|
126
|
+
credits_charged: number;
|
|
127
|
+
credits_remaining: number;
|
|
128
|
+
elapsed_ms: number;
|
|
129
|
+
}
|
|
130
|
+
interface BulkCheckResponse {
|
|
131
|
+
items: CheckResponse[];
|
|
132
|
+
summary: BulkSummary;
|
|
133
|
+
}
|
|
134
|
+
/** One line from /v1/check/bulk/stream. */
|
|
135
|
+
type BulkStreamEvent = {
|
|
136
|
+
index: number;
|
|
137
|
+
result: CheckResponse;
|
|
138
|
+
} | {
|
|
139
|
+
event: "summary";
|
|
140
|
+
total: number;
|
|
141
|
+
credits_charged: number;
|
|
142
|
+
credits_remaining: number;
|
|
143
|
+
elapsed_ms: number;
|
|
144
|
+
};
|
|
145
|
+
interface AsyncCheckResponse {
|
|
146
|
+
request_id: string;
|
|
147
|
+
status: "pending";
|
|
148
|
+
preliminary: CheckResponse;
|
|
149
|
+
webhook_url: string;
|
|
150
|
+
estimated_completion_ms: number;
|
|
151
|
+
}
|
|
152
|
+
interface ReportRequest {
|
|
153
|
+
domain: string;
|
|
154
|
+
outcome: "confirmed_throwaway" | "confirmed_legitimate" | "suspected_throwaway";
|
|
155
|
+
notes?: string;
|
|
156
|
+
}
|
|
157
|
+
interface ReportResponse {
|
|
158
|
+
accepted: boolean;
|
|
159
|
+
queued_for_review: boolean;
|
|
160
|
+
review_sla_hours: number;
|
|
161
|
+
report_id: string;
|
|
162
|
+
message: string;
|
|
163
|
+
}
|
|
164
|
+
interface UsageMeResponse {
|
|
165
|
+
total_checks: number;
|
|
166
|
+
checks_this_period: number;
|
|
167
|
+
period_start: string;
|
|
168
|
+
blocks: number;
|
|
169
|
+
allow_with_flag: number;
|
|
170
|
+
allows: number;
|
|
171
|
+
avg_latency_ms: number;
|
|
172
|
+
cache_hit_rate: number;
|
|
173
|
+
credit_balance_checks: number;
|
|
174
|
+
}
|
|
175
|
+
interface StatusResponse {
|
|
176
|
+
status: "ok" | "degraded";
|
|
177
|
+
components: {
|
|
178
|
+
redis: "ok" | "degraded";
|
|
179
|
+
postgres: "ok" | "degraded";
|
|
180
|
+
dns: "ok" | "degraded";
|
|
181
|
+
};
|
|
182
|
+
latency_ms: number;
|
|
183
|
+
}
|
|
184
|
+
/** Async webhook event posted to the customer's webhook_url. */
|
|
185
|
+
interface CheckCompletedEvent {
|
|
186
|
+
request_id: string;
|
|
187
|
+
event: "check.completed";
|
|
188
|
+
result: CheckResponse;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Error class hierarchy. All HTTP errors from the API are translated into one
|
|
193
|
+
* of these — customers can `instanceof` them to branch cleanly:
|
|
194
|
+
*
|
|
195
|
+
* try { await vm.check(email) }
|
|
196
|
+
* catch (e) {
|
|
197
|
+
* if (e instanceof QuotaExceededError) return showBilling();
|
|
198
|
+
* if (e instanceof RateLimitError) return retryLater(e.retryAfter);
|
|
199
|
+
* if (e instanceof VerifyMailError) return logAndShowGeneric(e);
|
|
200
|
+
* throw e;
|
|
201
|
+
* }
|
|
202
|
+
*/
|
|
203
|
+
interface ErrorBody {
|
|
204
|
+
code: string;
|
|
205
|
+
http_status: number;
|
|
206
|
+
message: string;
|
|
207
|
+
request_id?: string;
|
|
208
|
+
docs_url?: string;
|
|
209
|
+
limit?: number;
|
|
210
|
+
reset_at?: string;
|
|
211
|
+
upgrade_url?: string;
|
|
212
|
+
}
|
|
213
|
+
declare class VerifyMailError extends Error {
|
|
214
|
+
readonly code: string;
|
|
215
|
+
readonly status: number;
|
|
216
|
+
readonly requestId: string | undefined;
|
|
217
|
+
readonly docsUrl: string | undefined;
|
|
218
|
+
readonly body: ErrorBody | undefined;
|
|
219
|
+
constructor(message: string, opts?: {
|
|
220
|
+
code?: string;
|
|
221
|
+
status?: number;
|
|
222
|
+
requestId?: string;
|
|
223
|
+
docsUrl?: string;
|
|
224
|
+
body?: ErrorBody;
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
declare class InvalidApiKeyError extends VerifyMailError {
|
|
228
|
+
constructor(opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]>);
|
|
229
|
+
}
|
|
230
|
+
declare class QuotaExceededError extends VerifyMailError {
|
|
231
|
+
readonly upgradeUrl: string | undefined;
|
|
232
|
+
constructor(opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]>);
|
|
233
|
+
}
|
|
234
|
+
declare class RateLimitError extends VerifyMailError {
|
|
235
|
+
readonly retryAfter: number;
|
|
236
|
+
readonly limit: number | undefined;
|
|
237
|
+
readonly resetAt: string | undefined;
|
|
238
|
+
constructor(opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]> & {
|
|
239
|
+
retryAfter: number;
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
declare class IdempotencyConflictError extends VerifyMailError {
|
|
243
|
+
constructor(opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]>);
|
|
244
|
+
}
|
|
245
|
+
declare class ValidationError extends VerifyMailError {
|
|
246
|
+
constructor(message: string, opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]>);
|
|
247
|
+
}
|
|
248
|
+
declare class ServiceDegradedError extends VerifyMailError {
|
|
249
|
+
constructor(opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]>);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Map an HTTP response to the right error class. The backend's error envelope
|
|
253
|
+
* is `{ error: { code, http_status, message, ... } }`.
|
|
254
|
+
*/
|
|
255
|
+
declare function errorFromResponse(status: number, body: {
|
|
256
|
+
error?: ErrorBody;
|
|
257
|
+
} | unknown, retryAfterHeader?: string | null): VerifyMailError;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Verify an incoming webhook signature from a `/v1/check/async` completion.
|
|
261
|
+
*
|
|
262
|
+
* const ok = verifyWebhook(rawBody, req.header("X-VerifyMail-Signature"), secret);
|
|
263
|
+
* if (!ok) return res.status(401).end();
|
|
264
|
+
*
|
|
265
|
+
* Pass the *raw* request body bytes — not the parsed JSON. In Express:
|
|
266
|
+
* app.post("/webhook", express.raw({ type: "application/json" }), handler)
|
|
267
|
+
*/
|
|
268
|
+
declare function verifyWebhook(rawBody: Buffer | Uint8Array | string, signatureHeader: string | null | undefined, secret: string): boolean;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Official SDK for the VerifyMail API.
|
|
272
|
+
*
|
|
273
|
+
* import { VerifyMail } from "verifymailapi";
|
|
274
|
+
* const vm = new VerifyMail({ apiKey: process.env.VERIFYMAIL_KEY! });
|
|
275
|
+
* const r = await vm.check("user@example.com");
|
|
276
|
+
* if (r.verdict.recommendation === "block") { ... }
|
|
277
|
+
*
|
|
278
|
+
* Docs: https://verifymailapi.com/docs
|
|
279
|
+
*/
|
|
280
|
+
|
|
281
|
+
interface CheckOptions {
|
|
282
|
+
/** Override the SDK-wide risk profile for this call. */
|
|
283
|
+
riskProfile?: "strict" | "balanced" | "permissive";
|
|
284
|
+
/** Make the call idempotent. Pass `true` to auto-generate a UUID, or a fixed string. */
|
|
285
|
+
idempotencyKey?: string | boolean;
|
|
286
|
+
}
|
|
287
|
+
interface AsyncCheckArgs {
|
|
288
|
+
email: string;
|
|
289
|
+
webhookUrl: string;
|
|
290
|
+
/** Optional HMAC-SHA256 key used to sign the final webhook payload. */
|
|
291
|
+
webhookSecret?: string;
|
|
292
|
+
}
|
|
293
|
+
declare class VerifyMail {
|
|
294
|
+
private readonly http;
|
|
295
|
+
constructor(opts: ClientOptions);
|
|
296
|
+
/** Check a single email. Charges 1 credit. */
|
|
297
|
+
check(email: string, opts?: CheckOptions): Promise<CheckResponse>;
|
|
298
|
+
/** Check a domain only (no local part). Charges 1 credit. */
|
|
299
|
+
checkDomain(domain: string, opts?: CheckOptions): Promise<CheckResponse>;
|
|
300
|
+
/** Bulk check 1–100 emails. Charges N credits up front (all-or-nothing). */
|
|
301
|
+
checkBulk(emails: string[], opts?: CheckOptions): Promise<BulkCheckResponse>;
|
|
302
|
+
/**
|
|
303
|
+
* Stream bulk-check results as each row completes. Calls `onEvent` once
|
|
304
|
+
* per result (in finish-order) plus once with a final `{event: "summary"}`.
|
|
305
|
+
*
|
|
306
|
+
* await vm.checkBulkStream(emails, (e) => {
|
|
307
|
+
* if ("event" in e) console.log("done", e);
|
|
308
|
+
* else processRow(e.index, e.result);
|
|
309
|
+
* });
|
|
310
|
+
*/
|
|
311
|
+
checkBulkStream(emails: string[], onEvent: (e: BulkStreamEvent) => void | Promise<void>, opts?: Omit<CheckOptions, "idempotencyKey">): Promise<void>;
|
|
312
|
+
/**
|
|
313
|
+
* Async deep check. Returns 202 immediately with a preliminary verdict;
|
|
314
|
+
* VerifyMail POSTs the final result to your webhook URL once the deep
|
|
315
|
+
* SMTP probe completes. Verify the signature with `verifyWebhook()` in
|
|
316
|
+
* your handler before trusting the payload.
|
|
317
|
+
*/
|
|
318
|
+
checkAsync(args: AsyncCheckArgs, opts?: CheckOptions): Promise<AsyncCheckResponse>;
|
|
319
|
+
/** File a /v1/report for a domain outcome (feedback loop). */
|
|
320
|
+
report(req: ReportRequest): Promise<ReportResponse>;
|
|
321
|
+
/** Programmatic equivalent of the dashboard's Usage summary. */
|
|
322
|
+
usage(): Promise<UsageMeResponse>;
|
|
323
|
+
/** Component health (Redis / Postgres / DNS). Always returns 200. */
|
|
324
|
+
status(): Promise<StatusResponse>;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
export { type AsyncCheckArgs, type AsyncCheckResponse, type BulkCheckResponse, type BulkStreamEvent, type BulkSummary, type CatchAllDetail, type CheckCompletedEvent, type CheckOptions, type CheckResponse, type CheckStep, type ChecksBlock, type Compounding, type ConfidenceLevel, type ErrorBody, IdempotencyConflictError, InvalidApiKeyError, type Meta, type ModelPhase, QuotaExceededError, RateLimitError, type Recommendation, type ReportRequest, type ReportResponse, type RiskLevel, type RiskProfile, type Score, type ScoreComponents, ServiceDegradedError, type Signal, type SignalDirection, type Signals, type StatusResponse, type Thresholds, type UsageMeResponse, ValidationError, type Verdict, VerifyMail, VerifyMailError, VerifyMail as default, errorFromResponse, verifyWebhook };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
interface ClientOptions {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
/** Defaults to https://api.verifymailapi.com */
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
/** Max retry attempts on retryable failures (429, 5xx). Default 2 (so up to 3 total tries). */
|
|
6
|
+
retries?: number;
|
|
7
|
+
/** Per-request timeout in ms. Default 30000. */
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
/** Override fetch — useful for tests or non-Node runtimes. */
|
|
10
|
+
fetch?: typeof fetch;
|
|
11
|
+
/** Default risk profile sent as X-Risk-Profile on every call (overridable per request). */
|
|
12
|
+
riskProfile?: "strict" | "balanced" | "permissive";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Response types — mirror the backend Pydantic models in app/models/check.py.
|
|
17
|
+
* Kept hand-written rather than codegen so the surface stays small and readable.
|
|
18
|
+
*/
|
|
19
|
+
type Recommendation = "allow" | "allow_with_flag" | "block";
|
|
20
|
+
type RiskLevel = "low" | "medium" | "high" | "critical";
|
|
21
|
+
type ConfidenceLevel = "low" | "medium" | "high";
|
|
22
|
+
type RiskProfile = "strict" | "balanced" | "permissive";
|
|
23
|
+
type ModelPhase = "bootstrap" | "calibrated" | "optimised";
|
|
24
|
+
type SignalDirection = "risk" | "trust";
|
|
25
|
+
interface Meta {
|
|
26
|
+
request_id: string;
|
|
27
|
+
email: string;
|
|
28
|
+
domain: string;
|
|
29
|
+
checked_at: string;
|
|
30
|
+
latency_ms: number;
|
|
31
|
+
api_version: string;
|
|
32
|
+
model_phase: ModelPhase;
|
|
33
|
+
model_version: string;
|
|
34
|
+
path_taken: string;
|
|
35
|
+
cached: boolean;
|
|
36
|
+
cache_age_seconds: number | null;
|
|
37
|
+
}
|
|
38
|
+
interface Verdict {
|
|
39
|
+
recommendation: Recommendation;
|
|
40
|
+
risk_level: RiskLevel;
|
|
41
|
+
disposable: boolean;
|
|
42
|
+
catch_all: boolean | null;
|
|
43
|
+
catch_all_checked: boolean;
|
|
44
|
+
valid_address: boolean;
|
|
45
|
+
safe_to_send: boolean;
|
|
46
|
+
summary: string;
|
|
47
|
+
degraded_mode?: boolean;
|
|
48
|
+
degraded_reason?: string | null;
|
|
49
|
+
}
|
|
50
|
+
interface ScoreComponents {
|
|
51
|
+
strong_signals: number;
|
|
52
|
+
corroborating: number;
|
|
53
|
+
trust_adjustments: number;
|
|
54
|
+
compounding_bonus: number;
|
|
55
|
+
final_clamped: number;
|
|
56
|
+
}
|
|
57
|
+
interface Thresholds {
|
|
58
|
+
block_at: number;
|
|
59
|
+
flag_at: number;
|
|
60
|
+
your_profile: RiskProfile;
|
|
61
|
+
}
|
|
62
|
+
interface CatchAllDetail {
|
|
63
|
+
detected: boolean;
|
|
64
|
+
probability: number;
|
|
65
|
+
confidence: number;
|
|
66
|
+
legitimate_use_likely: boolean;
|
|
67
|
+
type: "confirmed" | "suspected" | "cleared";
|
|
68
|
+
}
|
|
69
|
+
interface Score {
|
|
70
|
+
value: number;
|
|
71
|
+
confidence: number;
|
|
72
|
+
confidence_level: ConfidenceLevel;
|
|
73
|
+
components: ScoreComponents;
|
|
74
|
+
thresholds: Thresholds;
|
|
75
|
+
catch_all_detail: CatchAllDetail | null;
|
|
76
|
+
}
|
|
77
|
+
interface Signal {
|
|
78
|
+
name: string;
|
|
79
|
+
category: string;
|
|
80
|
+
direction: SignalDirection;
|
|
81
|
+
weight: number;
|
|
82
|
+
description: string;
|
|
83
|
+
value?: unknown;
|
|
84
|
+
unit?: string | null;
|
|
85
|
+
probe_result?: Record<string, unknown> | null;
|
|
86
|
+
extra?: Record<string, unknown>;
|
|
87
|
+
}
|
|
88
|
+
interface Compounding {
|
|
89
|
+
applied: boolean;
|
|
90
|
+
signal_count: number;
|
|
91
|
+
bonus_applied: number;
|
|
92
|
+
explanation: string;
|
|
93
|
+
}
|
|
94
|
+
interface Signals {
|
|
95
|
+
fired: Signal[];
|
|
96
|
+
trust_signals: Signal[];
|
|
97
|
+
suppressed?: {
|
|
98
|
+
name: string;
|
|
99
|
+
reason: string;
|
|
100
|
+
}[];
|
|
101
|
+
compounding: Compounding;
|
|
102
|
+
}
|
|
103
|
+
interface CheckStep {
|
|
104
|
+
name: string;
|
|
105
|
+
status: string;
|
|
106
|
+
duration_ms: number;
|
|
107
|
+
result: string | null;
|
|
108
|
+
probe_detail?: Record<string, unknown> | null;
|
|
109
|
+
}
|
|
110
|
+
interface ChecksBlock {
|
|
111
|
+
run: CheckStep[];
|
|
112
|
+
skipped?: CheckStep[];
|
|
113
|
+
failed?: CheckStep[];
|
|
114
|
+
path_explanation: string;
|
|
115
|
+
}
|
|
116
|
+
/** Full /v1/check response (5-block schema). */
|
|
117
|
+
interface CheckResponse {
|
|
118
|
+
meta: Meta;
|
|
119
|
+
verdict: Verdict;
|
|
120
|
+
score: Score;
|
|
121
|
+
signals: Signals;
|
|
122
|
+
checks: ChecksBlock;
|
|
123
|
+
}
|
|
124
|
+
interface BulkSummary {
|
|
125
|
+
total: number;
|
|
126
|
+
credits_charged: number;
|
|
127
|
+
credits_remaining: number;
|
|
128
|
+
elapsed_ms: number;
|
|
129
|
+
}
|
|
130
|
+
interface BulkCheckResponse {
|
|
131
|
+
items: CheckResponse[];
|
|
132
|
+
summary: BulkSummary;
|
|
133
|
+
}
|
|
134
|
+
/** One line from /v1/check/bulk/stream. */
|
|
135
|
+
type BulkStreamEvent = {
|
|
136
|
+
index: number;
|
|
137
|
+
result: CheckResponse;
|
|
138
|
+
} | {
|
|
139
|
+
event: "summary";
|
|
140
|
+
total: number;
|
|
141
|
+
credits_charged: number;
|
|
142
|
+
credits_remaining: number;
|
|
143
|
+
elapsed_ms: number;
|
|
144
|
+
};
|
|
145
|
+
interface AsyncCheckResponse {
|
|
146
|
+
request_id: string;
|
|
147
|
+
status: "pending";
|
|
148
|
+
preliminary: CheckResponse;
|
|
149
|
+
webhook_url: string;
|
|
150
|
+
estimated_completion_ms: number;
|
|
151
|
+
}
|
|
152
|
+
interface ReportRequest {
|
|
153
|
+
domain: string;
|
|
154
|
+
outcome: "confirmed_throwaway" | "confirmed_legitimate" | "suspected_throwaway";
|
|
155
|
+
notes?: string;
|
|
156
|
+
}
|
|
157
|
+
interface ReportResponse {
|
|
158
|
+
accepted: boolean;
|
|
159
|
+
queued_for_review: boolean;
|
|
160
|
+
review_sla_hours: number;
|
|
161
|
+
report_id: string;
|
|
162
|
+
message: string;
|
|
163
|
+
}
|
|
164
|
+
interface UsageMeResponse {
|
|
165
|
+
total_checks: number;
|
|
166
|
+
checks_this_period: number;
|
|
167
|
+
period_start: string;
|
|
168
|
+
blocks: number;
|
|
169
|
+
allow_with_flag: number;
|
|
170
|
+
allows: number;
|
|
171
|
+
avg_latency_ms: number;
|
|
172
|
+
cache_hit_rate: number;
|
|
173
|
+
credit_balance_checks: number;
|
|
174
|
+
}
|
|
175
|
+
interface StatusResponse {
|
|
176
|
+
status: "ok" | "degraded";
|
|
177
|
+
components: {
|
|
178
|
+
redis: "ok" | "degraded";
|
|
179
|
+
postgres: "ok" | "degraded";
|
|
180
|
+
dns: "ok" | "degraded";
|
|
181
|
+
};
|
|
182
|
+
latency_ms: number;
|
|
183
|
+
}
|
|
184
|
+
/** Async webhook event posted to the customer's webhook_url. */
|
|
185
|
+
interface CheckCompletedEvent {
|
|
186
|
+
request_id: string;
|
|
187
|
+
event: "check.completed";
|
|
188
|
+
result: CheckResponse;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Error class hierarchy. All HTTP errors from the API are translated into one
|
|
193
|
+
* of these — customers can `instanceof` them to branch cleanly:
|
|
194
|
+
*
|
|
195
|
+
* try { await vm.check(email) }
|
|
196
|
+
* catch (e) {
|
|
197
|
+
* if (e instanceof QuotaExceededError) return showBilling();
|
|
198
|
+
* if (e instanceof RateLimitError) return retryLater(e.retryAfter);
|
|
199
|
+
* if (e instanceof VerifyMailError) return logAndShowGeneric(e);
|
|
200
|
+
* throw e;
|
|
201
|
+
* }
|
|
202
|
+
*/
|
|
203
|
+
interface ErrorBody {
|
|
204
|
+
code: string;
|
|
205
|
+
http_status: number;
|
|
206
|
+
message: string;
|
|
207
|
+
request_id?: string;
|
|
208
|
+
docs_url?: string;
|
|
209
|
+
limit?: number;
|
|
210
|
+
reset_at?: string;
|
|
211
|
+
upgrade_url?: string;
|
|
212
|
+
}
|
|
213
|
+
declare class VerifyMailError extends Error {
|
|
214
|
+
readonly code: string;
|
|
215
|
+
readonly status: number;
|
|
216
|
+
readonly requestId: string | undefined;
|
|
217
|
+
readonly docsUrl: string | undefined;
|
|
218
|
+
readonly body: ErrorBody | undefined;
|
|
219
|
+
constructor(message: string, opts?: {
|
|
220
|
+
code?: string;
|
|
221
|
+
status?: number;
|
|
222
|
+
requestId?: string;
|
|
223
|
+
docsUrl?: string;
|
|
224
|
+
body?: ErrorBody;
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
declare class InvalidApiKeyError extends VerifyMailError {
|
|
228
|
+
constructor(opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]>);
|
|
229
|
+
}
|
|
230
|
+
declare class QuotaExceededError extends VerifyMailError {
|
|
231
|
+
readonly upgradeUrl: string | undefined;
|
|
232
|
+
constructor(opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]>);
|
|
233
|
+
}
|
|
234
|
+
declare class RateLimitError extends VerifyMailError {
|
|
235
|
+
readonly retryAfter: number;
|
|
236
|
+
readonly limit: number | undefined;
|
|
237
|
+
readonly resetAt: string | undefined;
|
|
238
|
+
constructor(opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]> & {
|
|
239
|
+
retryAfter: number;
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
declare class IdempotencyConflictError extends VerifyMailError {
|
|
243
|
+
constructor(opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]>);
|
|
244
|
+
}
|
|
245
|
+
declare class ValidationError extends VerifyMailError {
|
|
246
|
+
constructor(message: string, opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]>);
|
|
247
|
+
}
|
|
248
|
+
declare class ServiceDegradedError extends VerifyMailError {
|
|
249
|
+
constructor(opts: NonNullable<ConstructorParameters<typeof VerifyMailError>[1]>);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Map an HTTP response to the right error class. The backend's error envelope
|
|
253
|
+
* is `{ error: { code, http_status, message, ... } }`.
|
|
254
|
+
*/
|
|
255
|
+
declare function errorFromResponse(status: number, body: {
|
|
256
|
+
error?: ErrorBody;
|
|
257
|
+
} | unknown, retryAfterHeader?: string | null): VerifyMailError;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Verify an incoming webhook signature from a `/v1/check/async` completion.
|
|
261
|
+
*
|
|
262
|
+
* const ok = verifyWebhook(rawBody, req.header("X-VerifyMail-Signature"), secret);
|
|
263
|
+
* if (!ok) return res.status(401).end();
|
|
264
|
+
*
|
|
265
|
+
* Pass the *raw* request body bytes — not the parsed JSON. In Express:
|
|
266
|
+
* app.post("/webhook", express.raw({ type: "application/json" }), handler)
|
|
267
|
+
*/
|
|
268
|
+
declare function verifyWebhook(rawBody: Buffer | Uint8Array | string, signatureHeader: string | null | undefined, secret: string): boolean;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Official SDK for the VerifyMail API.
|
|
272
|
+
*
|
|
273
|
+
* import { VerifyMail } from "verifymailapi";
|
|
274
|
+
* const vm = new VerifyMail({ apiKey: process.env.VERIFYMAIL_KEY! });
|
|
275
|
+
* const r = await vm.check("user@example.com");
|
|
276
|
+
* if (r.verdict.recommendation === "block") { ... }
|
|
277
|
+
*
|
|
278
|
+
* Docs: https://verifymailapi.com/docs
|
|
279
|
+
*/
|
|
280
|
+
|
|
281
|
+
interface CheckOptions {
|
|
282
|
+
/** Override the SDK-wide risk profile for this call. */
|
|
283
|
+
riskProfile?: "strict" | "balanced" | "permissive";
|
|
284
|
+
/** Make the call idempotent. Pass `true` to auto-generate a UUID, or a fixed string. */
|
|
285
|
+
idempotencyKey?: string | boolean;
|
|
286
|
+
}
|
|
287
|
+
interface AsyncCheckArgs {
|
|
288
|
+
email: string;
|
|
289
|
+
webhookUrl: string;
|
|
290
|
+
/** Optional HMAC-SHA256 key used to sign the final webhook payload. */
|
|
291
|
+
webhookSecret?: string;
|
|
292
|
+
}
|
|
293
|
+
declare class VerifyMail {
|
|
294
|
+
private readonly http;
|
|
295
|
+
constructor(opts: ClientOptions);
|
|
296
|
+
/** Check a single email. Charges 1 credit. */
|
|
297
|
+
check(email: string, opts?: CheckOptions): Promise<CheckResponse>;
|
|
298
|
+
/** Check a domain only (no local part). Charges 1 credit. */
|
|
299
|
+
checkDomain(domain: string, opts?: CheckOptions): Promise<CheckResponse>;
|
|
300
|
+
/** Bulk check 1–100 emails. Charges N credits up front (all-or-nothing). */
|
|
301
|
+
checkBulk(emails: string[], opts?: CheckOptions): Promise<BulkCheckResponse>;
|
|
302
|
+
/**
|
|
303
|
+
* Stream bulk-check results as each row completes. Calls `onEvent` once
|
|
304
|
+
* per result (in finish-order) plus once with a final `{event: "summary"}`.
|
|
305
|
+
*
|
|
306
|
+
* await vm.checkBulkStream(emails, (e) => {
|
|
307
|
+
* if ("event" in e) console.log("done", e);
|
|
308
|
+
* else processRow(e.index, e.result);
|
|
309
|
+
* });
|
|
310
|
+
*/
|
|
311
|
+
checkBulkStream(emails: string[], onEvent: (e: BulkStreamEvent) => void | Promise<void>, opts?: Omit<CheckOptions, "idempotencyKey">): Promise<void>;
|
|
312
|
+
/**
|
|
313
|
+
* Async deep check. Returns 202 immediately with a preliminary verdict;
|
|
314
|
+
* VerifyMail POSTs the final result to your webhook URL once the deep
|
|
315
|
+
* SMTP probe completes. Verify the signature with `verifyWebhook()` in
|
|
316
|
+
* your handler before trusting the payload.
|
|
317
|
+
*/
|
|
318
|
+
checkAsync(args: AsyncCheckArgs, opts?: CheckOptions): Promise<AsyncCheckResponse>;
|
|
319
|
+
/** File a /v1/report for a domain outcome (feedback loop). */
|
|
320
|
+
report(req: ReportRequest): Promise<ReportResponse>;
|
|
321
|
+
/** Programmatic equivalent of the dashboard's Usage summary. */
|
|
322
|
+
usage(): Promise<UsageMeResponse>;
|
|
323
|
+
/** Component health (Redis / Postgres / DNS). Always returns 200. */
|
|
324
|
+
status(): Promise<StatusResponse>;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
export { type AsyncCheckArgs, type AsyncCheckResponse, type BulkCheckResponse, type BulkStreamEvent, type BulkSummary, type CatchAllDetail, type CheckCompletedEvent, type CheckOptions, type CheckResponse, type CheckStep, type ChecksBlock, type Compounding, type ConfidenceLevel, type ErrorBody, IdempotencyConflictError, InvalidApiKeyError, type Meta, type ModelPhase, QuotaExceededError, RateLimitError, type Recommendation, type ReportRequest, type ReportResponse, type RiskLevel, type RiskProfile, type Score, type ScoreComponents, ServiceDegradedError, type Signal, type SignalDirection, type Signals, type StatusResponse, type Thresholds, type UsageMeResponse, ValidationError, type Verdict, VerifyMail, VerifyMailError, VerifyMail as default, errorFromResponse, verifyWebhook };
|