Die SmsEmpire-API
Kaufen Sie SMS- und E-Mail-Verifizierungen aus Ihrem eigenen Code, bezahlt aus Ihrem Guthaben, mit Rabatt auf den Website-Preis.
- →Rabattierter Preis bei jedem Kauf über die API
- →Signierte Webhooks, sobald der Code eintrifft — keine Polling-Schleife
- →Idempotente Käufe: ein Timeout lässt sich gefahrlos wiederholen
Schnellstart
Alles liegt unter https://smsempire.com/api/v1. Authentifizieren Sie sich mit Ihrem Schlüssel als Bearer-Token. Nur serverseitig — diese API sendet keine CORS-Header, und ein im Browser verwendeter Schlüssel ist ein geleakter Schlüssel.
# 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"Konventionen
- Geld ist ein Dezimal-String ("0.28000"), nie eine JSON-Zahl. Mit einem Decimal-Typ parsen, nicht als Float.
- Zeitstempel sind RFC3339 UTC.
- Fehler sind immer {"error": {"code", "message", "request_id"}}. Verzweigen Sie über code; message kann sich ändern.
- Nennen Sie die request_id in jedem Support-Ticket — sie zeigt direkt auf die Anfrage in unseren Logs.
- Limits kommen in den X-RateLimit-*-Headern zurück, und ein 429 trägt Retry-After.
Idempotenz (bei Käufen erforderlich)
Jeder Kauf braucht einen Idempotency-Key-Header — eine UUID ist ideal. Wiederverwendung liefert die ursprüngliche Antwort mit Idempotent-Replay: true, statt eine zweite Nummer zu kaufen.
Das gibt es für genau eine Situation: Ihr POST läuft in einen Timeout und Sie wissen nicht, ob er durchging. Ohne den Schlüssel kauft ein Retry doppelt, und kein Retry verliert die bereits bezahlte Nummer. Mit ihm wiederholen Sie einfach.
Derselbe Schlüssel mit anderem Body ergibt 422, keine stille Wiederholung — diese Kombination ist ein Fehler auf Ihrer Seite, und ihn zu verbergen würde Ihnen ein falsches Ergebnis liefern.
max_price
Optional, aber dringend empfohlen. Ohne Länderangabe probieren wir mehrere, nach Qualität sortiert und zu unterschiedlichen Preisen; max_price wird gegen jeden Kandidaten geprüft, sodass Ihnen nie mehr berechnet werden kann als vereinbart. Passt keiner, erhalten Sie 409 PRICE_ABOVE_MAX mit dem aktuellen Preis, und es wird nichts belastet.
Webhooks
Registrieren Sie einen HTTPS-Endpunkt in Ihrem Dashboard. Wir senden ein POST, sobald ein Code eintrifft. Die Zustellung erfolgt mindestens einmal, mit Backoff über rund zweieinhalb Stunden wiederholt.
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"
}
}Anforderungen an Ihren Endpunkt: HTTPS auf Port 443, auflösend auf eine öffentliche Adresse. Wir folgen keinen Weiterleitungen und lehnen private, Loopback- und Cloud-Metadaten-Ziele ab.
Einen Webhook verifizieren
Die Signatur ist HMAC-SHA256(secret, "<timestamp>.<Roh-Body>"), hex-kodiert. Vier häufige Fehler, nach Häufigkeit:
- Das re-serialisierte JSON signieren statt der Roh-Bytes. Re-Serialisieren ändert die Bytes, und die Signatur passt nie.
- Den Zeitstempel ignorieren. Ohne die ±300-s-Prüfung lässt sich eine abgefangene Zustellung ewig gegen Sie wiederholen.
- Mit == vergleichen statt mit einem zeitkonstanten Vergleich.
- Nicht über X-SmsEmpire-Delivery deduplizieren. Wir garantieren mindestens einmal, nicht genau einmal.
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))),
);
}Beim Rotieren bleibt das vorherige Secret 24 Stunden gültig, und beide signieren in diesem Fenster jede Zustellung — Sie können also ohne Ausfall deployen.
Fehler
| code | Was zu tun ist |
|---|---|
| INVALID_API_KEY | Schlüssel fehlt, ist fehlerhaft oder unbekannt. Nicht wiederholen. |
| KEY_REVOKED / KEY_EXPIRED | Neuen Schlüssel erstellen. Nicht wiederholen. |
| INSUFFICIENT_SCOPE | Dieser Schlüssel wurde ohne Schreibzugriff erstellt. |
| API_ACCESS_DENIED | Die API ist für dieses Konto deaktiviert, oder Sie haben noch nicht aufgeladen. |
| API_DISABLED | Die API ist plattformweit vorübergehend deaktiviert. Später erneut versuchen. |
| IDEMPOTENCY_KEY_REQUIRED | Senden Sie bei jedem Kauf einen Idempotency-Key-Header. |
| IDEMPOTENCY_KEY_REUSED | Gleicher Schlüssel, anderer Body. Korrigieren Sie Ihren Client. |
| IDEMPOTENCY_IN_PROGRESS | Der erste Versuch läuft noch. In einer Sekunde erneut versuchen. |
| PRICE_ABOVE_MAX | Der Preis liegt über Ihrem max_price. Neu abfragen und entscheiden. |
| INSUFFICIENT_BALANCE | Guthaben aufladen. Vorher nicht wiederholen. |
| COUNTRY_OUT_OF_STOCK | Derzeit keine Nummern. Erneut versuchen oder anderes Land wählen. |
| PROVIDER_CAPACITY | Dieses Land ist vorübergehend nicht lieferbar. Später erneut versuchen. |
| CONCURRENCY_LIMIT | Zu viele offene Aktivierungen. Einige abschließen oder stornieren. |
| SPEND_LIMIT | Stündliches Ausgabelimit erreicht. Nach dem Fenster erneut versuchen. |
| RATE_LIMITED | Langsamer. Retry-After beachten. |
| VALIDATION_ERROR | Ihr Request-Body ist falsch. Nicht unverändert wiederholen. |
Lebenszyklus einer Aktivierung
Eine Aktivierung ist pending, bis ein Code eintrifft (received), Sie sie als benutzt markieren (finished) oder sie storniert wird. Stornieren erstattet genau den berechneten Betrag.
Eine offene Aktivierung verfällt 20 Minuten nach dem Kauf. Wir stornieren sie im Netz und erstatten Ihnen den vollen Betrag, sobald diese Stornierung bestätigt ist — Sie zahlen nie für eine Nummer, die nichts empfangen hat.
Vor dem Stornieren einer Nummer gilt eine Karenzzeit von etwa 120 Sekunden; früheres Stornieren liefert EARLY_CANCEL_DENIED mit den verbleibenden Sekunden.
Limits
Lesende Anfragen, schreibende Anfragen und die Gesamtzahl pro Nutzer haben je eine Obergrenze pro Minute, dazu optionale Limits für offene Aktivierungen, stündliche Ausgaben und Aktivierungen pro Stunde. Ihre aktuellen Werte stehen in GET /api/v1/me, wobei null „kein Limit“ bedeutet. Für eine Anhebung öffnen Sie ein Ticket — es sind Kontoeinstellungen, keine fest codierten Werte.
Vollständige Endpunkt-Referenz
Interaktives OpenAPI-3.1-Dokument, stets aus dem laufenden Code generiert.
Referenz öffnen