Schnellstart
- Erstellen Sie ein Konto und laden Sie Ihr Guthaben in der Konsole auf.
- Öffnen Sie API-Schlüssel und erstellen Sie einen Schlüssel. Schlüssel können nach der ersten Guthabenaufladung erstellt werden. Der Schlüssel wird einmal angezeigt; bewahren Sie ihn als Geheimnis auf.
- Senden Sie eine POST-Anfrage an
/smsmit den Nummern und dem Text. Lesen Sie die zurückgegebene Kampagnen-ID und verfolgen Sie dann die Zustellung in der Konsole oder über Webhooks.
Authentifizierung
Jede Anfrage außer der öffentlichen Preisliste trägt Ihren Schlüssel im Authorization-Header. Schlüssel beginnen mit sbk_live_. Ein neuer Schlüssel ersetzt den alten sofort.
Authorization: Bearer sbk_live_YOUR_KEYSMS senden
POST/sms
Erstellt eine Kampagne, belastet sie vom Guthaben und reiht jede Nachricht in die Warteschlange ein. Nummern werden bereinigt und dedupliziert; solche, die nicht verwendet werden können, werden in dropped mit einem Grund zurückgegeben und nicht belastet.
| Feld | Typ | Beschreibung |
|---|---|---|
toerforderlich | String oder Array | Eine Nummer oder ein Array von bis zu 10,000 Nummern im internationalen Format, zum Beispiel "+447700900461" |
texterforderlich | String | Nachrichtentext, bis zu 10 Segmenten. GSM-7-Text passt in 160 Zeichen pro Segment, UCS-2 in 70 |
schedule_atoptional | String | ISO 8601-Zeit von 5 Minuten bis zu 60 Tagen im Voraus. Lassen Sie dies weg, um sofort zu senden |
client_refoptional | String | Ihr eigener Verweis, bis zu 64 Zeichen aus a-z A-Z 0-9 _ . : -, wird in Berichten und Webhooks zurückgegeben |
opt_outoptional | Boolean | true fügt den Abmeldehinweis hinzu, der in Ihren Kontoeinstellungen festgelegt ist |
curl -X POST https://sendbulksms.cc/api/v1/sms \
-H "Authorization: Bearer sbk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": ["+447700900461", "+5511955550123"],
"text": "Hi, your order 4821 ships today.",
"client_ref": "orders-4821"
}'const res = await fetch("https://sendbulksms.cc/api/v1/sms", {
method: "POST",
headers: { Authorization: "Bearer " + process.env.SENDBULKSMS_KEY, "Content-Type": "application/json" },
body: JSON.stringify({ to: ["+447700900461", "+5511955550123"], text: "Hi, your order 4821 ships today.", client_ref: "orders-4821" }),
});
const campaign = await res.json();
console.log(res.status, campaign.id, campaign.cost);import os, requests
r = requests.post(
"https://sendbulksms.cc/api/v1/sms",
headers={"Authorization": "Bearer " + os.environ["SENDBULKSMS_KEY"]},
json={"to": ["+447700900461", "+5511955550123"], "text": "Hi, your order 4821 ships today.", "client_ref": "orders-4821"},
timeout=30,
)
print(r.status_code, r.json()["id"])<?php
$ch = curl_init("https://sendbulksms.cc/api/v1/sms");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("SENDBULKSMS_KEY"), "Content-Type: application/json"],
CURLOPT_POSTFIELDS => json_encode(["to" => ["+447700900461", "+5511955550123"], "text" => "Hi, your order 4821 ships today.", "client_ref" => "orders-4821"]),
]);
$campaign = json_decode(curl_exec($ch), true);
echo $campaign["id"];Antwort: die Kampagne mit ihren Kosten und den ersten 1.000 Nachrichten. Holen Sie mehr mit Kampagnennachrichten.
HTTP/1.1 201 Created
{
"id": "CP-7KQ2-M9XA-4HTD",
"status": "sending",
"source": "api",
"recipients": 2,
"segments": 1,
"encoding": "GSM-7",
"cost": "0.01078",
"refunded": "0.00000",
"client_ref": "orders-4821",
"scheduled_at": null,
"created_at": "2026-11-07T10:32:04.118Z",
"done_at": null,
"counts": { "queued": 2, "sent": 0, "delivered": 0, "failed": 0, "canceled": 0 },
"dropped": [],
"balance": "248.30422",
"messages": [
{ "id": "SM-2RBW-8MZN-QF6K", "campaign_id": "CP-7KQ2-M9XA-4HTD", "to": "+447700900461", "country": "GB", "parts": 1, "price": "0.00819", "status": "queued", "error": null, "created_at": "2026-11-07T10:32:04.118Z", "sent_at": null, "done_at": null }
]
}Sendung schätzen
POST/estimate
Nimmt den gleichen Body wie /sms und gibt die Empfänger, Segmente, Kodierung, Gesamtkosten und die Kosten pro Land zurück, ohne etwas zu belasten oder zu senden.
{ "recipients": 2, "dropped": [], "segments": 1, "encoding": "GSM-7", "cost": "0.01078", "balance": "248.31500",
"countries": [ { "country": "GB", "recipients": 1, "cost": "0.00819" }, { "country": "BR", "recipients": 1, "cost": "0.00259" } ] }Nachrichtenstatus
GET/sms/{message_id}
Gibt eine Nachricht zurück: Nummer, Land, Segmente, Preis, Status, den Fehler für fehlgeschlagene Nachrichten und die Zeit jedes Schritts.
Kampagnen
GET/campaigns/{campaign_id}
Die Kampagne mit ihren Kosten, Rückerstattungen und einer Anzahl von Nachrichten pro Status.
GET/campaigns/{campaign_id}/messages?offset=0&limit=100
Nachrichten in der Reihenfolge, in der sie in die Warteschlange gestellt wurden, bis zu 1.000 pro Seite.
POST/campaigns/{campaign_id}/cancel
Bricht eine geplante Kampagne ab, die noch nicht gestartet ist, und erstattet die vollen Kosten an das Guthaben zurück.
Guthaben und Preise
GET/balance
{ "balance": "248.31500", "currency": "USD" }GET/rates
Öffentlich, kein Schlüssel benötigt. Jedes Land mit seiner Vorwahl und dem Preis pro Segment. /rates/GB gibt ein Land zurück.
{ "updated": "2026-11-07", "rates": [ { "country": "GB", "name": "United Kingdom", "calling_code": "+44", "price": "0.00819", "currency": "USD", "unit": "SMS segment" } ] }Zustellungswebhooks
Legen Sie eine Webhook-URL in der Konsole unter API-Schlüssel fest. Wenn eine Nachricht einen endgültigen Status erreicht (zugestellt oder fehlgeschlagen), senden wir einen Bericht per POST dorthin. Antworten Sie mit einem beliebigen 2xx-Status innerhalb von 8 Sekunden; andernfalls wird der Aufruf bis zu 8 Mal über etwa 11 Stunden wiederholt. Verwenden Sie id, um einen Bericht zu ignorieren, den Sie bereits verarbeitet haben.
POST https://your-server.example/sms-status
Content-Type: application/json
X-SendBulkSMS-Signature: t=1794047524,v1=5f0c3b9e...
{
"event": "message.status",
"id": "evt_8c1d2e4f6a7b9c0d1e2f",
"created_at": "2026-11-07T10:32:09.004Z",
"data": {
"message_id": "SM-2RBW-8MZN-QF6K",
"campaign_id": "CP-7KQ2-M9XA-4HTD",
"to": "+447700900461",
"country": "GB",
"status": "delivered",
"error": null,
"parts": 1,
"price": "0.00819",
"client_ref": "orders-4821",
"done_at": "2026-11-07T10:32:08.912Z"
}
}Überprüfen Sie die Signatur, bevor Sie einem Bericht vertrauen: HMAC-SHA256 von t + "." + raw body mit Ihrem Webhook-Geheimnis, verglichen in konstanter Zeit, und lehnen Sie Zeiten ab, die älter als 5 Minuten sind.
import { createHmac, timingSafeEqual } from "node:crypto";
// raw = the request body exactly as received (string), header = X-SendBulkSMS-Signature
export function verify(raw, 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 = Buffer.from(createHmac("sha256", secret).update(m[1] + "." + raw).digest("hex"));
const got = Buffer.from(m[2]);
return want.length === got.length && timingSafeEqual(want, got);
}import hmac, hashlib, re, time
def verify(raw: bytes, header: str, secret: str) -> bool:
m = re.fullmatch(r"t=(\d+),v1=([0-9a-f]{64})", header or "")
if not m or abs(time.time() - int(m.group(1))) > 300:
return False
want = hmac.new(secret.encode(), m.group(1).encode() + b"." + raw, hashlib.sha256).hexdigest()
return hmac.compare_digest(want, m.group(2))<?php
function verify(string $raw, string $header, string $secret): bool {
if (!preg_match('/^t=(\d+),v1=([0-9a-f]{64})$/', $header, $m) || abs(time() - (int)$m[1]) > 300) return false;
$want = hash_hmac('sha256', $m[1] . '.' . $raw, $secret);
return hash_equals($want, $m[2]);
}Status
| Status | Bedeutung |
|---|---|
queued | Akzeptiert und belastet, wartet auf seinen Platz in der Warteschlange |
sent | An die Route übergeben, wartet auf den Zustellbericht |
delivered | Das Netzwerk hat die Zustellung an das Handy bestätigt |
failed | Nicht zugestellt; der Preis wird erstattet und der Fehler enthält den Grund |
canceled | Teil einer geplanten Kampagne, die vor dem Start abgebrochen wurde; erstattet |
Fehler
Fehler verwenden HTTP-Statuscodes und einen JSON-Body: { "error": { "code": "insufficient_balance", "message": "..." } }. Eine Anfrage, die einen Fehler zurückgibt, belastet das Guthaben nicht.
| HTTP | Code | Wann |
|---|---|---|
| 400 | bad_requestEin Feld fehlt oder ist ungültig; die Nachricht erklärt welches | Ein Feld fehlt oder ist ungültig; die Nachricht erklärt welches |
| 400 | no_valid_numbersKeine der Nummern in "to" konnte verwendet werden | Keine der Nummern in "to" konnte verwendet werden |
| 401 | unauthorizedDer API-Schlüssel fehlt oder ist ungültig | Der API-Schlüssel fehlt oder ist ungültig |
| 402 | insufficient_balanceDas Guthaben deckt den Versand nicht ab; es wurde nichts belastet | Das Guthaben deckt den Versand nicht ab; es wurde nichts belastet |
| 404 | not_foundDie Kampagne, Nachricht oder der Endpunkt existiert nicht in Ihrem Konto | Die Kampagne, Nachricht oder der Endpunkt existiert nicht in Ihrem Konto |
| 409 | not_scheduledNur eine geplante Kampagne, die noch nicht gestartet wurde, kann abgebrochen werden | Nur eine geplante Kampagne, die noch nicht gestartet wurde, kann abgebrochen werden |
| 413 | too_many_recipientsMehr als 10,000 Nummern in einer Anfrage | Mehr als 10,000 Nummern in einer Anfrage |
| 429 | rate_limitedMehr als 300 Anfragen pro Minute für diesen Schlüssel | Mehr als 300 Anfragen pro Minute für diesen Schlüssel |
| 500 | server_errorVersuchen Sie es erneut; für eine fehlgeschlagene Anfrage wird keine Gebühr erhoben | Versuchen Sie es erneut; für eine fehlgeschlagene Anfrage wird keine Gebühr erhoben |
Limits
- 300 Anfragen pro Minute pro API-Schlüssel.
- 10,000 Nummern pro Versandanfrage; 10 Segmente pro Nachricht.
- Nachrichten werden mit bis zu 200 pro Minute pro Warteschlange in der Reihenfolge ihres Eingangs versendet.
- Planung von 5 Minuten bis zu 60 Tagen im Voraus.
- Nummern auf Ihrer Nicht-Senden-Liste werden übersprungen und in dropped mit dem Code suppressed zurückgegeben; sie werden nicht belastet.