Blog Tutoriel

Tutoriel

API SMS OTP : envoyer un code de vérification et des alertes par SMS

Générer un code OTP, l’envoyer par SMS en une requête, suivre sa livraison par webhook et automatiser vos alertes de paiement, de livraison et de sécurité.

SOMMAIRE
  1. Qu’est-ce qu’un code OTP et un SMS transactionnel ?
  2. Que faut-il pour intégrer une API SMS ?
  3. Comment envoyer un code OTP par SMS avec l’API ?
  4. Que signifie la réponse 202 Accepted ?
  5. Quand peut-on renvoyer une requête ? Le rôle de l’Idempotency-Key
  6. Comment savoir si le SMS est arrivé ? Webhooks et Rapport SMS
  7. Quelles erreurs l’API SMS peut-elle renvoyer ?
  8. Comment automatiser vos alertes SMS ?
  9. Comment sécuriser vos codes OTP ?
  10. Quels modèles de SMS utiliser pour vos codes et alertes ?
  11. Combien coûte l’envoi d’OTP par SMS en RDC ?
  12. Questions fréquentes

Envoyer un code OTP par SMS reste le moyen le plus simple de vérifier un numéro ou de confirmer une opération : le SMS fonctionne sur tous les téléphones mobiles, même sans Internet. Avec une API SMS OTP, votre serveur génère le code, l’envoie en une requête HTTP et suit sa livraison. Ce tutoriel utilise l’API REST de Coussema, en curl, Node.js, Python et PHP, puis l’étend aux alertes automatiques.

L’ESSENTIEL

  • Un code OTP (One-Time Password) est un code à usage unique, souvent de 6 chiffres, qui prouve qu’un utilisateur contrôle son numéro de téléphone.
  • Chez Coussema, un SMS part par POST https://api.coussema.com/v1/sms/send, avec une clé API côté serveur et un en-tête Idempotency-Key obligatoire.
  • 202 Accepted signifie « accepté dans la file d’envoi », pas « livré » : la livraison se suit par webhook et dans le Rapport SMS.
  • Pendant 24 heures, la même Idempotency-Key avec le même contenu signale une reprise, pas un nouvel envoi.
  • Un code sûr expire en 10 minutes au plus, sert une fois et n’est stocké que sous forme d’empreinte.
  • Chez Coussema, un SMS de 160 caractères en GSM-7 coûte 0,03 $ avec l’offre Croissance ; un seul « ç » ou une apostrophe typographique ’ le fait passer en Unicode, limité à 70 caractères.

Qu’est-ce qu’un code OTP et un SMS transactionnel ?

Un code OTP (One-Time Password, mot de passe à usage unique) est un code temporaire qui confirme qu’une personne contrôle un numéro de téléphone ou autorise une opération. Un SMS transactionnel est un message attendu par un seul destinataire, déclenché par une action : un code, une confirmation de paiement, un avis d’expédition. Le SMS marketing, soumis au consentement, a son propre guide de l’envoi de SMS en masse en RDC.

En RDC, selon le rapport de l’ARPTC sur le premier trimestre 2026, publié en juin 2026, le SMS se recentre sur trois usages : les codes OTP, les alertes techniques et les messages d’urgence. Fin mars 2026, le pays comptait 74,9 millions d’abonnements mobiles, mais l’Internet mobile n’y atteignait que 34,1 % de pénétration : le SMS joint aussi les abonnés hors ligne.

Que faut-il pour intégrer une API SMS ?

Il vous faut un compte, une clé API, un Sender ID approuvé et du crédit.

  1. Un compte. L’inscription offre 10 SMS pour vos tests.
  2. Une clé API au profil « Envoi SMS uniquement » (droit sms:send), créée dans le tableau de bord.
  3. Un Sender ID. Un Sender ID est le nom qui s’affiche comme expéditeur à la place d’un numéro, par exemple « MonAppli ». Gratuit, il se demande dans le tableau de bord et s’utilise après approbation, avec l’offre Croissance.
  4. Du crédit, rechargé par Mobile Money ; la réponse d’acceptation indique le solde à cet instant (remainingQuota).

Cette clé envoie des SMS sur votre solde : gardez-la sur le serveur, dans une variable d’environnement (COUSSEMA_API_KEY), jamais dans une application mobile, une page web, un dépôt Git ou un journal. GET https://api.coussema.com/v1/health vérifie que l’API répond ; le démarrage rapide reprend ces étapes.

Comment envoyer un code OTP par SMS avec l’API ?

Une seule requête suffit : POST https://api.coussema.com/v1/sms/send avec l’en-tête Authorization: Bearer <clé API>, une Idempotency-Key unique et un corps JSON qui contient le numéro, le texte et votre Sender ID.

ÉlémentExempleÀ savoir
AuthorizationBearer csm_live_…Ou l’en-tête x-api-key
Idempotency-Keyun UUID (identifiant unique)Obligatoire, une valeur par envoi
to243810000000Numéro congolais au format international, sans le 0 initial ; un par requête
messagele texte du SMS1 à 1 530 caractères, facturé par segment
senderNameMonAppliSender ID approuvé, ou senderId (son UUID)
clientReferenceotp-signup-001Facultatif : votre référence, 128 caractères au plus

L’en-tête facultatif X-Request-Id et les autres règles figurent dans la référence de l’API. Côté serveur, tirez le code avec un générateur cryptographique, jamais Math.random(), puis enregistrez son empreinte, son expiration et un compteur d’essais avant l’envoi.

Avec curl

curl -X POST https://api.coussema.com/v1/sms/send \
  -H 'Authorization: Bearer csm_live_xxxxxxxxxxxx_xxx' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 7228b5c7-cb1d-43c0-8d68-2e9f68a5fba5' \
  -H 'X-Request-Id: otp-signup-001' \
  -d '{
    "to": "243810000000",
    "message": "482019 est votre code MonAppli. Il expire dans 10 minutes. Ne le partagez avec personne.",
    "senderName": "MonAppli",
    "clientReference": "otp-signup-001"
  }'

Avec Node.js : envoyer et vérifier le code

Pas de bibliothèque Coussema à installer : fetch suffit.

import crypto from 'node:crypto';

const baseUrl = process.env.COUSSEMA_BASE_URL ?? 'https://api.coussema.com';
const apiKey = process.env.COUSSEMA_API_KEY;
const otpSecret = process.env.OTP_HMAC_SECRET; // votre secret, distinct de la clé API

if (!apiKey || !otpSecret) {
  throw new Error('COUSSEMA_API_KEY and OTP_HMAC_SECRET are required.');
}

// Exemple en mémoire : en production, utilisez votre base (PostgreSQL, Redis...).
const otps = new Map();

const hashCode = (phone, code) =>
  crypto.createHmac('sha256', otpSecret).update(`${phone}:${code}`).digest();

// Une tentative : un code et une clé, préparés une seule fois.
export function prepareOtp(phone) {
  const code = crypto.randomInt(0, 1_000_000).toString().padStart(6, '0');
  const idempotencyKey = crypto.randomUUID();

  // Un seul code actif par numéro : le nouveau remplace l'ancien.
  otps.set(phone, {
    hash: hashCode(phone, code),
    expiresAt: Date.now() + 10 * 60 * 1000,
    attempts: 0,
  });

  return { phone, code, idempotencyKey };
}

// Après une erreur réseau, rappelez sendOtp(attempt) avec la même tentative.
export async function sendOtp({ phone, code, idempotencyKey }) {
  const response = await fetch(`${baseUrl}/v1/sms/send`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${apiKey}`,
      'Content-Type': 'application/json',
      'Idempotency-Key': idempotencyKey,
      'X-Request-Id': crypto.randomUUID(),
    },
    body: JSON.stringify({
      to: phone,
      message: `${code} est votre code MonAppli. Il expire dans 10 minutes. Ne le partagez avec personne.`,
      senderName: 'MonAppli',
      clientReference: `otp-${idempotencyKey}`,
    }),
    signal: AbortSignal.timeout(15_000),
  });

  if (!response.ok) {
    // Ne journalisez ni le code, ni la clé API.
    throw new Error(`Coussema API returned ${response.status} (x-request-id ${response.headers.get('x-request-id')}).`);
  }

  // 202 : accepté dans la file d'envoi, pas encore livré.
  const payload = await response.json();
  return { messageId: payload.message.id, remainingQuota: payload.remainingQuota };
}

export function verifyOtp(phone, submittedCode) {
  const entry = otps.get(phone);
  if (!entry || Date.now() > entry.expiresAt || entry.attempts >= 5) {
    otps.delete(phone);
    return false;
  }
  entry.attempts += 1;
  const valid = crypto.timingSafeEqual(entry.hash, hashCode(phone, String(submittedCode)));
  if (valid) otps.delete(phone); // usage unique
  return valid;
}

Préparez la tentative une seule fois avec const attempt = prepareOtp(phone), puis envoyez-la avec sendOtp(attempt) ; après une erreur réseau, rappelez sendOtp(attempt) sans rappeler prepareOtp. L’empreinte HMAC-SHA256, un calcul à sens unique fondé sur un secret à vous, protège les codes si votre base fuit.

Avec Python

import os
import secrets
import uuid

import requests


def send_otp(phone, code, idempotency_key):
    api_key = os.environ['COUSSEMA_API_KEY'].strip()
    payload = {
        'to': phone,
        'message': f'{code} est votre code MonAppli. Il expire dans 10 minutes. '
                   'Ne le partagez avec personne.',
        'senderName': 'MonAppli',
        'clientReference': f'otp-{idempotency_key}',
    }
    try:
        response = requests.post(
            'https://api.coussema.com/v1/sms/send',
            headers={
                'Authorization': f'Bearer {api_key}',
                'Idempotency-Key': idempotency_key,
                'X-Request-Id': str(uuid.uuid4()),
            },
            json=payload,
            timeout=(5, 30),
            allow_redirects=False,
        )
    except requests.exceptions.InvalidHeader:
        # Le message de cette erreur peut contenir la clé : on ne le garde pas.
        raise RuntimeError('Configuration de l’en-tête API invalide.') from None
    except requests.exceptions.RequestException:
        # Issue incertaine : reprise possible avec la même clé et le même contenu.
        raise RuntimeError('Résultat réseau incertain.') from None

    request_id = response.headers.get('x-request-id', '')
    if not 200 <= response.status_code < 300:
        # Ne journalisez ni la clé API, ni le contenu du SMS.
        raise RuntimeError(f'HTTP {response.status_code}; request_id={request_id}')
    result = response.json()
    if result.get('queued') is not True or result.get('status') != 'accepted':
        raise RuntimeError(f'Réponse inattendue; request_id={request_id}')
    return result['message']['id']


code = f'{secrets.randbelow(1_000_000):06d}'  # 6 chiffres, générateur sûr
idempotency_key = str(uuid.uuid4())  # gardez-la, avec le code, pour une reprise
message_id = send_otp('243810000000', code, idempotency_key)

Avec PHP

<?php

$code = str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT);
$idempotencyKey = bin2hex(random_bytes(16)); // gardez-la, avec le code, pour une reprise

$payload = [
    'to' => '243810000000',
    'message' => $code . ' est votre code MonAppli. Il expire dans 10 minutes.',
    'senderName' => 'MonAppli',
    'clientReference' => 'otp-login-001',
];

$ch = curl_init('https://api.coussema.com/v1/sms/send');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 15,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('COUSSEMA_API_KEY'),
        'Content-Type: application/json',
        'Idempotency-Key: ' . $idempotencyKey,
    ],
    CURLOPT_POSTFIELDS => json_encode($payload, JSON_THROW_ON_ERROR),
]);

$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if ($body === false) {
    throw new RuntimeException('Erreur réseau : ' . curl_error($ch));
}
if ($status < 200 || $status >= 300) {
    throw new RuntimeException('Erreur API Coussema HTTP ' . $status);
}

$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
$messageId = $result['message']['id']; // 202 : accepté dans la file d'envoi

Que signifie la réponse 202 Accepted ?

202 Accepted signifie que Coussema a validé la requête, enregistré le message et l’a placé dans la file d’envoi. Ce n’est pas une preuve de livraison : les mises à jour de statut arrivent ensuite par webhook et dans le Rapport SMS.

HTTP/1.1 202 Accepted
Content-Type: application/json

{
  "success": true,
  "queued": true,
  "status": "accepted",
  "count": 1,
  "remainingQuota": 999,
  "message": {
    "id": "11111111-1111-4111-8111-111111111111",
    "clientReference": "otp-signup-001"
  },
  "provider": {
    "code": "coussema",
    "messageId": null,
    "httpStatus": 202
  }
}

Conservez message.id (provider.messageId vaut toujours null), acceptez tout succès 2xx et surveillez remainingQuota. Côté interface, affichez « Envoi du code en cours » après le 202, puis proposez « Renvoyer le code » après 30 à 60 secondes.

Quand peut-on renvoyer une requête ? Le rôle de l’Idempotency-Key

L’Idempotency-Key identifie un envoi : on ne renvoie une requête que pour reprendre ce même envoi, avec la même clé et le même contenu. Pendant 24 heures, l’API reconnaît alors la reprise et renvoie la réponse enregistrée la première fois, succès ou erreur, au lieu de traiter un nouvel envoi.

Après un délai dépassé ou une erreur réseau, l’issue est incertaine : rejouez la requête à l’identique. Vous recevez la réponse enregistrée si l’envoi a abouti, ou une erreur 409 si son issue reste indéterminée. Une erreur survenue pendant le traitement est en général enregistrée et rejouée telle quelle ; dans tous les cas, vérifiez l’état du message dans le Rapport SMS avant tout nouvel envoi, et gardez le x-request-id. La même clé avec un autre contenu renvoie aussi une erreur 409 ; la clientReference ne déduplique rien.

Comment savoir si le SMS est arrivé ? Webhooks et Rapport SMS

Les mises à jour de statut arrivent par webhook, un appel HTTP que Coussema envoie à votre serveur à chaque événement, et s’affichent dans le Rapport SMS. La mise en file vient de Coussema ; la remise est ensuite renseignée par le DLR (Delivery Report, ou accusé de réception) de l’opérateur.

Déclarez votre adresse HTTPS avec une clé qui a le droit webhooks:write, puis rangez le signingSecret de la réponse, donné une seule fois, dans COUSSEMA_WEBHOOK_SECRET.

curl -X POST https://api.coussema.com/v1/webhooks \
  -H 'Authorization: Bearer csm_live_xxxxxxxxxxxx_xxx' \
  -H 'Content-Type: application/json' \
  -d '{
    "url": "https://example.com/webhooks/coussema",
    "subscribed_events": ["message.delivered", "message.failed"]
  }'

Les événements SMS sont message.queued, message.sent (transmis au réseau), message.delivered (remis), message.failed (non remis : vérifiez le numéro, proposez un nouveau code) et message.delivery_unconfirmed (aucun accusé définitif). Vous recevez ceux auxquels votre adresse est abonnée. Chaque webhook SMS est signé : l’en-tête x-coussema-signature contient v1= suivi d’un HMAC-SHA256, calculé avec votre secret sur la valeur de x-coussema-timestamp, un point, puis le corps brut. Vérifiez-le avant tout JSON.parse :

import { createHmac, timingSafeEqual } from 'node:crypto';

function handleWebhook(rawBody, headers) {
  const timestamp = headers.get('x-coussema-timestamp');
  const signature = headers.get('x-coussema-signature');
  const secret = process.env.COUSSEMA_WEBHOOK_SECRET ?? '';
  if (!timestamp || !signature || !secret) throw new Error('Missing signature data.');

  const match = /^v1=([0-9a-f]{64})$/.exec(signature);
  if (!match) throw new Error('Invalid Coussema webhook signature.');

  const timestampMs = Date.parse(timestamp);
  const timestampIsFresh = Number.isFinite(timestampMs)
    && Math.abs(Date.now() - timestampMs) <= 5 * 60 * 1000;
  const expectedDigest = createHmac('sha256', secret)
    .update(`${timestamp}.${rawBody}`, 'utf8')
    .digest();
  const valid = timestampIsFresh && timingSafeEqual(Buffer.from(match[1], 'hex'), expectedDigest);

  if (!valid) throw new Error('Invalid Coussema webhook signature.');
  return JSON.parse(rawBody);
}

Répondez vite par un 2xx, dédupliquez sur x-coussema-delivery-id (un événement peut arriver deux fois) et retrouvez l’opération par message.id ou message.client_reference. Dans le Rapport SMS, un message peut être En attente, Envoyé, Reçu, Échec ou Non confirmé ; seul « Reçu » prouve la remise ; le guide des webhooks détaille le reste.

Quelles erreurs l’API SMS peut-elle renvoyer ?

L’API répond par un code HTTP : 4xx pour une requête à corriger, 429 pour un débit dépassé, 5xx pour un incident côté serveur. Traitez d’abord ce code HTTP : le champ code n’est pas présent dans toutes les réponses d’erreur. Gardez le x-request-id de chaque réponse pour le support.

HTTPCodeSignificationQue faire
400—Requête hors contrat : numéro, texte, expéditeurCorriger avant de renvoyer
401—Clé absente, révoquée ou invalideUtiliser une clé valide
403api_key_scope_requiredDroit manquant sur la cléChanger de profil de clé
409—Même clé avec un autre contenu, ou envoi précédent encore indéterminéVérifier le contenu et l’état de l’envoi
429—Débit dépasséAttendre Retry-After, garder la clé
500—Erreur imprévueVérifier l’état du message avant un nouvel envoi

L’envoi accepte par défaut jusqu’à 10 000 requêtes par fenêtre de limitation ; l’en-tête X-RateLimit-Remaining indique les requêtes encore autorisées. Ne bouclez jamais sur une erreur.

Comment automatiser vos alertes SMS ?

Les alertes SMS automatiques sont des messages déclenchés par un événement de votre système : paiement confirmé, commande expédiée, nouvelle connexion. L’appel est celui de l’OTP, avec trois précautions.

  1. Une clé tirée de l’événement, comme payment-58231-sms : une tâche rejouée dans les 24 heures reprend le même envoi, si le texte est identique.
  2. Une tâche de fond, pour qu’un appel lent ne bloque pas le paiement.
  3. Le bon moment : la sécurité tout de suite, les rappels aux heures de bureau, sur les deux fuseaux de la RDC (UTC+1 à Kinshasa, UTC+2 à Lubumbashi).
// Mêmes baseUrl et apiKey que dans l'exemple précédent.
// Espaces ordinaires : toLocaleString('fr-FR') insère une espace fine insécable, hors GSM-7.
const formatAmount = (n) => String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ' ');

export async function sendPaymentAlert(payment) {
  const response = await fetch(`${baseUrl}/v1/sms/send`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${apiKey}`,
      'Content-Type': 'application/json',
      // Une clé tirée de l'événement : une tâche rejouée reprend le même envoi.
      'Idempotency-Key': `payment-${payment.id}-sms`,
    },
    body: JSON.stringify({
      to: payment.phone,
      // Texte construit à partir de l'événement seul : identique à chaque reprise.
      message: `Paiement de ${formatAmount(payment.amount)} FC confirmé pour la commande ${payment.orderId}. Merci de votre confiance.`,
      senderName: 'MaBoutique',
      clientReference: `payment-${payment.id}`,
    }),
  });

  if (!response.ok) throw new Error(`Coussema API returned ${response.status}.`);
  return (await response.json()).message.id;
}

Restez informatif : une promotion en ferait un message marketing.

Comment sécuriser vos codes OTP ?

Une vérification par SMS sûre repose sur un code aléatoire, court, à usage unique, limité en essais et en envois, et jamais écrit en clair dans votre base ni vos journaux.

RègleValeur conseilléePourquoi
Longueur6 chiffresUn million de combinaisons
Validité5 à 10 minutesPlafond du NIST et de l’OWASP
Essais3 à 5 par code5 essais : 5 chances sur un million
EnvoisRenvoi après 30 à 60 secondes, plafond horaire par numéroContre les abus et la facture
Code actifUn seul, supprimé après usageLe nouveau code annule l’ancien
StockageEmpreinte HMAC-SHA256La base ne livre pas les codes
JournauxNi le code, ni la clé APIIls circulent plus que la base

Le guide SP 800-63B-4 du NIST, l’institut américain des normes (version finale de juillet 2025), impose au moins six chiffres, une validité de 10 minutes au plus et un usage unique, et classe le SMS parmi les authentificateurs « restreints », à cause de l’échange de carte SIM et de la portabilité du numéro. La norme ASVS 5.0 de l’OWASP (mai 2025) exige une limitation du débit et exclut le SMS des applications les plus sensibles.

Plafonnez aussi les demandes par numéro, par adresse IP et par compte : le « SMS pumping », des vagues de demandes vers des numéros de fraudeurs, vide votre crédit. Si le SMS échoue, proposez un nouveau code ou un autre canal : un modèle d’authentification WhatsApp, avec l’accord du client (API WhatsApp), ou un appel vocal.

Quels modèles de SMS utiliser pour vos codes et alertes ?

Utilisez des messages courts, qui tiennent en un seul segment. Un segment est l’unité facturée d’un SMS : 160 caractères en GSM-7, l’alphabet standard des SMS, ou 70 dès qu’un caractère en sort ; au-delà, chaque segment compte 153 caractères, ou 67 en Unicode. Quelques symboles comme € et la plupart des emojis comptent double.

UsageModèleCaractèresSMS facturés
Code de vérification482019 est votre code MonAppli. Il expire dans 10 minutes. Ne le partagez avec personne.881
Mot de passe oublié739204 est votre code pour changer de mot de passe. Valable 10 minutes. Si la demande ne vient pas de vous, ignorez ce SMS.1231
Paiement reçuPaiement de 25 000 FC confirmé pour la commande 1042. Merci de votre confiance.791
Commande expédiéeVotre commande 1042 est expédiée. Livraison prévue demain entre 10 h et 12 h. Le livreur vous appellera.1041
Alerte de sécuritéNouvelle connexion à votre compte le 24/10 à 14 h 05. En cas de doute, appelez le 0810000000 et changez votre mot de passe.1231

Le code vient en tête, lisible dans la notification. Les lettres é, è, à et ù restent en GSM-7, mais un seul ê, ç, °, guillemet « », emoji ou apostrophe ’ fait passer le message en Unicode : « Paiement de 25 000 FC bien reçu… », 80 caractères, coûte 2 SMS. Même piège avec l’espace fine insécable de toLocaleString('fr-FR').

482019 est votre code MonAppli. Il expire dans 10 minutes.

@example.com #482019

Combien coûte l’envoi d’OTP par SMS en RDC ?

Chez Coussema, l’accès à l’API SMS est gratuit et chaque SMS d’un segment vers la RDC coûte 0,03 $ avec l’offre Croissance, sans abonnement ; 10 SMS sont offerts à l’inscription.

Envoi mensuelSMS facturésCoût à 0,03 $
Codes de vérification, renvois compris4 000120 $
Confirmations de paiement10 000300 $
Alertes de sécurité1 00030 $
Total15 000450 $

Avec « bien reçu » au lieu de « confirmé », les confirmations passent à 2 segments : 25 000 SMS facturés, soit 750 $. Les SMS achetés n’expirent pas et se paient par Mobile Money ; les gros volumes relèvent de l’offre Entreprise, sur devis (tarifs, contact). Le SMS couvre pour l’instant la RDC (+243) ; d’autres destinations sont en cours d’ouverture. Le reste de l’offre est présenté sur la page SMS professionnel.

Questions fréquentes

Qu’est-ce qu’une API SMS OTP ?

C’est une interface qui permet à votre application d’envoyer des codes à usage unique par SMS en une requête HTTP, puis d’en suivre la livraison. Votre serveur génère et vérifie le code ; l’API l’achemine.

Combien de chiffres doit compter un code OTP envoyé par SMS ?

Six chiffres, soit un million de combinaisons : c’est le minimum fixé par le NIST. Ajoutez une validité de 5 à 10 minutes et des essais limités.

Peut-on appeler l’API SMS depuis une application mobile ou un navigateur ?

Non. La clé API envoie des SMS sur votre solde et doit rester sur votre serveur. L’application ou la page web appelle votre serveur, qui appelle l’API.

Combien coûte un SMS OTP en RDC ?

Chez Coussema, 0,03 $ par SMS d’un segment avec l’offre Croissance, sans abonnement ; l’accès à l’API est gratuit. Mille codes d’un segment coûtent donc 30 $.

Le SMS est-il assez sûr pour la double authentification ?

Il ajoute un second facteur au mot de passe, mais le NIST le classe parmi les authentificateurs « restreints » (échange de carte SIM, portabilité des numéros). Pour les opérations à fort enjeu, proposez aussi une application d’authentification ou une clé d’accès (passkey).

Peut-on envoyer des OTP par SMS hors de la RDC ?

Pas encore avec Coussema : le SMS couvre pour l’instant les numéros congolais (+243), d’autres destinations étant en cours d’ouverture. WhatsApp permet d’écrire à l’international, avec des modèles d’authentification validés par Meta.