Passer au contenu
smsbulk

API SMS en masse v1

Une petite API REST pour envoyer des SMS en masse depuis votre logiciel : JSON en entrée et sortie, clés Bearer, les mêmes prix et vérifications que la console, et des webhooks signés pour les rapports de remise. URL de base https://smsbulk.cc/rest/v1

Aperçu

Envoyez jusqu'à 8,000 numéros par requête, chacun avec ses propres valeurs de fusion, et l'API tarifie chaque destinataire avec son propre texte fusionné, exactement comme la console. Demandez d'abord un devis avec le même corps pour connaître le coût ; rien n'est envoyé ou facturé par un devis. Les heures sont au format ISO 8601 en UTC, l'argent est une chaîne en dollars américains avec cinq décimales.

curl https://smsbulk.cc/rest/v1/send \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipients": [
      { "to": "+14155550142", "fields": { "name": "Maria" } },
      { "to": "+447400123456", "fields": { "name": "Tom" } }
    ],
    "text": "Hi {{name}}, your order ships today.",
    "client_ref": "order-batch-17"
  }'

Authentification

Créez une clé dans la console sous API et webhooks ; les clés sont activées après votre premier rechargement crédité. Envoyez-la à chaque requête en tant que token Bearer. Une clé est affichée une seule fois ; vous pouvez conserver jusqu'à 5 clés et en révoquer n'importe laquelle immédiatement.

Authorization: Bearer smsb_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Tarifs

Public, aucune clé nécessaire. Le prix par segment SMS pour chaque destination, ou pour un code ISO.

GEThttps://smsbulk.cc/rest/v1/rates

GEThttps://smsbulk.cc/rest/v1/rates/{ISO}

{
  "country": "US",
  "name": "United States",
  "dial_code": "+1",
  "rate": "0.00485",
  "currency": "USD",
  "per": "message segment"
}

Crédit

GEThttps://smsbulk.cc/rest/v1/credit

{ "credit": "125.40000", "currency": "USD", "account": "A418820037715" }

Devis

Tarifie un envoi sans l'envoyer. Prend le même corps que Envoyer.

POSThttps://smsbulk.cc/rest/v1/quote

ChampSignification
toUn numéro ou une liste. La forme internationale avec + est la plus sûre ; les numéros locaux nécessitent default_country.
recipientsAu lieu de to : une liste de { to, fields } où fields remplit les champs de fusion comme {{name}}.
textLe message, jusqu'à 2,000 caractères et 10 segments après fusion.
default_countryCode ISO utilisé pour les numéros écrits sans +, comme GB. Revient à la valeur par défaut enregistrée dans les paramètres.
opt_outAjoute votre mention de désinscription enregistrée comme dernière ligne (enregistrez-la d'abord dans les paramètres).
{
  "recipients": 2,
  "messages": 2,
  "segments": { "min": 1, "max": 1 },
  "encoding": "GSM-7",
  "total": "0.01240",
  "currency": "USD",
  "credit": "125.40000",
  "credit_after": "125.38760",
  "countries": [
    { "country": "US", "recipients": 1, "rate": "0.00485", "segments": 1, "subtotal": "0.00485" },
    { "country": "GB", "recipients": 1, "rate": "0.00755", "segments": 1, "subtotal": "0.00755" }
  ],
  "left_out": []
}

Envoyer

Crée une campagne, prend son total de votre crédit et met les messages en file d'attente. Répond avec un code 201 et la campagne. Les numéros qui ne peuvent pas être envoyés sont listés dans left_out et ne sont jamais facturés.

POSThttps://smsbulk.cc/rest/v1/send

ChampSignification
to / recipients / text / default_country / opt_outComme dans Quote.
send_atHeure ISO 8601 pour démarrer, 5 minutes à 90 jours à l'avance. Laissez vide pour envoyer maintenant.
nameVotre étiquette pour la campagne, jusqu'à 80 caractères.
client_refVotre propre référence, jusqu'à 64 caractères, renvoyée sur chaque message et webhook.
HTTP/1.1 201 Created
{
  "campaign": {
    "id": "C507318264409",
    "name": null,
    "status": "sending",
    "source": "api",
    "test": false,
    "recipients": 2,
    "cost": "0.01240",
    "refunded": "0.00000",
    "net_cost": "0.01240",
    "currency": "USD",
    "send_at": null,
    "created_at": "2026-11-07T14:02:11.000Z",
    "started_at": "2026-11-07T14:02:11.000Z",
    "finished_at": null,
    "client_ref": "order-batch-17"
  },
  "messages": 2,
  "left_out": []
}

Campagnes

GEThttps://smsbulk.cc/rest/v1/campaigns?limit=25&before={id}

GEThttps://smsbulk.cc/rest/v1/campaigns/{id}

GEThttps://smsbulk.cc/rest/v1/campaigns/{id}/messages?status=failed&limit=100&after={message id}

Une seule campagne inclut des comptes par statut : en file d'attente, envoyé, remis, échoué et annulé. Liste des messages avec after et has_more ; jusqu'à 1 000 par page.

Messages

GEThttps://smsbulk.cc/rest/v1/messages/{id}

GEThttps://smsbulk.cc/rest/v1/messages?to=%2B14155550142&status=delivered&client_ref=order-batch-17&limit=50

{
  "id": "M220947781305",
  "campaign": "C507318264409",
  "to": "+14155550142",
  "country": "US",
  "segments": 1,
  "encoding": "GSM-7",
  "price": "0.00485",
  "status": "delivered",
  "reason": null,
  "reason_text": null,
  "refunded": false,
  "client_ref": "order-batch-17",
  "created_at": "2026-11-07T14:02:11.000Z",
  "sent_at": "2026-11-07T14:02:12.000Z",
  "finished_at": "2026-11-07T14:02:16.000Z"
}

Annuler une campagne planifiée

POSThttps://smsbulk.cc/rest/v1/campaigns/{id}/cancel

Fonctionne jusqu'à l'heure de début. Le coût total est restitué à votre crédit en une ligne de registre et le statut de la campagne devient annulé.

Webhooks

Définissez une URL de point de terminaison dans la console. Nous envoyons un JSON POST pour message.delivered, message.failed et campaign.done, ainsi qu'un test lorsque vous appuyez sur Envoyer un événement de test. Chaque événement contient quatre en-têtes, et toute réponse 2xx dans les 10 secondes est considérée comme reçue.

ChampSignification
Smsbulk-EventNom de l'événement, comme message.delivered.
Smsbulk-DeliveryID de livraison, le même à chaque nouvelle tentative d'un événement.
Smsbulk-TimestampSecondes Unix lorsque cette tentative a été signée.
Smsbulk-Signaturesha256= suivi du HMAC-SHA256 base64 du timestamp, d'un saut de ligne et du corps brut, clé avec votre secret sbw_.

La remise est tentée 8 fois : immédiatement, puis après 1 minute, 5 minutes, 15 minutes, 1 heure, 3 heures, 6 heures et 12 heures. Chaque tentative apparaît dans le journal de remise de la console avec son statut HTTP et le début de votre réponse.

{
  "id": "dlv_3f9a1c07b2e44d58a6c1",
  "event": "message.failed",
  "created": "2026-11-07T14:02:16.000Z",
  "data": {
    "message": "M220947781305",
    "campaign": "C507318264409",
    "to": "+447400123456",
    "country": "GB",
    "status": "failed",
    "reason": "not_in_service",
    "segments": 1,
    "price": "0.00755",
    "client_ref": "order-batch-17"
  }
}

Vérifier la signature

import crypto from "node:crypto";

// raw = the request body exactly as received (string), secret = your sbw_ signing secret
export function verify(raw, headers, secret) {
  const ts = headers["smsbulk-timestamp"];
  const want = "sha256=" + crypto.createHmac("sha256", secret).update(ts + "\n" + raw).digest("base64");
  const got = headers["smsbulk-signature"] || "";
  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
  return fresh && got.length === want.length && crypto.timingSafeEqual(Buffer.from(got), Buffer.from(want));
}

Erreurs et limites

Les erreurs utilisent le statut HTTP et un corps JSON : {"error":{"code":"insufficient_credit","message":"..."}}. Aucun frais n'est facturé en cas d'échec de la demande.

ChampSignification
400 bad_jsonLe corps n'est pas du JSON.
401 unauthorizedClé manquante, malformée ou révoquée.
402 insufficient_creditLe total dépasse votre crédit. Ajoutez des fonds dans la console.
404 not_foundAucun point de terminaison, campagne, message ou code ISO correspondant sur ce compte.
409 not_scheduledUne annulation a été demandée pour une campagne déjà commencée.
422 text_missing, text_too_long, too_many_segmentsMessage vide, dépassant 2,000 caractères, ou plus de 10 segments pour un destinataire.
422 no_recipients, too_many, recipients_missingAucun numéro envoyable, plus de 8,000 numéros, ou ni 'to' ni 'recipients'.
422 schedule_range, bad_send_atsend_at en dehors de 5 minutes à 90 jours, ou heure invalide.
422 opt_out_unsetopt_out est vrai mais aucun texte n'est enregistré dans les Paramètres.
429 rate_limitedPlus de 300 requêtes par minute pour cette clé.

Chaque réponse contient X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Reset.

Codes exclus

Les numéros supprimés avant le calcul du prix reviennent dans left_out avec leur position dans votre liste, la valeur envoyée, un code et la raison explicite.

ChampSignification
no_country_codePas de + et pas de pays par défaut.
too_short / too_longMoins de 8 ou plus de 15 chiffres.
not_a_numberLettres ou symboles qui ne font pas partie d'un numéro.
nanp_lengthUn numéro +1 sans onze chiffres.
not_coveredUne destination en dehors de notre liste.
duplicateLe même numéro est apparu plus tôt dans la requête.
suppressedLe numéro est sur votre liste de non-envoi.

Statuts et raisons

ChampSignification
queuedEn attente de sortie de notre file.
sentTransmis au réseau, en attente du rapport de remise. La plupart des rapports arrivent en quelques minutes ; certains réseaux prennent jusqu'à 24 heures.
deliveredLe réseau a confirmé que le téléphone l'a reçu.
failedNon remis. Le prix a été remboursé sur votre crédit.
canceledNon envoyé car vous avez annulé. Remboursé.
ChampSignification
network_errorErreur réseau
switched_offTéléphone éteint ou hors couverture
not_in_serviceNuméro hors service
blockedBloqué par le réseau ou le destinataire
landlineLigne fixe ou numéro ne pouvant pas recevoir de SMS
content_filterRejeté par le filtre de contenu du réseau
expiredExpiré : aucun rapport avant la limite de temps du réseau
unknownRéponse réseau inconnue
canceledAnnulé avant l'envoi

Des questions sur l'API ? Ouvrez un ticket dans la console ou consultez la FAQ.

Documentation de l'API SMS en masse v1 : Envoi, Devis, Webhooks | SMSBulk