@promodev/smspro-sdk
v1.0.0
Published
SDK client TypeScript pour l'API smspro-promodev (envoi SMS/RCS, sous-clients, usage & facturation).
Readme
@promodev/smspro-sdk
SDK client TypeScript pour l'API smspro-promodev : envoi de SMS/RCS, gestion
des sous-clients et consultation de l'usage/facturation. Aucune dépendance
runtime (utilise le fetch natif de Node ≥ 18).
Installation
npm install @promodev/smspro-sdkDémarrage
import { SmsproClient, SmsproError, isSkipped } from '@promodev/smspro-sdk';
const sms = new SmsproClient({
apiKey: 'sk_…', // clé d'API du compte (client ou sous-client)
baseUrl: 'https://api.example.com', // défaut http://localhost:3000
});
const res = await sms.send({
to: '+33612345678',
message: 'Bonjour 👋',
channel: 'AUTO', // tente RCS puis SMS (fallback)
tag: 'flight-notif', // métadonnée libre pour vos filtres/stats
ref: 'mon-id-externe-42', // référence de corrélation (optionnelle)
});
if (isSkipped(res)) {
console.log('ignoré :', res.reason);
} else {
console.log(res.status, res.cost, res.currency);
}Suivi des statuts (polling)
await sms.messages.get('mon-id-externe-42'); // un message par sa ref
await sms.messages.list({ status: 'DELIVERED' }); // filtres: status / tag / ref / limitCallback de livraison (push)
Configurez une URL : à chaque évolution de statut, smspro y envoie un POST JSON
(DeliveryEvent). La vérification de signature est optionnelle.
const me = await sms.me.setCallbackUrl('https://mon-app.example.com/sms-callback');
const secret = me.callbackSecret; // à conserver pour vérifier les signatures
// Réception (Express) — version minimale :
app.post('/sms-callback', express.json(), (req, res) => {
const { ref, status } = req.body; // ex. status: 'DELIVERED'
res.sendStatus(200);
});
// …ou avec vérification de signature (1 ligne) :
import { verifyDeliverySignature } from '@promodev/smspro-sdk';
app.post('/sms-callback', express.raw({ type: '*/*' }), (req, res) => {
const raw = req.body.toString('utf8');
if (!verifyDeliverySignature(secret, raw, req.header('x-smspro-signature') ?? '')) {
return res.sendStatus(401);
}
const event = JSON.parse(raw);
res.sendStatus(200);
});Gestion des erreurs
Toute réponse HTTP ≥ 400 lève une SmsproError :
try {
await sms.send({ to: '+33123456789', message: 'test' });
} catch (err) {
if (err instanceof SmsproError) {
if (err.isInvalidNumber) { /* 422 : numéro fixe/invalide, err.code === 'LANDLINE'… */ }
if (err.isInsufficientBalance) { /* 402 : solde prépayé insuffisant */ }
console.error(err.status, err.code, err.message);
}
}Sous-clients (comptes de 1er niveau)
const sub = await sms.subClients.create({
name: 'Filiale Sud',
unitPrice: 0.07, // tarif revendeur
prepaid: true,
balance: 50,
});
await sms.subClients.list();
await sms.subClients.update(sub._id, { balance: 100 }); // recharge
await sms.subClients.regenerateKey(sub._id);
await sms.subClients.usage(sub._id, { from: new Date('2026-01-01') });
await sms.subClients.messages(sub._id, { limit: 100 });Un sous-client peut envoyer des messages mais ne peut pas gérer de sous-clients (
subClients.*renvoie alors HTTP 403).
API
| Méthode | Endpoint | Retour |
|---|---|---|
| client.health() | GET /health | Health |
| client.send(input) | POST /sms | SentMessage \| SkippedResult |
| client.messages.list(opts) | GET /messages | Message[] |
| client.messages.get(ref) | GET /messages/:ref | Message |
| client.me.get() | GET /me | Account |
| client.me.setCallbackUrl(url) | PATCH /me | Account |
| client.me.regenerateCallbackSecret() | POST /me/callback-secret/regenerate | { callbackSecret } |
| client.subClients.create(input) | POST /sub-clients | SubClient |
| client.subClients.list() | GET /sub-clients | SubClient[] |
| client.subClients.get(id) | GET /sub-clients/:id | SubClient |
| client.subClients.update(id, data) | PATCH /sub-clients/:id | SubClient |
| client.subClients.regenerateKey(id) | POST /sub-clients/:id/regenerate-key | SubClient |
| client.subClients.usage(id, range?) | GET /sub-clients/:id/usage | Usage |
| client.subClients.messages(id, opts?) | GET /sub-clients/:id/messages | Message[] |
Options du constructeur : apiKey (requis), baseUrl, fetch (injection pour
Node < 18 ou tests), timeoutMs (défaut 30 000).
Un exemple exécutable est fourni dans examples/quickstart.mjs.
