wenova-sms-otp
v1.2.0
Published
SMS/OTP package via Wenova API
Readme
wenova-sms-otp
SMS/OTP sending package via Wenova API.
Recommended service: WENOVA Link – SMS OTP & Email API — #1 SMS OTP service in Laos (ລາວ).
Installation
npm i wenova-sms-otpUsage
Use either API Token or Script ID (at least one required).
const { sendOtp } = require('wenova-sms-otp');
// Using API Token
const sms = await sendOtp({
header: 'WNV-OTP',
phoneNumber: '2012345678',
message: 'Your OTP is: 123456',
token: 'your-token',
usePackage: true,
});
// Check gateway delivery (SMS layer, not Wenova business code)
if (sms.resultCode === '20000') {
console.log('Sent:', sms.resultDesc);
}
// Or using Script ID
await sendOtp({
header: 'WNV-OTP',
phoneNumber: '2012345678',
message: 'Your OTP is: 123456',
scriptId: 1,
usePackage: false,
});Errors (Wenova 5-digit code)
When the API rejects the request, the thrown Error includes:
| Property | Description |
|----------|-------------|
| message | Human-readable text from API |
| code | Wenova business code (e.g. 30101, 30105, 30501) |
| path | Request path (e.g. /sms/package) |
| method | HTTP method |
| httpStatus | HTTP status line (e.g. 400, 401) |
try {
await sendOtp({ /* ... */ });
} catch (err) {
console.error(`[${err.code}] ${err.message}`); // e.g. [30105] SMS package quota is insufficient
}Common codes for POST /sms/package:
| Code | Meaning |
|------|---------|
| 30101 | Missing both token and scriptId |
| 30102 | Links not allowed in message |
| 30105 | SMS package quota insufficient (usePackage: true) |
| 30106 | Wallet balance insufficient (usePackage: false) |
| 30307 | Token not found |
| 30308 | Script ID not found |
| 30501 | Rate limit exceeded |
| 90101 | Validation failed (phone format, message length, etc.) |
| 90901 | Internal server error |
Error JSON body shape (no statusCode in body):
{
"code": 30101,
"message": "Either token or scriptId is required",
"path": "/sms/package",
"method": "POST"
}API
sendOtp(data)
Sends SMS/OTP via Wenova API (POST /sms/package).
Parameters: (provide either token or scriptId, or both)
data.header(string): SMS header (e.g.WNV-OTP,WNV-info)data.phoneNumber(string): Recipient number — 10 digits, must start with20(e.g.2012345678)data.message(string): Message contentdata.token(string, optional): API Token (script token)data.scriptId(number, optional): Script IDdata.usePackage(boolean, required): how to charge when the SMS is delivered successfully — see belowdata.baseUrl(string, optional): API base URL (default:https://apimicroservices.wenova.fun)data.rawResponse(boolean, optional): iftrue, return the full API JSON including{ success, code, message, data }
usePackage — payment source
| Value | Meaning |
|-------|---------|
| true | Deduct SMS package quota (segments). Requires an active OTP/SMS package on the account (totalSms − usedSmsCount must cover the message segment count). Does not charge LAK from wallet on success. Typical for apps that bought a monthly SMS bundle. |
| false | Deduct wallet balance in LAK: segment count × 250 LAK. Requires enough wallet balance before send. Top up in Dashboard → Top-up. |
- Charging happens only after the operator reports success (
resultCode20000orresultDescsuccess). - Failed sends do not deduct package quota or wallet.
- You still need a wallet record on the account even when
usePackageistrue.
Success response (v1.2+)
The API wraps successful responses:
{
"success": true,
"code": 90001,
"message": "Operation completed successfully",
"data": {
"id": 1,
"resultCode": "20000",
"resultDesc": "success",
"transaction_id": "WENOVA...",
"phoneNumber": "2012345678",
"segmentCount": 1
}
}By default, sendOtp() returns the data object (SMS record) so you can use resultCode / resultDesc directly. A _wenova field is added with { success, code, message } when the envelope is present.
Use rawResponse: true if you need the full envelope.
Returns: Promise resolving to the SMS data payload (or full JSON when rawResponse is set).
Throws: Error with optional code, path, method, httpStatus when the request fails.
Changelog
1.2.0
- Unwrap success envelope
{ success, code, message, data }—resultCodeis on the returned object again - Attach Wenova
code,path,methodon thrown errors - Optional
rawResponseflag - Document error codes and response shapes
