Référence de l'API SMS en masse

L'API REST BulkSMSOnline envoie des messages texte vers 227 pays depuis votre propre logiciel, avec les mêmes prix, règles de segments, planification et remboursements que la console. Les requêtes et réponses sont en JSON sur HTTPS, et chaque statut de livraison final peut être poussé vers votre serveur via un webhook signé.

URL de basehttps://bulksmsonline.cc/api/v1

Aperçu

Utilisez l'API lorsque les messages sont déclenchés par vos propres systèmes : mises à jour de commande d'une boutique, codes d'un formulaire de connexion, rappels d'un outil de réservation. Une requête POST /v1/messages avec jusqu'à 10,000 numéros crée une campagne, débite le solde et met chaque message en file d'attente. Les campagnes créées par l'API apparaissent aussi dans la console avec leurs rapports de remise.

  • Tous les montants sont en dollars US sous forme de chaînes avec cinq décimales, par exemple "0.00534".
  • Les numéros de téléphone sont internationaux, avec ou sans le + initial ; les espaces et les tirets sont supprimés.
  • Les heures sont au format ISO 8601 en UTC, par exemple 2026-12-01T09:00:00Z.
  • Les identifiants de message et de campagne ressemblent à MSG-XXXX-XXXX-XXXX et CMP-XXXX-XXXX-XXXX.

Authentification

Créez une clé API sous API dans la console (les clés sont accessibles après votre premier rechargement). Envoyez-la dans l'en-tête Authorization de chaque requête. Une clé ressemble à bso_api_ suivi de 36 caractères ; elle n'est affichée qu'une fois, alors stockez-la comme secret sur votre serveur. Créer une nouvelle clé remplace immédiatement la précédente.

Authorization: Bearer bso_api_0123456789abcdef0123456789abcdef0123
Content-Type: application/json

Limites

Requêtes300 par minute par clé ; au-delà, réponse 429 rate_limited
Numéros par requête10,000
Texte du message2,000 caractères tels qu'écrits, jusqu'à 10 segments
Planificationsend_at de 5 minutes à 60 jours à l'avance
Cadence d'envoi400 messages par minute par file
Nouvelles tentatives de webhook9 tentatives sur environ 22 heures

Envoyer des messages

POST/v1/messages

Envoie un texte à un ou plusieurs numéros. Le coût total est prélevé du solde lorsque la demande est acceptée ; chaque message qui ne peut être livré est remboursé ultérieurement. La réponse a le statut 201 et la campagne avec chaque message.

ChampDescription
toobligatoireUn numéro ou un tableau de jusqu'à 10,000 numéros au format international. Les numéros répétés sont envoyés une fois ; les numéros illisibles sont listés dans skipped.
textobligatoireLe message, jusqu'à 2,000 caractères et 10 segments. Le texte GSM-7 contient 160 caractères par SMS, Unicode 70.
send_atoptionnelHeure ISO 8601 pour planifier l'envoi, de 5 minutes à 60 jours à l'avance. Omettez pour envoyer maintenant.
opt_outoptionneltrue ajoute votre mention de désinscription des paramètres de la console sur une nouvelle ligne à la fin.
client_refoptionnelVotre propre référence, jusqu'à 64 lettres, chiffres et _ . : -. Elle est renvoyée dans les rapports et les webhooks.
curl -X POST https://bulksmsonline.cc/api/v1/messages \
  -H "Authorization: Bearer $BSO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":["+447700900412","+33612345678"],"text":"Order 4521 has shipped. Track it at shop.example/t/4521","client_ref":"order-4521"}'
HTTP/1.1 201 Created
{
  "id": "CMP-7KQ2-M9XA-4HTD",
  "status": "sending",
  "channel": "api",
  "recipients": 2,
  "segments": 1,
  "encoding": "GSM-7",
  "cost": "0.02158",
  "refunded": "0.00000",
  "client_ref": "order-4521",
  "send_at": null,
  "counts": { "queued": 2, "submitted": 0, "delivered": 0, "failed": 0, "canceled": 0 },
  "skipped": [],
  "balance": "118.43120",
  "messages": [
    { "id": "MSG-3RTW-81KD-ZQ0P", "to": "+447700900412", "country": "GB", "segments": 1, "price": "0.00834", "status": "queued" },
    { "id": "MSG-5HNA-4C2E-7YVB", "to": "+33612345678", "country": "FR", "segments": 1, "price": "0.01324", "status": "queued" }
  ]
}

Devis d'envoi

POST/v1/quote

Prend le même corps que /v1/messages et renvoie le coût exact, les segments et l'encodage sans envoyer ni facturer quoi que ce soit. Utilisez-le pour afficher un prix à vos propres utilisateurs avant qu'ils ne confirment.

{
  "recipients": 2,
  "skipped": [],
  "segments": 1,
  "encoding": "GSM-7",
  "cost": "0.02158",
  "balance": "118.45278",
  "countries": [ { "country": "GB", "recipients": 1, "cost": "0.00834" }, { "country": "FR", "recipients": 1, "cost": "0.01324" } ]
}

Solde

GET/v1/balance

{ "balance": "118.43120", "currency": "USD" }

Tarifs

GET/v1/rates

GET/v1/rates/{country}

Le prix d'un segment SMS pour chaque destination, ou pour un code pays ISO à deux lettres. Ces deux endpoints sont publics et ne nécessitent pas de clé.

{ "country": "DE", "name": "Germany", "calling_code": "+49", "price": "0.01544", "currency": "USD", "per": "segment" }

Statut du message

GET/v1/messages/{id}

{
  "id": "MSG-3RTW-81KD-ZQ0P",
  "campaign_id": "CMP-7KQ2-M9XA-4HTD",
  "to": "+447700900412",
  "country": "GB",
  "segments": 1,
  "price": "0.00834",
  "status": "delivered",
  "error": null,
  "created_at": "2026-11-07T09:00:02Z",
  "submitted_at": "2026-11-07T09:00:03Z",
  "final_at": "2026-11-07T09:00:08Z"
}

Campagnes

GET/v1/campaigns/{id}

GET/v1/campaigns/{id}/messages?offset=0&limit=100

Le premier renvoie la campagne avec ses comptes par statut ; le second pagine ses messages, jusqu'à 1 000 par page. Les campagnes envoyées depuis la console peuvent être lues de la même manière avec l'id affiché sur leur page.

Annuler un envoi programmé

POST/v1/campaigns/{id}/cancel

Arrête une campagne créée avec send_at et qui n'a pas encore commencé. Chaque message est annulé et le coût total est retourné au solde. Une campagne déjà en cours d'envoi répond 409 not_scheduled.

Webhooks de livraison

Ajoutez une URL HTTPS sous API dans la console pour recevoir chaque statut final (livré ou échoué) sous forme de requête POST. Répondez avec n'importe quel statut 2xx dans les 8 secondes. Les autres réponses et les timeouts sont réessayés après 20 secondes, 1, 5 et 15 minutes, puis 1, 3, 6 et 12 heures, 9 tentatives au total. Le même événement peut arriver deux fois, utilisez donc event_id pour le traiter une fois.

POST https://your-server.example/sms-status
Content-Type: application/json
X-BulkSMSOnline-Signature: t=1794042008,v1=5f0c2a...e91b

{
  "type": "message.status",
  "event_id": "ev_8f1c22d0a4b97e63c1f0",
  "sent_at": "2026-11-07T09:00:09Z",
  "data": {
    "message_id": "MSG-3RTW-81KD-ZQ0P",
    "campaign_id": "CMP-7KQ2-M9XA-4HTD",
    "to": "+447700900412",
    "country": "GB",
    "status": "delivered",
    "error": null,
    "segments": 1,
    "price": "0.00834",
    "currency": "USD",
    "client_ref": "order-4521",
    "final_at": "2026-11-07T09:00:08Z"
  }
}

Vérifiez la signature

L'en-tête contient le temps Unix t et la signature v1 = HMAC-SHA256 de la chaîne "t.raw_body" avec votre secret webhook, en hexadécimal. Calculez-la sur le corps brut avant d'analyser le JSON, comparez en temps constant et rejetez les événements de plus de cinq minutes.

import crypto from "node:crypto";

export function verify(rawBody, header, secret) {
  const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(header || "");
  if (!m || Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false;
  const want = crypto.createHmac("sha256", secret).update(m[1] + "." + rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(want), Buffer.from(m[2]));
}

Statuts

queuedAccepté et en attente de quitter la file
submittedRemis au réseau de destination
deliveredConfirmé par le terminal (final)
failedN'a pas pu être livré ; le prix est remboursé (final)
canceledPartie d'une campagne planifiée annulée avant l'envoi (final)

Le statut de la campagne est scheduled, sending, complete ou canceled.

Erreurs

Les erreurs répondent avec un statut HTTP et un corps JSON : { "error": { "code": "insufficient_balance", "message": "..." } }. Rien n'est facturé lorsqu'une demande répond avec une erreur.

HTTPCodeSignification
400invalid_requestUn champ est manquant ou non valide ; le message indique lequel.
400invalid_jsonLe corps n'est pas du JSON.
400no_valid_numbersAucun des numéros n'a pu être lu.
401unauthorizedLa clé est manquante, mal formée ou remplacée.
402insufficient_balanceLe solde ne couvre pas le coût ; rechargez et renvoyez.
404not_foundID ou endpoint inconnu.
409not_scheduledSeule une campagne planifiée qui n'a pas démarré peut être annulée.
413too_many_recipientsPlus de 10,000 numéros dans une seule requête.
429rate_limitedPlus de 300 requêtes par minute.
500server_errorRéessayez la requête ; rien n'a été facturé.

Obtenez une clé API dans la console

Créez un compte, ajoutez votre première recharge et générez une clé sous API. Votre première requête peut être envoyée une minute plus tard.

Créer un compte
Référence API SMS en masse : Endpoints REST et Webhooks | BulkSMSOnline