numberotp
v0.1.1
Published
Official NumberOTP API client — virtual numbers for SMS / OTP verification
Maintainers
Readme
numberotp (TypeScript / JavaScript)
The official client for the NumberOTP API: real phone numbers for SMS / OTP verification. Works in Node 20+, Deno, Bun, Cloudflare Workers, Vercel Edge and browsers, with zero dependencies.
npm install numberotpGet an API key at numberotp.com/dashboard/developer and set it as NOTP_API_KEY. Guides: numberotp.com/docs/sdks.
import { NumberOTP } from 'numberotp'
const notp = new NumberOTP() // reads NOTP_API_KEY
// Buy a UK WhatsApp number and wait for the code (refunded automatically if none arrives)
const act = await notp.activations.createAndWait(
{ service: 'wa', country: '16' },
{ onNumber: n => console.log('Use this number:', n.phoneNumber) },
)
console.log('Code:', act.otp)Finding codes
await notp.services.search({ q: 'discord.com' }) // → [{ code: 'ds', name: 'Discord' }]
await notp.prices.get({ service: 'wa' }) // price, stock and success rate by country and pool
await notp.countries.list()Numbers
const n = await notp.activations.create({ service: 'tg', country: '187', pool: 'auto', max_price: 3 })
const act = await notp.activations.waitForCode(n.data.id, { timeout: '20m' })
await notp.activations.resend(n.data.id) // another SMS on the same number
await notp.activations.finish(n.data.id) // done
await notp.activations.cancel(n.data.id) // no SMS? cancel → full refund
await notp.activations.list({ status: 'waiting' })waitForCode throws ActivationClosedError if the number expired or was canceled (it's refunded), and WaitTimeoutError if your timeout passes first.
Live events
for await (const e of notp.events.stream()) {
if (e.type === 'activation.code_received') console.log(e.data.otp)
}The stream reconnects by itself and resumes from where it left off, so no event is skipped.
Webhooks
import { verifyWebhook } from 'numberotp'
const ok = await verifyWebhook(rawBody, req.headers['x-numberotp-signature'], process.env.NOTP_WEBHOOK_SECRET!)Signing in users (apps, extensions, CLIs)
const notp = new NumberOTP({ onTokens: t => secureStore.save(t) }) // persist the rotating refresh token
await notp.auth.deviceLogin({ client: 'cli', onCode: c => console.log(c.user_code, c.verification_uri_complete) })
// or: await notp.auth.sendEmailCode({ email }); await notp.auth.signInWithEmailCode(email, code)
// or: await notp.auth.signInWithIdToken('apple', idToken, { nonce })Expired access tokens are refreshed automatically.
Reliability
- Every purchase, rental and top-up sends an
Idempotency-Key. Retries after a timeout can never buy twice. - Network errors, 429 and 5xx are retried with backoff, but only where retrying is safe.
- Errors are typed:
InsufficientBalanceError,NotFoundError(withcode: 'NO_NUMBERS_AVAILABLE'),ConflictError,AuthenticationErrorand so on. Each hasstatusand a stablecode.
All 62 API operations are available. Resellers get notp.reseller.* and notp.resellerPublic.*.
