SmsEmpire

L'API SmsEmpire

Achetez des vérifications SMS et e-mail depuis votre propre code, débitées de votre solde, avec une remise sur le prix du site.

  • Tarif remisé sur chaque achat effectué via l'API
  • Webhooks signés dès l'arrivée du code — pas de boucle d'interrogation
  • Achats idempotents : réessayer après un timeout est sans risque

Démarrage rapide

Tout se trouve sous https://smsempire.com/api/v1. Authentifiez-vous en envoyant votre clé comme bearer token. Côté serveur uniquement : cette API n'envoie aucun en-tête CORS, et une clé utilisée depuis un navigateur est une clé divulguée.

# 1. Create a key in your dashboard, then:
export SE_KEY="se_live_XXXXXXXXXXXX_..."

# 2. What will this cost?
curl -s https://smsempire.com/api/v1/prices?service=tg \
  -H "Authorization: Bearer $SE_KEY"

# 3. Buy a number. The Idempotency-Key is required.
curl -s https://smsempire.com/api/v1/activations \
  -H "Authorization: Bearer $SE_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"service":"tg","max_price":"0.35"}'

# 4. Collect the code (or let the webhook push it to you).
curl -s https://smsempire.com/api/v1/activations/90210 \
  -H "Authorization: Bearer $SE_KEY"

Conventions

  • L'argent est une chaîne décimale ("0.28000"), jamais un nombre JSON. Analysez-la avec un type décimal, pas un float.
  • Les horodatages sont en RFC3339 UTC.
  • Les erreurs sont toujours {"error": {"code", "message", "request_id"}}. Branchez sur code ; message peut changer.
  • Citez le request_id dans tout ticket de support : il pointe directement sur la requête dans nos journaux.
  • Les limites reviennent dans les en-têtes X-RateLimit-*, et un 429 porte Retry-After.

Idempotence (obligatoire à l'achat)

Chaque achat exige un en-tête Idempotency-Key — un UUID est idéal. La réutiliser renvoie la réponse d'origine avec Idempotent-Replay: true au lieu d'acheter un second numéro.

Cela existe pour une seule situation : votre POST expire et vous ignorez s'il a abouti. Sans la clé, réessayer achète deux fois et ne pas réessayer perd le numéro déjà payé. Avec elle, réessayez simplement.

Réutiliser une clé avec un corps différent renvoie 422, pas une répétition silencieuse : cette combinaison est un bug de votre côté, et la masquer vous donnerait un résultat faux.

max_price

Facultatif mais vivement recommandé. Si vous omettez le pays, nous en essayons plusieurs, par ordre de qualité et à des prix différents ; max_price est vérifié sur chaque candidat, vous ne pouvez donc jamais être facturé plus que ce que vous avez accepté. Si rien ne convient, vous obtenez 409 PRICE_ABOVE_MAX avec le prix actuel, et rien n'est débité.

Webhooks

Enregistrez un endpoint HTTPS dans votre tableau de bord. Nous envoyons un POST dès qu'un code arrive. La livraison est au moins une fois, réessayée avec un délai croissant sur environ deux heures et demie.

POST /your/webhook
X-SmsEmpire-Event: activation.code_received
X-SmsEmpire-Delivery: evt_01j8z...        <- deduplicate on this
X-SmsEmpire-Timestamp: 1765432991
X-SmsEmpire-Signature: v1=3a7f...

{
  "id": "evt_01j8z...",
  "type": "activation.code_received",
  "created_at": "2026-08-14T12:03:11Z",
  "data": {
    "activation_id": 90210,
    "service": "tg",
    "country": "2",
    "number": "+79991234567",
    "code": "483920",
    "status": "received",
    "price": "0.28000"
  }
}

Exigences pour votre endpoint : HTTPS sur le port 443, résolvant vers une adresse publique. Nous ne suivons pas les redirections et refusons les destinations privées, loopback et métadonnées cloud.

Vérifier un webhook

La signature est HMAC-SHA256(secret, "<timestamp>.<corps brut>"), encodée en hexadécimal. Quatre erreurs courantes, par ordre de fréquence :

  1. Signer le JSON re-sérialisé au lieu des octets bruts. La re-sérialisation change les octets et la signature ne correspondra jamais.
  2. Ignorer l'horodatage. Sans la vérification ±300 s, une livraison capturée peut vous être rejouée indéfiniment.
  3. Comparer avec == au lieu d'une comparaison à temps constant.
  4. Ne pas dédupliquer sur X-SmsEmpire-Delivery. Nous garantissons au moins une fois, pas exactement une fois.
import hmac, hashlib, time
from flask import request, abort

SECRET = "whsec_..."          # from your dashboard
TOLERANCE = 300               # seconds

def verify(request):
    raw = request.get_data()                       # RAW bytes, before json parsing
    ts = request.headers.get("X-SmsEmpire-Timestamp", "")
    sig_header = request.headers.get("X-SmsEmpire-Signature", "")

    if abs(time.time() - int(ts)) > TOLERANCE:     # blocks replays
        abort(400)

    expected = hmac.new(SECRET.encode(),
                        f"{ts}.".encode() + raw,
                        hashlib.sha256).hexdigest()

    # More than one v1= during a secret rotation; any match is valid.
    sigs = [p.split("=", 1)[1] for p in sig_header.split(",") if p.startswith("v1=")]
    if not any(hmac.compare_digest(expected, s) for s in sigs):
        abort(400)
const crypto = require("crypto");

// express.raw({type: "application/json"}) — you need the RAW body, not the parsed one.
function verify(req, secret) {
  const ts = req.get("X-SmsEmpire-Timestamp") || "";
  const header = req.get("X-SmsEmpire-Signature") || "";

  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;

  const expected = crypto
    .createHmac("sha256", secret)
    .update(Buffer.concat([Buffer.from(ts + "."), req.body]))
    .digest("hex");

  return header
    .split(",")
    .filter((p) => p.startsWith("v1="))
    .some((p) =>
      crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(p.slice(3))),
    );
}

La rotation du secret conserve le précédent valide 24 heures, et les deux signent chaque livraison pendant cette fenêtre — vous pouvez donc déployer sans interruption.

Erreurs

codeQue faire
INVALID_API_KEYClé absente, mal formée ou inconnue. Ne réessayez pas.
KEY_REVOKED / KEY_EXPIREDCréez une nouvelle clé. Ne réessayez pas.
INSUFFICIENT_SCOPECette clé a été créée sans accès en écriture.
API_ACCESS_DENIEDL'API est désactivée pour ce compte, ou vous n'avez pas encore rechargé.
API_DISABLEDL'API est temporairement désactivée pour tous. Réessayez plus tard.
IDEMPOTENCY_KEY_REQUIREDEnvoyez un en-tête Idempotency-Key à chaque achat.
IDEMPOTENCY_KEY_REUSEDMême clé, corps différent. Corrigez votre client.
IDEMPOTENCY_IN_PROGRESSLa première tentative est encore en cours. Réessayez dans une seconde.
PRICE_ABOVE_MAXLe prix a dépassé votre max_price. Redemandez un devis et décidez.
INSUFFICIENT_BALANCERechargez. Ne réessayez pas avant.
COUNTRY_OUT_OF_STOCKAucun numéro pour l'instant. Réessayez ou choisissez un autre pays.
PROVIDER_CAPACITYImpossible de fournir ce pays temporairement. Réessayez plus tard.
CONCURRENCY_LIMITTrop d'activations en attente. Terminez-en ou annulez-en.
SPEND_LIMITPlafond de dépense horaire atteint. Réessayez après la fenêtre.
RATE_LIMITEDRalentissez. Respectez Retry-After.
VALIDATION_ERRORLe corps de votre requête est incorrect. Ne réessayez pas sans le modifier.

Cycle de vie d'une activation

Une activation est pending jusqu'à l'arrivée d'un code (received), jusqu'à ce que vous la marquiez utilisée (finished) ou qu'elle soit annulée. L'annulation rembourse exactement ce qui a été facturé.

Une activation en attente expire 20 minutes après l'achat. Nous l'annulons auprès du réseau et vous remboursons intégralement une fois cette annulation confirmée — vous ne payez jamais pour un numéro qui n'a rien reçu.

Un délai de grâce d'environ 120 secondes s'applique avant de pouvoir annuler un numéro ; annuler plus tôt renvoie EARLY_CANCEL_DENIED avec le nombre de secondes à attendre.

Limites

Les requêtes en lecture, en écriture et le total par utilisateur ont chacun un plafond par minute, et des plafonds facultatifs existent sur les activations en attente, la dépense horaire et le nombre d'activations par heure. Vos valeurs actuelles sont dans GET /api/v1/me, où null signifie aucune limite. Pour les augmenter, ouvrez un ticket : ce sont des réglages par compte, pas des valeurs codées en dur.

Référence complète des endpoints

Document OpenAPI 3.1 interactif, toujours généré à partir du code en cours d'exécution.

Ouvrir la référence