{"_id":"@bounceshift/sdk","_rev":"3-cf12ed1ca15006619b5ade83b5163530","name":"@bounceshift/sdk","dist-tags":{"latest":"1.2.0"},"versions":{"1.0.0":{"name":"@bounceshift/sdk","version":"1.0.0","keywords":["bounceshift","email","email-validation","email-verification","deliverability","smtp"],"author":{"name":"BounceShift"},"license":"MIT","_id":"@bounceshift/sdk@1.0.0","maintainers":[{"name":"hussam3bd","email":"hussam3bd@gmail.com"}],"homepage":"https://bounceshift.com","bugs":{"url":"https://github.com/bounceshift/bounceshift-node/issues"},"dist":{"shasum":"2d47bf6db057ead8c32e059ee0dfd1580e4be40f","tarball":"https://registry.npmjs.org/@bounceshift/sdk/-/sdk-1.0.0.tgz","fileCount":9,"integrity":"sha512-WzDV/t494Xyry4ZhRl4PewOuhPXQ2YXzbEfW6Y71D2Yc7CsoTq5Hg1ogV/FxkGV80xKTQdVmT+0pTrPV8JzxSQ==","signatures":[{"sig":"MEYCIQDjfhgQwfrGDpYGzAQtdXtUKBxhoKbq1HCb9qsvEQdfrQIhALeKNyWcxBOPpNtV1aP5IZlD531bUzLcJjtiT3iu5Faa","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":110092},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"4acdc6ce1026d66f843fb78941654abfecab5842","scripts":{"test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run build && npm test"},"_npmUser":{"name":"hussam3bd","email":"hussam3bd@gmail.com"},"repository":{"url":"git+https://github.com/bounceshift/bounceshift-node.git","type":"git"},"_npmVersion":"10.9.7","description":"Official BounceShift TypeScript SDK — email validation and deliverability, with an Express middleware.","directories":{},"sideEffects":false,"_nodeVersion":"22.22.2","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","vitest":"^2.1.8","typescript":"^5.7.2","@types/node":"^22.10.0","@types/express":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.0.0_1782991284341_0.4855203299776214","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@bounceshift/sdk","version":"1.1.0","keywords":["bounceshift","email","email-validation","email-verification","deliverability","smtp"],"author":{"name":"BounceShift"},"license":"MIT","_id":"@bounceshift/sdk@1.1.0","maintainers":[{"name":"hussam3bd","email":"hussam3bd@gmail.com"}],"homepage":"https://bounceshift.com","bugs":{"url":"https://github.com/bounceshift/bounceshift-node/issues"},"dist":{"shasum":"6295dfe11b4e2e1470fed5d77c95b0abddaeb857","tarball":"https://registry.npmjs.org/@bounceshift/sdk/-/sdk-1.1.0.tgz","fileCount":9,"integrity":"sha512-e3RlaZxxkvhayxTJc919OP60OZ3qPo8xgAHcX7+ImY7JCqdgcu9BoWAAeHehHK5TrrhSIXNiM2POBkxfKJ/D0w==","signatures":[{"sig":"MEUCIFB9PKYM3zYk/SU1+Jt2rCEue3+c3FO1gayLi0XFJn5sAiEAsgACVxFYJ/EEuzSRO22751yjePzzaDvwSq0+VTz7SVI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":128804},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"e52b17832f4db798c8d524e9e37be769bf732502","scripts":{"test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run build && npm test"},"_npmUser":{"name":"hussam3bd","email":"hussam3bd@gmail.com"},"repository":{"url":"git+https://github.com/bounceshift/bounceshift-node.git","type":"git"},"_npmVersion":"10.9.7","description":"Official BounceShift TypeScript SDK — email validation and deliverability, with an Express middleware.","directories":{},"sideEffects":false,"_nodeVersion":"22.22.2","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","vitest":"^2.1.8","typescript":"^5.7.2","@types/node":"^22.10.0","@types/express":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.1.0_1783426183024_0.6506889394848228","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@bounceshift/sdk","version":"1.2.0","description":"Official BounceShift TypeScript SDK — email validation and deliverability, with an Express middleware.","license":"MIT","author":{"name":"BounceShift"},"homepage":"https://bounceshift.com","repository":{"type":"git","url":"git+https://github.com/bounceshift/bounceshift-node.git"},"bugs":{"url":"https://github.com/bounceshift/bounceshift-node/issues"},"keywords":["bounceshift","email","email-validation","email-verification","deliverability","smtp"],"type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"engines":{"node":">=18"},"sideEffects":false,"scripts":{"build":"tsup","test":"vitest run","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run build && npm test"},"devDependencies":{"@types/express":"^5.0.0","@types/node":"^22.10.0","tsup":"^8.3.5","typescript":"^5.7.2","vitest":"^2.1.8"},"_id":"@bounceshift/sdk@1.2.0","gitHead":"d286c0f7b1ad647dcb21d83493b43d22a67b9e7a","_nodeVersion":"22.22.2","_npmVersion":"10.9.7","dist":{"integrity":"sha512-y9pJLb9hjU8/Xsp5Iy+T9F5WWia39iDNGEr5fISrtIFxUGmFYxoke9oDXew4M426Ps+Sp7hzpSSFn6ZsrUFPFg==","shasum":"4994003b60e9ad9db7514c734db4d6d4f29e27bc","tarball":"https://registry.npmjs.org/@bounceshift/sdk/-/sdk-1.2.0.tgz","fileCount":9,"unpackedSize":146915,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDDQVwQgf6JobO56ym+M3E/7/PdMOAjx6e/54SNeJAYzgIhAMJ5gPrt3WO8MXVsQcMp7+Z7oEn20nkbtSbIRtXawFEF"}]},"_npmUser":{"name":"hussam3bd","email":"hussam3bd@gmail.com"},"directories":{},"maintainers":[{"name":"hussam3bd","email":"hussam3bd@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_1.2.0_1783934030990_0.9358647780428255"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-02T11:21:24.129Z","modified":"2026-07-13T09:13:51.243Z","1.0.0":"2026-07-02T11:21:24.512Z","1.1.0":"2026-07-07T12:09:43.191Z","1.2.0":"2026-07-13T09:13:51.114Z"},"bugs":{"url":"https://github.com/bounceshift/bounceshift-node/issues"},"author":{"name":"BounceShift"},"license":"MIT","homepage":"https://bounceshift.com","keywords":["bounceshift","email","email-validation","email-verification","deliverability","smtp"],"repository":{"type":"git","url":"git+https://github.com/bounceshift/bounceshift-node.git"},"description":"Official BounceShift TypeScript SDK — email validation and deliverability, with an Express middleware.","maintainers":[{"name":"hussam3bd","email":"hussam3bd@gmail.com"}],"readme":"# @bounceshift/sdk\n\nOfficial [BounceShift](https://bounceshift.com) TypeScript SDK — real-time email\nvalidation and deliverability, with a drop-in Express middleware for gating\nsignups.\n\n- Zero runtime dependencies (uses the global `fetch`, Node ≥ 18).\n- Dual ESM + CommonJS build with full TypeScript types.\n- Typed error classes, automatic retries with `Retry-After` support.\n\nAPI reference: <https://bounceshift.com/docs/api>\n\n## Install\n\n```bash\nnpm install @bounceshift/sdk\n```\n\n## Quickstart\n\n```ts\nimport { BounceShift, isSafeToSend, isSendable } from '@bounceshift/sdk';\n\nconst client = new BounceShift({\n  apiKey: process.env.BOUNCESHIFT_API_KEY!,\n  organizationId: process.env.BOUNCESHIFT_ORG_ID!,\n  // baseUrl defaults to https://api.bounceshift.com/v1 (must be HTTPS)\n  // timeoutMs defaults to 10000, retries defaults to 2\n});\n\nconst result = await client.validate('user@example.com');\n\nconsole.log(result.status);         // 'valid' | 'catch_all' | 'invalid' | ...\nconsole.log(result.confidence);     // 0–100\nconsole.log(result.smtpValid);      // boolean | null\nconsole.log(result.recommendation); // 'deliverable' | 'send_with_caution' | ...\nconsole.log(result.qualityScore);   // 0–100 | null\nconsole.log(result.explanation);    // plain-English verdict | null\nconsole.log(isSafeToSend(result));  // true when status is 'valid' or 'catch_all'\nconsole.log(isSendable(result));    // true when recommendation says to send\n```\n\n`validate()` returns a `ValidationResult` with camelCase fields mapped from the\nAPI's snake_case payload:\n\n| Field               | Type                        |\n| ------------------- | --------------------------- |\n| `email`             | `string`                    |\n| `status`            | `ValidationStatus`          |\n| `confidence`        | `number` (0–100)            |\n| `mxFound`           | `boolean`                   |\n| `smtpValid`         | `boolean \\| null`           |\n| `isDisposable`      | `boolean`                   |\n| `isCatchAll`        | `boolean`                   |\n| `isRoleAccount`     | `boolean`                   |\n| `fromCache`         | `boolean`                   |\n| `creditsUsed`       | `number`                    |\n| `result`            | `Record<string, unknown>`   |\n| `subStatus`         | `string \\| null`            |\n| `recommendation`    | `Recommendation \\| null`    |\n| `recommendationRaw` | `string \\| null`            |\n| `qualityScore`      | `number \\| null` (0–100)    |\n| `explanation`       | `string \\| null`            |\n\n`ValidationStatus` is one of:\n`valid`, `invalid`, `risky`, `catch_all`, `unknown`, `disposable`, `spamtrap`,\n`abuse`, `do_not_mail`.\n\n### Recommendation\n\n`recommendation` is the API's action-oriented deliverability verdict, surfaced\nas-is (the SDK does not re-derive it from `status`). It is one of:\n`deliverable`, `send_with_caution`, `risky`, `undeliverable`, `unknown`.\n\n`isSendable(result)` (or `isSendable(recommendation)`) returns `true` only for\n`deliverable` and `send_with_caution`.\n\nThe SDK tolerates the unexpected: if the API omits `recommendation` or sends a\nvalue this SDK version doesn't know, `recommendation` is `null` (the exact\nstring is still available on `recommendationRaw`) and `isSendable()` returns\n`false` — it never throws. `subStatus`, `qualityScore`, and `explanation` are\n`null` when the API omits them (e.g. some error paths).\n\n- `subStatus` — granular reason for the verdict (e.g. `smtp_verified`).\n- `qualityScore` — a 0–100 score modeled separately from `confidence`; it\n  currently tracks `confidence` but may diverge.\n- `explanation` — a plain-English sentence describing the verdict.\n\n## Error handling\n\nEvery failure throws a subclass of `BounceShiftError`:\n\n```ts\nimport {\n  BounceShift,\n  AuthenticationError,\n  InsufficientCreditsError,\n  ForbiddenError,\n  RateLimitError,\n  ApiError,\n  BounceShiftError,\n} from '@bounceshift/sdk';\n\ntry {\n  await client.validate('user@example.com');\n} catch (error) {\n  if (error instanceof InsufficientCreditsError) {\n    // 402 — top up credits\n  } else if (error instanceof RateLimitError) {\n    // 429 — error.retryAfter is the (clamped) seconds to wait\n  } else if (error instanceof AuthenticationError) {\n    // 401\n  } else if (error instanceof ForbiddenError) {\n    // 403\n  } else if (error instanceof ApiError) {\n    // any other non-2xx — error.statusCode, error.body\n  } else if (error instanceof BounceShiftError) {\n    // transport failure, timeout, or a malformed response\n  }\n}\n```\n\n`429` and `5xx` responses are retried automatically (up to `retries`), honoring\na numeric `Retry-After` header clamped to 60 seconds. Your API key is never\nlogged or included in error output.\n\n## Fail open — never block your users\n\nOn a hot path such as validate-on-signup, a validation problem should never\nblock the user. `validate()` throws; `validateSafe()` **never** does. If your\naccount runs out of credits, or the API is down or timing out, it returns a\ndegraded result instead of throwing, so you can let the address through:\n\n```ts\nimport { BounceShift, isDegraded, isSafeToSend } from '@bounceshift/sdk';\n\nconst client = new BounceShift({\n  apiKey: process.env.BOUNCESHIFT_API_KEY!,\n  organizationId: process.env.BOUNCESHIFT_ORG_ID!,\n  // Optional: observe every fail-open (out of credits, outage, timeout).\n  onDegraded: (error, email) => logger.warn('bounceshift degraded', { email, error }),\n});\n\nconst result = await client.validateSafe('user@example.com');\n\nif (isDegraded(result)) {\n  // We couldn't reach a verdict — let it through, and your onDegraded hook fired.\n} else if (!isSafeToSend(result)) {\n  // A real verdict came back and it's not safe — reject as usual.\n}\n```\n\nA degraded result has `status: 'unknown'`, `creditsUsed: 0`, and\n`isDegraded(result) === true`, so you can always tell \"we couldn't check\" apart\nfrom a genuine `unknown` verdict. `timeoutMs` bounds how long a stalled API can\nhold your request before `validateSafe()` gives up. Works on any stack —\nNext.js route handlers, Fastify, serverless, workers — not just Express.\n\n## Express middleware\n\n`deliverableEmail` validates an email on the request body and rejects\nundeliverable ones before your handler runs.\n\n```ts\nimport express from 'express';\nimport { BounceShift, deliverableEmail } from '@bounceshift/sdk';\n\nconst client = new BounceShift({\n  apiKey: process.env.BOUNCESHIFT_API_KEY!,\n  organizationId: process.env.BOUNCESHIFT_ORG_ID!,\n});\n\nconst app = express();\napp.use(express.json());\n\napp.post('/signup', deliverableEmail({ client }), (req, res) => {\n  // Only reached for deliverable emails.\n  res.json({ ok: true });\n});\n```\n\n### Policy\n\nBy default the middleware mirrors BounceShift's Laravel `Deliverable` rule and\nblocks **only** clearly bad addresses:\n\n- Blocked: `invalid`, `disposable`, `do_not_mail`, `abuse`, `spamtrap`\n- Allowed: `valid`, `catch_all`, `unknown`, `risky`\n\nOptions:\n\n| Option          | Default   | Effect                                                        |\n| --------------- | --------- | ------------------------------------------------------------- |\n| `client`        | —         | **Required.** A configured `BounceShift` instance.            |\n| `field`         | `'email'` | Body/query field to read the email from.                      |\n| `strict`        | `false`   | Also block `risky` and `unknown`.                             |\n| `minConfidence` | —         | Also block results with `confidence` below this threshold.    |\n| `status`        | `422`     | HTTP status returned on block.                                |\n| `message`       | —         | Error message returned on block.                              |\n| `onInvalid`     | —         | `(result, req, res, next)` handler run on block instead of the default JSON response. |\n\n### Fail-open by design\n\nIf the API is unreachable, times out, is rate limited, out of credits, or\nmisconfigured, the middleware **calls `next()`** and lets the request through —\neven in `strict` mode — so an outage never blocks your signups. It fails open\nvia the client's `validateSafe()`, so pass an `onDegraded` hook to the client\n(see [Fail open](#fail-open--never-block-your-users)) to log/alert when it does.\n(Unexpected non-SDK errors are forwarded to `next(error)`.)\n\n### ⚠️ `strict` / `minConfidence` can reject real users\n\nMany legitimate mailboxes on throttled SMTP infrastructure — notably\n**Outlook/Hotmail** and **Gmail** — routinely return a low-confidence\n`unknown` verdict because the provider greylists or rate-limits verification\nprobes. Enabling `strict` or a high `minConfidence` will reject those real\nusers. Prefer the lenient default unless you have a strong reason to trade\nsignup conversion for stricter filtering.\n\n## License\n\nMIT © BounceShift\n","readmeFilename":"README.md"}