API v2 (Beta)
API v2
API v2 ist die neue REST-API von WbizTool: ein Schlüssel pro App mit genau dem Zugriff, den sie braucht, ressourcenorientierte URLs, echte HTTP-Statuscodes, signierte JSON-Webhooks und sichere Wiederholungen. Diese Seite beschreibt, was alle Requests gemeinsam haben. Die einzelnen Endpoints finden Sie auf den Ressourcenseiten.
Basis-URL#
https://wbiztool.com/api/v2
Pfade haben keinen abschließenden Schrägstrich (/api/v2/messages), einer wird aber ebenfalls akzeptiert. Eine Adresse, die es nicht gibt, antwortet mit 404 und dem Code not_found.
Kurzes Beispiel#
Prüfen Sie Ihren Schlüssel mit GET /me. Das funktioniert mit jedem Scope und sendet nichts:
curl https://wbiztool.com/api/v2/me \
-H "Authorization: Bearer $WBIZTOOL_API_KEY"import os
import requests
response = requests.get(
"https://wbiztool.com/api/v2/me",
headers={"Authorization": f"Bearer {os.environ['WBIZTOOL_API_KEY']}"},
timeout=30,
)
print(response.status_code, response.json())// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const response = await fetch("https://wbiztool.com/api/v2/me", {
headers: { Authorization: `Bearer ${process.env.WBIZTOOL_API_KEY}` },
});
console.log(response.status, await response.json());<?php
$ch = curl_init('https://wbiztool.com/api/v2/me');
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('WBIZTOOL_API_KEY')],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
]);
$body = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), "\n";
print_r($body);
curl_close($ch);{
"workspace": { "id": 5012, "name": "Acme Bakery" },
"key": {
"id": 7,
"name": "Order system",
"mode": "live",
"scopes": ["messages:send", "messages:read"],
"limited_to_numbers": false,
"number_ids": [],
"expires_at": null
},
"plan": { "name": "Starter" },
"limits": {
"requests_per_minute": 60,
"requests_per_day": 10000,
"messages_per_number_per_day": 1000,
"messages_remaining": null
}
}
messages_remaining ist null, wenn der Plan unbegrenzt viele Nachrichten sendet. plan ist null, wenn der Arbeitsbereich keinen aktiven Plan hat.
Schlüssel#
Senden Sie Ihren Schlüssel bei jedem Request im Header Authorization:
Authorization: Bearer wbz_live_…
Eine client_id gibt es nicht: Der Schlüssel bestimmt seinen Arbeitsbereich. Ein v2-Schlüssel beginnt mit wbz_live_ oder wbz_test_, gefolgt von 38 Buchstaben und Ziffern. v1-Schlüssel funktionieren nicht mit v2 (sie erhalten v1_key_on_v2), und v2-Schlüssel funktionieren nicht mit v1.
Schlüssel erstellen#
Inhaber erstellen Schlüssel unter Einstellungen → API-Schlüssel in der Karte API-v2-Schlüssel: Klicken Sie auf v2-Schlüssel erstellen und wählen Sie dann:
- Name: die App, die ihn nutzen wird, bis zu 50 Zeichen.
- Art des Schlüssels: Live sendet echte Nachrichten; Test prüft alles und sendet nichts (siehe Testmodus).
- Was er darf: die Scopes oder Alles.
- Nummern, die er nutzen darf: alle Nummern, auch später hinzugefügte, oder nur einige (siehe Auf einige Nummern beschränkte Schlüssel).
- Läuft ab: nie oder in 30 Tagen, 90 Tagen oder 1 Jahr.
Der Schlüssel wird nur einmal angezeigt. Kopieren Sie ihn sofort und speichern Sie ihn auf Ihrem Server, zum Beispiel in einer Umgebungsvariablen. WbizTool speichert nur einen Hash und seine letzten vier Zeichen, ein verlorener Schlüssel kann also nicht erneut angezeigt werden: Widerrufen Sie ihn und erstellen Sie einen neuen.
Ein Arbeitsbereich kann bis zu 10 nicht widerrufene v2-Schlüssel haben. Die Karte zeigt für jeden Schlüssel die letzten vier Zeichen, Scopes, Nummern, das Ablaufdatum und wann und von welcher IP-Adresse er zuletzt verwendet wurde. Widerrufen sperrt einen Schlüssel sofort und mit ihm die Webhook-Endpunkte, die er angelegt hat. Ein Schlüssel nach seinem Ablaufdatum erhält api_key_expired.
Scopes#
Jeder Schlüssel darf nur, was seine Scopes erlauben. Ein Request außerhalb davon antwortet mit 403 und missing_scope, und required_scope im Fehler nennt den benötigten Scope.
| Scope | Was er erlaubt |
|---|---|
messages:send | Nachrichten und Batches senden und wartende Nachrichten stornieren: POST /messages, POST /messages/batch, DELETE /messages/{id} |
messages:read | Nachrichten und ihren Status lesen (GET /messages, GET /messages/{id}) und Webhook-Endpunkte verwalten |
reminders | Erinnerungen erstellen, auflisten, ändern, pausieren und löschen |
numbers | Nummern auflisten, ihre Verbindung sehen und WhatsApp-Nummern verbinden |
media | Dateien im Medienverzeichnis hochladen, auflisten und löschen |
contacts | Nummernprüfungen (Kontakt-Endpoints folgen später) |
GET /me braucht keinen bestimmten Scope. Für das Senden an einen gespeicherten Kontakt mit to.contact_id genügt messages:send.
Auf einige Nummern beschränkte Schlüssel#
Ein Schlüssel, der auf einige Nummern beschränkt ist, funktioniert nur mit diesen:
- Er sendet nur von diesen Nummern und listet, liest und storniert nur ihre Nachrichten. Eine andere Nummer in
fromerhältnumber_not_allowed. GET /numberslistet nur diese Nummern auf. Er kann sie neu verbinden, aber keine neue Nummer hinzufügen.- Er sieht und ändert nur die Erinnerungen, die von diesen Nummern senden, und eine neue Erinnerung muss eine davon als
fromangeben. - Webhook-Endpunkte kann er gar nicht verwalten, weil diese die Ereignisse des gesamten Arbeitsbereichs empfangen.
GET /me zeigt limited_to_numbers und die number_ids, die der Schlüssel nutzen darf.
Requests#
- JSON hin und zurück. Senden Sie Bodys als
Content-Type: application/json. Die einzige Ausnahme ist das Hochladen einer Datei, dasmultipart/form-dataverwendet. Jede Antwort ist JSON, auch Fehler. - Feldnamen sind
snake_case, und unbekannte Felder werden abgelehnt: Ein Tippfehler wietxtantwortet mitvalidation_failed, statt ignoriert zu werden. - Telefonnummern stehen im internationalen Format mit
+(E.164), zum Beispiel+919876543210. Leerzeichen und Bindestriche sind erlaubt; eine Nummer ohne+wird mitinvalid_phoneabgelehnt. - Zeiten sind ISO 8601 mit Offset, zum Beispiel
2026-10-20T09:30:00+05:30oder2026-10-20T04:00:00Z. Eine Zeit ohne Offset wird mitinvalid_datetimeabgelehnt. Zeiten in Antworten sind in UTC und enden aufZ, außernext_run_ateiner Erinnerung, das in der Zeitzone der Erinnerung angegeben ist. - IDs sind Ganzzahlen, etwa die
ideiner Nummer (frombeim Senden) oder dieideiner Nachricht. - Statuscodes bedeuten, was sie sagen:
200OK,201erstellt,202angenommen (in der Warteschlange),400der Request ist fehlerhaft,401der Schlüssel ist falsch,402keine Nachrichten mehr übrig,403nicht erlaubt,404nicht gefunden,409Konflikt,413zu groß,415falscher Content-Type,422ein Wert kann nicht verwendet werden,429zu viele Requests,5xxein Fehler auf unserer Seite.
Antworten enthalten Cache-Control: no-store.
Fehler#
Jeder Fehler hat dasselbe Format:
{
"error": {
"code": "invalid_phone",
"message": "This is not a valid phone number. Write it in international format with +, e.g. +919876543210.",
"field": "to.phone",
"docs": "https://wbiztool.com/docs/api/v2/errors/#invalid_phone",
"request_id": "req_4f1c2a9b8e7d6c5b4a392817"
}
}
codeist stabil: Verzweigen Sie in Ihrem Code danach.messageist englischer Text für Entwickler und kann sich ändern.fieldnennt das Feld, um das es im Fehler geht (to.phone,to[3].phone,schedule.cron), oder istnull.docsverlinkt den Code auf der Fehlerseite.request_idist derselbe Wert wie im HeaderX-Request-Id. Geben Sie ihn an, wenn Sie uns kontaktieren.- Manche Fehler enthalten zusätzliche Angaben, zum Beispiel
statusbeinot_cancellableoderusedundlimitbeistorage_full. Hat ein Request mehrere Probleme, listeterrorsdie übrigen auf, jeweils mitfieldundmessage.
Alle Codes, ihr HTTP-Status und was zu tun ist, stehen auf der Fehlerseite.
Idempotency-Key#
Nach einem Netzwerkfehler oder Timeout wissen Sie nicht, ob ein Request funktioniert hat. Senden Sie bei einem POST, der etwas erstellt, einen Header Idempotency-Key mit, dann können Sie ihn gefahrlos erneut senden:
curl -X POST https://wbiztool.com/api/v2/messages \
-H "Authorization: Bearer $WBIZTOOL_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042-ready" \
-d '{"to": {"phone": "+919876543210"}, "text": "Hi Asha, your order #1042 is ready."}'
- Den Wert bestimmen Sie: eine beliebige eindeutige Zeichenfolge aus 1 bis 255 druckbaren Zeichen, etwa eine UUID oder Ihre eigene Bestellnummer. Erzeugen Sie für jeden neuen Request einen neuen Wert und verwenden Sie ihn nur für eine Wiederholung desselben Requests erneut.
- Eine Wiederholung erhält die erste Antwort zurück, mit dem Header
Idempotent-Replayed: true. Nichts wird doppelt ausgeführt: keine zweite Nachricht, Erinnerung, Datei oder kein zweiter Endpunkt. - Keys gelten 24 Stunden ab dem ersten Request und gehören zu Ihrem API-Schlüssel: Ein anderer API-Schlüssel des Arbeitsbereichs kann denselben Wert ohne Konflikt verwenden.
- Gleicher Key, anderer Request: Ein Request mit einem Key, der bereits für eine andere Methode, einen anderen Pfad oder Body verwendet wurde, antwortet mit
422idempotency_key_reused. - Noch in Bearbeitung: Solange der erste Request mit dem Key noch bearbeitet wird, antwortet eine Wiederholung mit
409idempotency_in_progressundRetry-After: 1. Warten Sie einen Moment und senden Sie ihn erneut. - Fehler werden nicht gespeichert. Hat der erste Request mit einem Fehler geantwortet, wird nichts gespeichert: Korrigieren Sie den Request und senden Sie ihn mit demselben Key erneut.
- Secrets werden nicht wiederholt. Eine Wiederholung von
POST /webhookslässt dassecretdes Endpunkts weg, das nur in der ersten Antwort angezeigt wird.
Das funktioniert bei POST /messages, POST /messages/batch, POST /numbers, POST /reminders, POST /media, POST /number-checks und POST /webhooks und ist jeweils optional. Andere Requests ignorieren den Header. Ein leerer oder zu langer Wert antwortet mit 400 invalid_idempotency_key.
Rate-Limits#
Jeder Schlüssel kann 60 Requests pro Minute und 10.000 Requests pro Tag stellen. Das sind feste Zeitfenster: Das Minutenfenster beginnt mit der vollen Minute, das Tagesfenster um 00:00 UTC. Über einem Limit antwortet der Request mit 429 rate_limited.
Antworten auf Requests mit gültigem Schlüssel enthalten diese Header:
| Header | Bedeutung |
|---|---|
RateLimit-Limit | Im aktuellen Fenster erlaubte Requests (60, oder 10000, sobald das Tageslimit erreicht ist) |
RateLimit-Remaining | Verbleibende Requests in diesem Fenster |
RateLimit-Reset | Sekunden, bis dieses Fenster neu beginnt |
RateLimit-Policy | Beide Limits: 60;w=60, 10000;w=86400 |
Retry-After | Bei einem 429: Sekunden, die Sie vor dem nächsten Versuch warten sollten |
Unabhängig davon gilt:
- Falsche Schlüssel: Mehr als 30 Requests pro Minute mit einem falschen Schlüssel von einer IP-Adresse antworten mit
429too_many_auth_failuresundRetry-After: 60. - Nachrichten pro Nummer: Eine Nummer sendet höchstens 1.000 Nachrichten in 24 Stunden (Fair Use). Ein Senden darüber hinaus antwortet mit
429number_daily_cap_reached.
Seitenweise Abfrage#
Listen, die wachsen können (GET /messages, /reminders, /media, /number-checks und die /results einer Prüfung), kommen in Seiten, die neuesten zuerst:
{
"data": [ … ],
"next_cursor": "eyJpZCI6OTgxNzI2MywidCI6IjIwMjYtMTAtMThUMTA6MTU6MDIuMzExWiIsImYiOiI0NGIxMzZmYTM1NWIifQ"
}
limitlegt die Seitengröße fest, von 1 bis 100 (Standard 25).- Für die nächste Seite senden Sie denselben Request mit
cursor, gesetzt auf dennext_cursorder letzten Seite. Auf der letzten Seite istnext_cursornull. - Lassen Sie die übrigen Filter gleich: Ein Cursor mit anderen Filtern antwortet mit
400invalid_cursor. Beginnen Sie dann ohne Cursor neu. - Behandeln Sie den Cursor als undurchsichtige Zeichenfolge. Einträge, die während des Blätterns hinzukommen, verschieben die Seiten nicht.
curl "https://wbiztool.com/api/v2/messages?limit=100&cursor=eyJpZCI6OTgxNzI2MywidCI6..." \
-H "Authorization: Bearer $WBIZTOOL_API_KEY"
GET /numbers und GET /webhooks liefern alles in einer einzigen data-Liste.
Request-IDs#
Jede Antwort, auch jeder Fehler, hat einen Header X-Request-Id wie req_4f1c2a9b8e7d6c5b4a392817. Fehler enthalten denselben Wert als request_id. Protokollieren Sie ihn und geben Sie ihn an, wenn Sie uns kontaktieren: Damit finden wir den Request in unseren Logs, die die ID Ihres Schlüssels speichern, aber nie den Schlüssel selbst.
Wenn Sie eine eigene X-Request-Id senden (bis zu 100 druckbare Zeichen), kommt sie als X-Client-Request-Id zurück, sodass Sie Antworten Ihren eigenen Logs zuordnen können.
Testmodus#
Mit einem Testschlüssel (wbz_test_…) entwickeln und testen Sie eine Integration, ohne etwas zu senden. Erstellen Sie ihn unter Einstellungen → API-Schlüssel mit Art des Schlüssels: Test. GET /me zeigt "mode": "test".
Was ein Testschlüssel wie ein Live-Schlüssel tut:
POST /messagesundPOST /messages/batchprüfen alles, was auch ein echtes Senden prüft: den Empfänger, den Text, Medien,send_atundexpires_at, die sendende Nummer sowie die Scopes und Nummern des Schlüssels. Dieselben Fehler ergeben dieselben Fehlermeldungen.- Scopes, Nummern, Rate-Limits und
Idempotency-Keyfunktionieren genauso. - Jeder Lesezugriff auf den übrigen Arbeitsbereich (
GET /me,/numbers,/reminders,/media,/number-checks,/webhooks) zeigt die echten Daten, nur lesend.
Was anders ist:
- Nichts wird gesendet. Ein Testversand wird stattdessen als Testnachricht gespeichert und verbraucht weder die Nachrichten des Plans noch die täglichen 1.000 der Nummer. Er erhält also nie
no_creditsodernumber_daily_cap_reached. - Der Status ändert sich von selbst:
queued, dannsent5 Sekunden unddelivered15 Sekunden nach dem Erstellen (bei einer geplanten Nachricht absend_atgezählt). Eine Nachricht, derenexpires_atvor dem Senden liegt, wirdexpired. Testnachrichten werden niereadoderfailed. - Ein Testschlüssel sieht nur seine eigenen Testnachrichten.
GET /messagesundGET /messages/{id}zeigen diese und sonst nichts, undDELETE /messages/{id}storniert eine, solange siequeuedoderscheduledist. Live-Schlüssel sehen Testnachrichten nie. Der FilterstatusvonGET /messageswird für Testschlüssel nicht unterstützt und antwortet mittest_mode_unsupported;number,sinceunduntilfunktionieren. - Andere Schreibzugriffe werden abgelehnt, mit
403test_mode_unsupported: eine Nummer verbinden, Erinnerungen erstellen, ändern oder löschen, Medien hochladen oder löschen, eine Nummernprüfung starten sowie Webhook-Endpunkte hinzufügen, entfernen, rotieren oder testen. - Keine Webhook-Ereignisse werden für Testnachrichten gesendet.
- Testnachrichten werden 30 Tage aufbewahrt.
Ressourcen#
- Nachrichten: jetzt oder später senden, an bis zu 1.000 Empfänger senden, den Verlauf lesen, stornieren.
- Nummern: Ihre WhatsApp-Nummern und Telegram-Konten auflisten und eine WhatsApp-Nummer per QR-Code oder Kopplungscode verbinden.
- Erinnerungen: wiederkehrende Nachrichten nach einem Cron-Zeitplan.
- Medien: Dateien einmal hochladen und per
media_idsenden. - Nummernprüfungen: herausfinden, welche Nummern WhatsApp nutzen.
- Webhooks: signierte Ereignisse, wenn eine Nachricht gesendet wird, fehlschlägt, storniert wird oder abläuft.
- Fehler: alle Fehlercodes.
- Von v1 zu v2 wechseln: jeder v1-Endpoint und jedes v1-Feld mit seiner Entsprechung in v2.
