Intégrer le premier SMS en JavaScript
Ce guide montre comment utiliser le SDK JavaScript officiel pour envoyer un SMS, lire la vraie réponse de l'API et préparer la validation des webhooks.
Pré-requis d'exécution
Le serveur qui appelle l'API doit conserver la clé API côté backend. Ne l'exposez jamais dans un bundle navigateur.
- →Téléchargez le SDK officiel
cutuma-client.mjsdans votre backend Node.js. - →Créez un compte et récupérez une clé API depuis le dashboard.
- →Conservez la clé API côté serveur uniquement.
- →Ajoutez
Idempotency-Keysur chaque mutation critique. - →Corrélez les erreurs via
X-Request-Idet les headersX-RateLimit-*.
Comprendre la réponse 202
Contrat d'envoi
L'API privilégie la durabilité de la file avant la soumission opérateur. Le code client doit traiter l'acceptation plateforme et le statut de livraison comme deux étapes séparées.
client.sendSms(...)reçoit une acceptation202 Accepted, pas une preuve de livraison.queued: trueetstatus: acceptedconfirment la persistance avant dispatch.provider.messageIdpeut êtrenullinitialement — utilisez vos références,X-Request-Idet webhooks.- Ne testez pas
statusCode === 200strictement : acceptez les réponses2xxconformes.
Exemple SDK Node.js
client.sendSms(...)
# Copier le SDK dans votre projet
curl -O https://cutuma.com/sdk/cutuma-client.mjs
# ou placez cutuma-client.mjs dans votre dossier lib/
import crypto from 'node:crypto';
import { CutumaClient } from './cutuma-client.mjs';
const baseUrl = process.env.CUTUMA_BASE_URL ?? 'https://cutuma.com/api/v1';
const apiKey = process.env.CUTUMA_API_KEY;
if (!apiKey) {
throw new Error('CUTUMA_API_KEY is required.');
}
const client = new CutumaClient({ baseUrl, apiKey });
const response = await client.sendSms(
{
to: '+243810000000',
message: 'Votre code de vérification est 482019.',
senderName: 'CUTUMA',
},
{
idempotencyKey: crypto.randomUUID(),
requestId: 'quickstart-send-001',
}
);
console.log({
statusCode: response.statusCode,
requestId: response.requestId,
remainingQuota: response.data.remainingQuota,
queued: response.data.queued,
status: response.data.status,
});
Variables d'environnement
CUTUMA_API_KEY
Clé API générée depuis le dashboard.
at_live_xxx
CUTUMA_BASE_URL
Hôte API. Le SDK utilise /v1 directement.
https://cutuma.com/api/v1
CUTUMA_WEBHOOK_SECRET
Secret partagé pour vérifier les callbacks webhook (bientôt).
at_whsec_...
Préparer les webhooks
Quand l'envoi est critique, créez un endpoint webhook et vérifiez les callbacks signés.
POST https://cutuma.com/api/v1/webhooks
Authorization: Bearer at_live_xxx
Content-Type: application/json
{
"url": "https://cutuma.com/webhooks/cutuma",
"subscribed_events": ["message.delivered", "message.failed"]
}
202 Accepted
{
"success": true,
"webhookEndpoint": {
"id": "7d5f1e88-6fd8-4ca7-a1a5-3b338f5f0f50",
"url": "https://cutuma.com/webhooks/cutuma",
"subscribed_events": ["message.delivered", "message.failed"],
"status": "active"
},
"signingSecret": "at_whsec_..."
}
import crypto from 'node:crypto';
function assertWebhookSignature({ signingSecret, timestamp, signature, payload }) {
const expected = crypto
.createHmac('sha256', signingSecret)
.update(`${timestamp}.${payload}`)
.digest('hex');
if (signature !== expected) {
throw new Error('Invalid webhook signature.');
}
}
function handleWebhook(rawBody, headers) {
assertWebhookSignature({
signingSecret: process.env.CUTUMA_WEBHOOK_SECRET,
timestamp: headers['x-cutuma-timestamp'],
signature: headers['x-cutuma-signature'],
payload: rawBody,
});
return JSON.parse(rawBody);
}
Webhooks sortants — disponibles prochainement. Structure documentée à l'avance pour faciliter l'intégration.
Alternative sans SDK (fetch natif)
const res = await fetch('https://cutuma.com/api/v1/sms/send', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.CUTUMA_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
to: '+243810000000',
message: 'Votre code est 482019',
senderName: 'CUTUMA',
}),
});
if (res.status >= 200 && res.status < 300) {
const data = await res.json();
console.log('Accepted:', data.remainingQuota, 'SMS restants');
}