Install and send your first SMS
npm install envoisms, then const client = new EnvoiSMSClient(process.env.ENVOISMS_API_KEY!). await client.send({ to: '+212600000000', message: '…', from: 'MyBusiness' }) returns the message id, which you poll with getMessage() and match in your webhooks.
- import { EnvoiSMSClient } from 'envoisms';
- from: your validated Sender ID, or omit it for your default
- sendBulk({ messages: [...], from }) for a bulk send; listMessages(50, 0) for recent sends
Retry-safe sends and typed errors
Every send() and sendBulk() carries an Idempotency-Key — generated, or pass idempotencyKey — so a retry after a timeout can never bill the same message twice. The client retries 5xx responses and network or timeout errors up to maxRetries times (2 by default) with exponential backoff, then throws EnvoiSMSError with statusCode and code properties.
- new EnvoiSMSClient({ apiKey, maxRetries: 3, timeoutMs: 20000 })
- err instanceof EnvoiSMSError → err.statusCode, err.code
SMS or WhatsApp, and the cascade
Default to SMS: it reaches every Moroccan mobile with no setup beyond the API key. channel: 'whatsapp' sends from your own connected WhatsApp Business number — 403 WHATSAPP_NOT_CONNECTED without one, 400 OUT_OF_24H_WINDOW for free text outside the 24-hour customer window, nothing charged in either case. Outside the window, pass an approved template. cascade: true drops back to SMS when the number is unreachable or has no WhatsApp.
- template: { name: 'order_shipped', language: 'fr', variables: ['89240'] }
- Common mistake: an SMS-style text with channel: 'whatsapp' because the customer uses WhatsApp — send it as SMS
OTP, webhooks and the account
client.sendOtp({ to, brand, code_length: 6, expiry: 600 }) returns a session_id; client.checkOtp({ session_id, code }) returns verified; getOtpSession() inspects a session without consuming an attempt. EnvoiSMSClient.verifyWebhookSignature(rawBody, signatureHeader, secret) checks the X-EnvoiSMS-Signature header against the raw body, not parsed JSON.
- sendOtp({ ..., channel: 'whatsapp' }): a WhatsApp code through the shared sender, no connection needed
- getBalance(), listPacks(), listPaymentMethods(), createTopup()
- analytics(30), createApiKey(), createOptout()