Programmatischer Zugriff auf virtuelle Nummern, Bestellungen und Kontoguthaben.
Empfohlen
⟩Mit den offiziellen SDKs starten
Nutzen Sie das TypeScript/JavaScript- oder Python-SDK für neue Integrationen. Beide SDKs verwenden standardmäßig die öffentliche /v2-API, bewahren Idempotency-Keys bei sicheren Wiederholungen, liefern typisierte Fehler und halten den OTP-Lebenszyklus konsistent.
Erstelle eine Bestellung mit product_id für einen exakten stabilen Preisstufen-Slot oder mit catalog_product_id, optionaler operator_id, min_price/max_price und einem Idempotency-Key für wiederholsichere geroutete bezahlte Aufrufe.
catalog_product_idmax_priceIdempotency-Key
02
OTP verwenden
Warten Sie auf das OTP, geben Sie es in Ihrer Ziel-App ein und rufen Sie dann finish auf, um die Bestellung zu schließen.
waitForOtpwait_for_otpfinish
03
Nur bei Bedarf erneut senden
Warten Sie nach einem Resend mit afterCode in TypeScript oder after_code in Python auf einen neuen Code.
can_resendresend_available_at
import { SmscodeClient, OtpTimeoutError } from "@smscode/sdk";const client = new SmscodeClient({ token: process.env.SMSCODE_TOKEN! });let orderId: number | undefined;try { const created = await client.orders.create({ catalog_product_id: Number(process.env.SMSCODE_CATALOG_PRODUCT_ID), max_price: "0.50", quantity: 1, }); const order = created.orders[0]!; orderId = order.id; const first = await client.orders.waitForOtp(orderId, { timeoutMs: 120_000 }); console.log(first.otpCode); // Diesen Code in der Ziel-App eingeben. await client.orders.finish(orderId);} catch (err) { if (err instanceof OtpTimeoutError && orderId !== undefined) { const current = await client.orders.get(orderId); if (current.can_cancel) await client.orders.cancel(orderId); } throw err;}
import osfrom smscode import OtpTimeoutError, SmscodeClientwith SmscodeClient(token=os.environ["SMSCODE_TOKEN"]) as client: created = client.orders.create( catalog_product_id=int(os.environ["SMSCODE_CATALOG_PRODUCT_ID"]), max_price="0.50", quantity=1, ) order = created.orders[0] order_id = int(order["id"]) try: first = client.orders.wait_for_otp(order_id, timeout_ms=120_000) print(first.otp_code) # Diesen Code in der Ziel-App eingeben. client.orders.finish(order_id) except OtpTimeoutError: current = client.orders.get(order_id) if current["can_cancel"]: client.orders.cancel(order_id) raise
Verwenden Sie can_resend und resend_available_at für das Resend-Timing. Niedrigere Resend-Zeitstempel sind intern und keine öffentlichen Antwortfelder.
⟩Ueberblick
Alle Geldfelder der /v1-API sind in IDR (indonesische Rupiah), als ganzzahlige Einheiten — zum Beispiel bedeuten "price": 15000 und "balance": 500000 Rp 15.000 und Rp 500.000. Für eine USD-native Projektion desselben Ledgers wechseln Sie über den Versionsschalter oben zur v2-API.
⟩Authentifizierung
Alle API-Anfragen erfordern einen Bearer-Token. Generieren Sie einen in den Kontoeinstellungen im Dashboard und fügen Sie ihn jeder Anfrage hinzu:
Authorization:Bearer YOUR_API_TOKEN
Anfragen ohne gültigen Token erhalten eine 401 UNAUTHORIZED-Antwort.
⟩Basis-URL
Alle nachfolgenden Endpunkt-Pfade sind relativ zu:
https://api.smscode.gg/v1
⟩Antwortformat
Jede Antwort gibt JSON mit einer konsistenten Umschlagsstruktur zurück. Alle Antworten enthalten einen x-request-id-Header für Debugging.
Alle Geldfelder der /v1-API sind in IDR (indonesische Rupiah), als ganzzahlige Einheiten — zum Beispiel bedeuten "price": 15000 und "balance": 500000 Rp 15.000 und Rp 500.000. Für eine USD-native Projektion desselben Ledgers wechseln Sie über den Versionsschalter oben zur v2-API.
Gibt die auswählbaren Betreiber für ein Land + einen Service zurück. Wenn sowohl echte Betreiber als auch Any-Bestand verfügbar sind, enthält die Antwort eine Any-Zeile mit operator_id null; wenn es keine betreiberspezifischen Produkte gibt, ist die Liste leer.
Gibt eine Liste der Bestellungen des authentifizierten Nutzers zurück, sortiert nach Aktualität. Unterstützt Filterung nach Status und Paginierung per Offset.
Query-Parameter
Name
Typ
Erforderlich
Beschreibung
limit
integer
Nein
Max. Ergebnisse (1–100, Standard 20)
offset
integer
Nein
Anzahl der zu überspringenden Ergebnisse (Standard 0)
status
string
Nein
Nach Status filtern: ACTIVE, OTP_RECEIVED, COMPLETED, CANCELED, EXPIRED (Groß-/Kleinschreibung egal)
Erstellt eine neue Bestellung für eine virtuelle Nummer. Guthaben wird automatisch abgebucht. Unterstützt einen optionalen Idempotency-Key-Header, um doppelte Bestellungen bei Netzwerk-Wiederholungen zu verhindern.
Anfragekörper
Name
Typ
Erforderlich
Beschreibung
product_id
integer
Nein
Stabile Produkt-ID für einen exakten Preisstufen-Slot zur direkten Bestellung. Gib ENTWEDER diese ID ODER catalog_product_id an, nicht beides.
catalog_product_id
integer
Nein
Geroutete Umbrella-ID für Land+Plattform. Der Server wählt eine aktuell passende Preisstufe. Gib entweder diese ID oder product_id an.
operator_id
integer
Nein
Optionale Betreiber-ID aus /catalog/operators. Nur mit catalog_product_id gültig; für Any weglassen.
min_price
integer
Nein
Optionale Preisuntergrenze. IDR-Ganzzahl. Nur mit catalog_product_id gültig.
max_price
integer
Nein
Optionale Preisobergrenze. IDR-Ganzzahl. Nur mit catalog_product_id gültig.
prefer_provider
string
Nein
Optionaler Anbietercode, der bei gleichwertigen Angeboten bevorzugt wird.
policy
string
Nein
Optionale Routing-Strategie, nur zusammen mit catalog_product_id gültig. Werte: cheapest (Standard) wählt das günstigste funktionierende Angebot; best_success sortiert Angebote zuerst nach dem jüngsten Zustellerfolg. best_success bewertet jeden Anbieter anhand des Anteils der Bestellungen, die in den letzten 30 abgeschlossenen Tagen ein OTP erhalten haben, in 10%-Stufen, und zählt einen Anbieter erst ab mindestens 20 Bestellungen in diesem Zeitraum — Anbieter unterhalb dieser Schwelle oder ohne Historie gelten als neutral, sodass neue Angebote nie benachteiligt werden (opt-in; das Signal startet neutral). Ist zusätzlich prefer_provider gesetzt, steht der bevorzugte Anbieter weiterhin an erster Stelle.
quantity
integer
Nein
Anzahl (1–100, Standard 1)
Übergeben Sie einen Idempotency-Key-Header, um Anfragen sicher zu wiederholen, ohne doppelte Bestellungen zu erstellen. Der Schlüssel darf Buchstaben, Ziffern, Bindestrich und Unterstrich enthalten (A-Z a-z 0-9 _ -), maximal 128 Zeichen; ein ungültiger Schlüssel wird mit 422 VALIDATION_ERROR abgelehnt. Eine Wiederholung mit demselben Schlüssel und demselben Body gibt das ursprüngliche Ergebnis erneut zurück (einschließlich des failed_count bei einem Teilerfolg). Eine Wiederholung, die den Anbieter erreicht, aber fehlschlägt, wird gespeichert und gibt bei erneutem Versuch denselben Fehler zurück — verwenden Sie einen NEUEN Schlüssel für einen weiteren Versuch. Fehler ohne Seiteneffekte (unzureichendes Guthaben, kein verfügbares Angebot) geben den Schlüssel frei, sodass Sie Guthaben aufladen und mit demselben Schlüssel erneut versuchen können. Die Wiederverwendung eines Schlüssels mit einem anderen Body gibt 422 IDEMPOTENCY_KEY_REUSED zurück, und eine noch laufende Anfrage mit diesem Schlüssel gibt 409 REQUEST_IN_PROGRESS zurück. Das Feld failed_reason ist in create-Antworten immer null — es wird nur beim Abfragen/Auflisten von Bestellungen befüllt.
Beispielanfrage
curl -s -X POST https://api.smscode.gg/v1/orders/create \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: unique-request-id-123" \ -d '{"product_id":142,"quantity":1}'# Or route by catalog_product_id — the server picks a current tier.# product_id is the stable exact tier-slot id. catalog_product_id is the# country+platform umbrella for routed ordering. Optional min_price/max_price# bound the tier; operator_id scopes to a carrier from /catalog/operators.# Pass EITHER product_id OR catalog_product_id.curl -s -X POST https://api.smscode.gg/v1/orders/create \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: unique-request-id-124" \ -d '{"catalog_product_id":87,"min_price":12000,"max_price":20000,"operator_id":433}'
Fordert die Plattform auf, die SMS erneut an die gemietete Nummer zu senden. Nicht alle Plattformen unterstützen den erneuten Versand — prüfen Sie das Feld "resent" in der Antwort.
Reaktiviert eine abgeschlossene Nummer — bestellt dieselbe Nummer erneut für einen weiteren Verifizierungscode, ohne eine neue Nummer zu mieten. Nur eine abgeschlossene Bestellung, deren Nummer Reaktivierung unterstützt, kommt infrage (prüfen Sie can_reactivate an der Bestellung oder rufen Sie über reactivate-options eine Vorschau ab). Die reaktivierte Kind-Bestellung ist eine NEUE Bestellung, die im selben Format wie bei create zurückgegeben wird; das Guthaben wird automatisch abgebucht.
Anfragekörper
Name
Typ
Erforderlich
Beschreibung
id
integer
Ja
Die abgeschlossene Bestellung, die reaktiviert werden soll.
max_price
integer
Nein
Optionale Kostenobergrenze. IDR-Ganzzahl. Die Reaktivierung wird mit 422 VALIDATION_ERROR abgelehnt, wenn die aktuellen Kosten diese überschreiten.
Wie create ist dies eine geldwirksame Änderung — übergeben Sie einen Idempotency-Key-Header für sichere Wiederholungen (ein create und ein reactivate können bei ein und demselben Schlüssel niemals kollidieren). Die Wiederverwendung eines Schlüssels mit einem anderen Body gibt 422 IDEMPOTENCY_KEY_REUSED zurück, und eine noch nicht abgeschlossene Anfrage mit diesem Schlüssel gibt 409 REQUEST_IN_PROGRESS zurück. Eine Nummer, die nicht reaktiviert werden kann, gibt 409 CONFLICT zurück; ein zu geringes Guthaben gibt 409 INSUFFICIENT_BALANCE zurück.
Zeigt eine Vorschau, was eine Reaktivierung aktuell kosten würde. Nur lesend — verbraucht keinen Idempotency-Key und erstellt nichts. Gibt die Kosten als IDR-Ganzzahl zurück. Nur für eine abgeschlossene Bestellung verfügbar, deren Nummer Reaktivierung unterstützt.
Pfad-Parameter
Name
Typ
Erforderlich
Beschreibung
id
integer
Ja
Bestell-ID, für die die Reaktivierungskosten in der Vorschau angezeigt werden sollen (Pfadparameter).
Aktualisiert Ihre Webhook-URL und/oder Ihr Secret. Ein Secret wird automatisch generiert, wenn Sie zum ersten Mal eine URL festlegen. Senden Sie einen leeren String zum Löschen. Die URL muss HTTPS verwenden.
Anfragekörper
Name
Typ
Erforderlich
Beschreibung
webhook_url
string
Nein
HTTPS-URL für den Empfang von Webhook-Ereignissen (leerer String zum Löschen)
webhook_secret
string
Nein
Gemeinsames Secret für HMAC-SHA256-Signatur (wird beim ersten Setzen automatisch generiert, falls nicht angegeben)
Sendet ein Testereignis an Ihre konfigurierte Webhook-URL. Gibt den HTTP-Statuscode Ihres Servers zurück. Nützlich zur Überprüfung, ob Ihr Endpunkt funktioniert, bevor Sie live gehen.
Parameter
Keine
Beispielanfrage
curl -s -X POST https://api.smscode.gg/v1/webhook/test \ -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/webhook/test", { method: "POST", headers: { Authorization: "Bearer YOUR_API_TOKEN" },});const data = await res.json();
Konfigurieren Sie eine Webhook-URL, um Echtzeit-Push-Benachrichtigungen für Bestellereignisse zu erhalten, anstatt zu pollen. Dies ist der empfohlene Ansatz für Bot-Skripte.
Ereignisse
Ereignis
Auslöser
order.otp_received
Neue SMS zugestellt; der erkannte Code kann null sein
order.completed
Bestellung als abgeschlossen markiert (manuell oder durch Ablauf)
order.expired
Bestellung vor dem Empfang einer SMS abgelaufen (Guthaben erstattet)
order.canceled
Bestellung vom Nutzer storniert (Guthaben erstattet)
Jede neue SMS löst dieses Ereignis aus. otp_code kann null sein, während otp_message vorhanden ist. Mehrere SMS-Ereignisse können in anderer Reihenfolge eintreffen; verwende sms_revision, um ein älteres Aggregatpaar zu ignorieren.
Jede Webhook-Anfrage enthält einen X-Webhook-Signature-Header mit einer HMAC-SHA256-Signatur des Anfragekörpers, wobei Ihr webhook_secret als Schlüssel verwendet wird:
Verifizieren Sie diese Signatur auf Ihrem Server, um die Authentizität der Anfrage sicherzustellen. Die Zustellung erfolgt nach dem Fire-and-Forget-Prinzip mit einem 3-Sekunden-Timeout und ohne Wiederholungsversuche.
⟩Ratenlimits
API-Anfragen sind pro Endpunkt-Gruppe ratenlimitiert. Bei Überschreitung des Limits wird 429 Too Many Requests mit einem Retry-After-Header zurückgegeben, der angibt, wie viele Sekunden gewartet werden soll.
Endpunkt-Gruppe
Limit
Zeitfenster
Katalog (Länder, Dienste, Produkte, Wechselkurs)
5.000 Anfragen
60 Sekunden
Guthaben
600 Anfragen
60 Sekunden
Bestellabfragen (Liste, Einzeln, Aktiv)
5.000 Anfragen
60 Sekunden
Bestellung erstellen
3.000 Anfragen
60 Sekunden
Bestellung stornieren
1.000 Anfragen
60 Sekunden
Bestellaktionen (Abschließen, Erneut senden)
1.000 Anfragen
60 Sekunden
Webhook-Konfiguration (Abrufen, Aktualisieren)
600 Anfragen
60 Sekunden
Webhook-Test
10 Anfragen
60 Sekunden
⟩Fehlercodes
Fehlerantworten enthalten einen der folgenden Codes in error.code:
Code
HTTP
Beschreibung
UNAUTHORIZED
401
Fehlender oder ungültiger API-Token
FORBIDDEN
403
Zugriff verweigert
NOT_FOUND
404
Ressource nicht gefunden (Bestellung, Wechselkurs usw.)
CONFLICT
409
Doppelte Anfrage oder Ressourcenkonflikt
INSUFFICIENT_BALANCE
409
Unzureichendes Guthaben für die Bestellung
VALIDATION_ERROR
422
Anfrageparameter haben die Validierung nicht bestanden
RATE_LIMIT_EXCEEDED
429
Zu viele Anfragen (prüfen Sie den Retry-After-Header)
INTERNAL_ERROR
500
Interner Serverfehler
PROVIDER_ERROR
422
Vorgelagerter SMS-Anbieter hat die Anfrage abgelehnt. Bei fehlgeschlagener Bestellerstellung kann der Fehler details enthalten: cause_counts (Bestellungen mit altem product_id — eine nach Ursache gruppierte Zählung) oder attempts (Bestellungen mit catalog_product_id — Ergebnisse pro Versuch), mit den Werten ok, no_numbers, insufficient_balance, price_rejected, provider_unavailable, provider_account_balance, provider_error.
NO_OFFER_AVAILABLE
422
Kein aktives Angebot passt zum angeforderten Produkt und zur Richtlinie (Preisobergrenze, Verfügbarkeit).
CANCEL_TOO_EARLY
409
Bestellung zu neu zum Stornieren — warten Sie 2 Minuten
REQUEST_IN_PROGRESS
409
Eine Erstellungsanfrage mit diesem Idempotenzschlüssel läuft noch
IDEMPOTENCY_KEY_REUSED
422
Dieser Idempotenzschlüssel wurde bereits mit einem anderen Anfrage-Body verwendet
SERVICE_UNAVAILABLE
503
Dienst vorübergehend nicht verfügbar (Wartung)
⟩Ueberblick
Alle Geldfelder der /v2-API sind in USD und werden als Geldobjekt zurückgegeben — { "amount": "0.92", "currency": "USD", "canonical_amount": 15000, "canonical_currency": "IDR" }. amount ist ein dezimaler String; canonical_amount ist der exakte IDR-Ledgerwert (verwenden Sie ihn zur Abstimmung). Der angewandte USD/IDR-rate wird einmal pro Antwort in meta.fx offengelegt. v2 ist eine USD-Projektion zur Renderzeit über demselben IDR-Ledger wie v1 — sie speichert oder verbucht niemals USD.
Alle Geldfelder der /v2-API sind in USD und werden als Geldobjekt zurückgegeben — { "amount": "0.92", "currency": "USD", "canonical_amount": 15000, "canonical_currency": "IDR" }. amount ist ein dezimaler String; canonical_amount ist der exakte IDR-Ledgerwert (verwenden Sie ihn zur Abstimmung). Der angewandte USD/IDR-rate wird einmal pro Antwort in meta.fx offengelegt. v2 ist eine USD-Projektion zur Renderzeit über demselben IDR-Ledger wie v1 — sie speichert oder verbucht niemals USD.
Identisch mit v1 — nur der Basispfad ändert sich (/v1 → /v2).
GET/catalog/operators
Gibt die auswählbaren Betreiber für ein Land + einen Service zurück. Wenn sowohl echte Betreiber als auch Any-Bestand verfügbar sind, enthält die Antwort eine Any-Zeile mit operator_id null; wenn es keine betreiberspezifischen Produkte gibt, ist die Liste leer.
v2: Geldfelder sind USD-Geldobjekte, und die Antwort enthält ein einzelnes meta.fx { pair, rate, rate_as_of }. rate ist die ganzzahlige IDR-Menge pro 1 USD, also USD = canonical_amount / rate. Summen verwenden 2 Dezimalstellen; Einzelpreise/Erstattungen verwenden 4. Ein streng positiver Betrag wird niemals auf 0.00 gerundet. rate_as_of ist der RFC3339-Zeitstempel des Kurses (Form +00:00) oder null, wenn kein Zeitstempel erfasst ist.
Nur v2: Existiert kein verwendbarer USD/IDR-Kurs, geben Geld-Endpoints 503 FX_RATE_UNAVAILABLE mit einem Retry-After-Header statt eines Geld-Bodys zurück. v1 gibt dies niemals zurück.
GET/catalog/exchange-rate
Gibt den aktuellen USD/IDR-Wechselkurs zurück, der für die Währungsumrechnung verwendet wird.
Parameter
Keine — v2 gibt immer USD/IDR zurück; der ?pair-Parameter von v1 wird ignoriert.
v2: gibt { pair, rate, rate_as_of } zurück (kein base_currency/quote_currency, kein meta-Wrapper — der Kurs ist die Daten). ?pair wird ignoriert — v2 gibt immer USD/IDR zurück (v1 berücksichtigt ?pair). Gibt 503 FX_RATE_UNAVAILABLE zurück, wenn kein verwendbarer Kurs existiert.
GET/balance
Gibt das Kontoguthaben des authentifizierten Nutzers zurück.
v2: Geldfelder sind USD-Geldobjekte, und die Antwort enthält ein einzelnes meta.fx { pair, rate, rate_as_of }. rate ist die ganzzahlige IDR-Menge pro 1 USD, also USD = canonical_amount / rate. Summen verwenden 2 Dezimalstellen; Einzelpreise/Erstattungen verwenden 4. Ein streng positiver Betrag wird niemals auf 0.00 gerundet. rate_as_of ist der RFC3339-Zeitstempel des Kurses (Form +00:00) oder null, wenn kein Zeitstempel erfasst ist.
Nur v2: Existiert kein verwendbarer USD/IDR-Kurs, geben Geld-Endpoints 503 FX_RATE_UNAVAILABLE mit einem Retry-After-Header statt eines Geld-Bodys zurück. v1 gibt dies niemals zurück.
GET/orders
Gibt eine Liste der Bestellungen des authentifizierten Nutzers zurück, sortiert nach Aktualität. Unterstützt Filterung nach Status und Paginierung per Offset.
Query-Parameter
Name
Typ
Erforderlich
Beschreibung
limit
integer
Nein
Max. Ergebnisse (1–100, Standard 20)
offset
integer
Nein
Anzahl der zu überspringenden Ergebnisse (Standard 0)
status
string
Nein
Nach Status filtern: ACTIVE, OTP_RECEIVED, COMPLETED, CANCELED, EXPIRED (Groß-/Kleinschreibung egal)
v2: Geldfelder sind USD-Geldobjekte, und die Antwort enthält ein einzelnes meta.fx { pair, rate, rate_as_of }. rate ist die ganzzahlige IDR-Menge pro 1 USD, also USD = canonical_amount / rate. Summen verwenden 2 Dezimalstellen; Einzelpreise/Erstattungen verwenden 4. Ein streng positiver Betrag wird niemals auf 0.00 gerundet. rate_as_of ist der RFC3339-Zeitstempel des Kurses (Form +00:00) oder null, wenn kein Zeitstempel erfasst ist.
Nur v2: Existiert kein verwendbarer USD/IDR-Kurs, geben Geld-Endpoints 503 FX_RATE_UNAVAILABLE mit einem Retry-After-Header statt eines Geld-Bodys zurück. v1 gibt dies niemals zurück.
GET/orders/{id}
Gibt eine einzelne Bestellung nach ID zurück. Gibt nur Bestellungen des authentifizierten Nutzers zurück.
v2: Geldfelder sind USD-Geldobjekte, und die Antwort enthält ein einzelnes meta.fx { pair, rate, rate_as_of }. rate ist die ganzzahlige IDR-Menge pro 1 USD, also USD = canonical_amount / rate. Summen verwenden 2 Dezimalstellen; Einzelpreise/Erstattungen verwenden 4. Ein streng positiver Betrag wird niemals auf 0.00 gerundet. rate_as_of ist der RFC3339-Zeitstempel des Kurses (Form +00:00) oder null, wenn kein Zeitstempel erfasst ist.
Nur v2: Existiert kein verwendbarer USD/IDR-Kurs, geben Geld-Endpoints 503 FX_RATE_UNAVAILABLE mit einem Retry-After-Header statt eines Geld-Bodys zurück. v1 gibt dies niemals zurück.
GET/orders/active
Listet alle aktuell aktiven Bestellungen auf (ACTIVE + OTP_RECEIVED). Verwenden Sie dies, um den OTP-Status abzufragen.
v2: Dieser Endpoint ist nicht geldführend — er gibt weder amount noch meta.fx zurück (dieselbe Struktur wie v1, unter /v2).
POST/orders/create
Erstellt eine neue Bestellung für eine virtuelle Nummer. Guthaben wird automatisch abgebucht. Unterstützt einen optionalen Idempotency-Key-Header, um doppelte Bestellungen bei Netzwerk-Wiederholungen zu verhindern.
Anfragekörper
Name
Typ
Erforderlich
Beschreibung
product_id
integer
Nein
Stabile Produkt-ID für einen exakten Preisstufen-Slot zur direkten Bestellung. Gib ENTWEDER diese ID ODER catalog_product_id an, nicht beides.
catalog_product_id
integer
Nein
Geroutete Umbrella-ID für Land+Plattform. Der Server wählt eine aktuell passende Preisstufe. Gib entweder diese ID oder product_id an.
operator_id
integer
Nein
Optionale Betreiber-ID aus /catalog/operators. Nur mit catalog_product_id gültig; für Any weglassen.
min_price
string
Nein
Optionale Preisuntergrenze. USD-Dezimalstring (z. B. "0.30"). Nur mit catalog_product_id gültig.
max_price
string
Nein
Optionale Preisobergrenze. USD-Dezimalstring (z. B. "0.50"). Nur mit catalog_product_id gültig.
prefer_provider
string
Nein
Optionaler Anbietercode, der bei gleichwertigen Angeboten bevorzugt wird.
policy
string
Nein
Optionale Routing-Strategie, nur zusammen mit catalog_product_id gültig. Werte: cheapest (Standard) wählt das günstigste funktionierende Angebot; best_success sortiert Angebote zuerst nach dem jüngsten Zustellerfolg. best_success bewertet jeden Anbieter anhand des Anteils der Bestellungen, die in den letzten 30 abgeschlossenen Tagen ein OTP erhalten haben, in 10%-Stufen, und zählt einen Anbieter erst ab mindestens 20 Bestellungen in diesem Zeitraum — Anbieter unterhalb dieser Schwelle oder ohne Historie gelten als neutral, sodass neue Angebote nie benachteiligt werden (opt-in; das Signal startet neutral). Ist zusätzlich prefer_provider gesetzt, steht der bevorzugte Anbieter weiterhin an erster Stelle.
quantity
integer
Nein
Anzahl (1–100, Standard 1)
Übergeben Sie einen Idempotency-Key-Header, um Anfragen sicher zu wiederholen, ohne doppelte Bestellungen zu erstellen. Der Schlüssel darf Buchstaben, Ziffern, Bindestrich und Unterstrich enthalten (A-Z a-z 0-9 _ -), maximal 128 Zeichen; ein ungültiger Schlüssel wird mit 422 VALIDATION_ERROR abgelehnt. Eine Wiederholung mit demselben Schlüssel und demselben Body gibt das ursprüngliche Ergebnis erneut zurück (einschließlich des failed_count bei einem Teilerfolg). Eine Wiederholung, die den Anbieter erreicht, aber fehlschlägt, wird gespeichert und gibt bei erneutem Versuch denselben Fehler zurück — verwenden Sie einen NEUEN Schlüssel für einen weiteren Versuch. Fehler ohne Seiteneffekte (unzureichendes Guthaben, kein verfügbares Angebot) geben den Schlüssel frei, sodass Sie Guthaben aufladen und mit demselben Schlüssel erneut versuchen können. Die Wiederverwendung eines Schlüssels mit einem anderen Body gibt 422 IDEMPOTENCY_KEY_REUSED zurück, und eine noch laufende Anfrage mit diesem Schlüssel gibt 409 REQUEST_IN_PROGRESS zurück. Das Feld failed_reason ist in create-Antworten immer null — es wird nur beim Abfragen/Auflisten von Bestellungen befüllt.
v2: Geldfelder sind USD-Geldobjekte, und die Antwort enthält ein einzelnes meta.fx { pair, rate, rate_as_of }. rate ist die ganzzahlige IDR-Menge pro 1 USD, also USD = canonical_amount / rate. Summen verwenden 2 Dezimalstellen; Einzelpreise/Erstattungen verwenden 4. Ein streng positiver Betrag wird niemals auf 0.00 gerundet. rate_as_of ist der RFC3339-Zeitstempel des Kurses (Form +00:00) oder null, wenn kein Zeitstempel erfasst ist.
Nur v2: Existiert kein verwendbarer USD/IDR-Kurs, geben Geld-Endpoints 503 FX_RATE_UNAVAILABLE mit einem Retry-After-Header statt eines Geld-Bodys zurück. v1 gibt dies niemals zurück.
POST/orders/cancel
Storniert eine aktive Bestellung. Die Mietkosten werden Ihrem Guthaben gutgeschrieben.
v2: Geldfelder sind USD-Geldobjekte, und die Antwort enthält ein einzelnes meta.fx { pair, rate, rate_as_of }. rate ist die ganzzahlige IDR-Menge pro 1 USD, also USD = canonical_amount / rate. Summen verwenden 2 Dezimalstellen; Einzelpreise/Erstattungen verwenden 4. Ein streng positiver Betrag wird niemals auf 0.00 gerundet. rate_as_of ist der RFC3339-Zeitstempel des Kurses (Form +00:00) oder null, wenn kein Zeitstempel erfasst ist.
Nur v2: Existiert kein verwendbarer USD/IDR-Kurs, geben Geld-Endpoints 503 FX_RATE_UNAVAILABLE mit einem Retry-After-Header statt eines Geld-Bodys zurück. v1 gibt dies niemals zurück.
POST/orders/finish
Markiert eine Bestellung als abgeschlossen, nachdem der OTP empfangen wurde. Die Nummer wird sofort freigegeben, anstatt auf den Ablauf zu warten.
Identisch mit v1 — nur der Basispfad ändert sich (/v1 → /v2).
POST/orders/resend
Fordert die Plattform auf, die SMS erneut an die gemietete Nummer zu senden. Nicht alle Plattformen unterstützen den erneuten Versand — prüfen Sie das Feld "resent" in der Antwort.
Identisch mit v1 — nur der Basispfad ändert sich (/v1 → /v2).
POST/orders/reactivate
Reaktiviert eine abgeschlossene Nummer — bestellt dieselbe Nummer erneut für einen weiteren Verifizierungscode, ohne eine neue Nummer zu mieten. Nur eine abgeschlossene Bestellung, deren Nummer Reaktivierung unterstützt, kommt infrage (prüfen Sie can_reactivate an der Bestellung oder rufen Sie über reactivate-options eine Vorschau ab). Die reaktivierte Kind-Bestellung ist eine NEUE Bestellung, die im selben Format wie bei create zurückgegeben wird; das Guthaben wird automatisch abgebucht.
Anfragekörper
Name
Typ
Erforderlich
Beschreibung
id
integer
Ja
Die abgeschlossene Bestellung, die reaktiviert werden soll.
max_price
string
Nein
Optionale Kostenobergrenze. USD-Dezimalstring (z. B. "0.50"). Die Reaktivierung wird mit 422 VALIDATION_ERROR abgelehnt, wenn die aktuellen Kosten diese überschreiten.
Wie create ist dies eine geldwirksame Änderung — übergeben Sie einen Idempotency-Key-Header für sichere Wiederholungen (ein create und ein reactivate können bei ein und demselben Schlüssel niemals kollidieren). Die Wiederverwendung eines Schlüssels mit einem anderen Body gibt 422 IDEMPOTENCY_KEY_REUSED zurück, und eine noch nicht abgeschlossene Anfrage mit diesem Schlüssel gibt 409 REQUEST_IN_PROGRESS zurück. Eine Nummer, die nicht reaktiviert werden kann, gibt 409 CONFLICT zurück; ein zu geringes Guthaben gibt 409 INSUFFICIENT_BALANCE zurück.
v2: Geldfelder sind USD-Geldobjekte, und die Antwort enthält ein einzelnes meta.fx { pair, rate, rate_as_of }. rate ist die ganzzahlige IDR-Menge pro 1 USD, also USD = canonical_amount / rate. Summen verwenden 2 Dezimalstellen; Einzelpreise/Erstattungen verwenden 4. Ein streng positiver Betrag wird niemals auf 0.00 gerundet. rate_as_of ist der RFC3339-Zeitstempel des Kurses (Form +00:00) oder null, wenn kein Zeitstempel erfasst ist.
Nur v2: Existiert kein verwendbarer USD/IDR-Kurs, geben Geld-Endpoints 503 FX_RATE_UNAVAILABLE mit einem Retry-After-Header statt eines Geld-Bodys zurück. v1 gibt dies niemals zurück.
GET/orders/{id}/reactivate-options
Zeigt eine Vorschau, was eine Reaktivierung aktuell kosten würde. Nur lesend — verbraucht keinen Idempotency-Key und erstellt nichts. Gibt die Kosten als USD-Geldobjekt mit einem FX-Beleg zurück. Nur für eine abgeschlossene Bestellung verfügbar, deren Nummer Reaktivierung unterstützt.
Pfad-Parameter
Name
Typ
Erforderlich
Beschreibung
id
integer
Ja
Bestell-ID, für die die Reaktivierungskosten in der Vorschau angezeigt werden sollen (Pfadparameter).
v2: Geldfelder sind USD-Geldobjekte, und die Antwort enthält ein einzelnes meta.fx { pair, rate, rate_as_of }. rate ist die ganzzahlige IDR-Menge pro 1 USD, also USD = canonical_amount / rate. Summen verwenden 2 Dezimalstellen; Einzelpreise/Erstattungen verwenden 4. Ein streng positiver Betrag wird niemals auf 0.00 gerundet. rate_as_of ist der RFC3339-Zeitstempel des Kurses (Form +00:00) oder null, wenn kein Zeitstempel erfasst ist.
Nur v2: Existiert kein verwendbarer USD/IDR-Kurs, geben Geld-Endpoints 503 FX_RATE_UNAVAILABLE mit einem Retry-After-Header statt eines Geld-Bodys zurück. v1 gibt dies niemals zurück.
GET/webhook
Gibt Ihre aktuelle Webhook-Benachrichtigungskonfiguration zurück.
Identisch mit v1 — nur der Basispfad ändert sich (/v1 → /v2).
PATCH/webhook
Aktualisiert Ihre Webhook-URL und/oder Ihr Secret. Ein Secret wird automatisch generiert, wenn Sie zum ersten Mal eine URL festlegen. Senden Sie einen leeren String zum Löschen. Die URL muss HTTPS verwenden.
Anfragekörper
Name
Typ
Erforderlich
Beschreibung
webhook_url
string
Nein
HTTPS-URL für den Empfang von Webhook-Ereignissen (leerer String zum Löschen)
webhook_secret
string
Nein
Gemeinsames Secret für HMAC-SHA256-Signatur (wird beim ersten Setzen automatisch generiert, falls nicht angegeben)
Identisch mit v1 — nur der Basispfad ändert sich (/v1 → /v2).
POST/webhook/test
Sendet ein Testereignis an Ihre konfigurierte Webhook-URL. Gibt den HTTP-Statuscode Ihres Servers zurück. Nützlich zur Überprüfung, ob Ihr Endpunkt funktioniert, bevor Sie live gehen.
Parameter
Keine
Beispielanfrage
curl -s -X POST https://api.smscode.gg/v2/webhook/test \ -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v2/webhook/test", { method: "POST", headers: { Authorization: "Bearer YOUR_API_TOKEN" },});const data = await res.json();
Identisch mit v1 — nur der Basispfad ändert sich (/v1 → /v2).
⟩Webhook-Benachrichtigungen
Konfigurieren Sie eine Webhook-URL, um Echtzeit-Push-Benachrichtigungen für Bestellereignisse zu erhalten, anstatt zu pollen. Dies ist der empfohlene Ansatz für Bot-Skripte.
Ereignisse
Ereignis
Auslöser
order.otp_received
Neue SMS zugestellt; der erkannte Code kann null sein
order.completed
Bestellung als abgeschlossen markiert (manuell oder durch Ablauf)
order.expired
Bestellung vor dem Empfang einer SMS abgelaufen (Guthaben erstattet)
order.canceled
Bestellung vom Nutzer storniert (Guthaben erstattet)
Jede neue SMS löst dieses Ereignis aus. otp_code kann null sein, während otp_message vorhanden ist. Mehrere SMS-Ereignisse können in anderer Reihenfolge eintreffen; verwende sms_revision, um ein älteres Aggregatpaar zu ignorieren.
Jede Webhook-Anfrage enthält einen X-Webhook-Signature-Header mit einer HMAC-SHA256-Signatur des Anfragekörpers, wobei Ihr webhook_secret als Schlüssel verwendet wird:
Verifizieren Sie diese Signatur auf Ihrem Server, um die Authentizität der Anfrage sicherzustellen. Die Zustellung erfolgt nach dem Fire-and-Forget-Prinzip mit einem 3-Sekunden-Timeout und ohne Wiederholungsversuche.
⟩Ratenlimits
API-Anfragen sind pro Endpunkt-Gruppe ratenlimitiert. Bei Überschreitung des Limits wird 429 Too Many Requests mit einem Retry-After-Header zurückgegeben, der angibt, wie viele Sekunden gewartet werden soll.
Endpunkt-Gruppe
Limit
Zeitfenster
Katalog (Länder, Dienste, Produkte, Wechselkurs)
5.000 Anfragen
60 Sekunden
Guthaben
600 Anfragen
60 Sekunden
Bestellabfragen (Liste, Einzeln, Aktiv)
5.000 Anfragen
60 Sekunden
Bestellung erstellen
3.000 Anfragen
60 Sekunden
Bestellung stornieren
1.000 Anfragen
60 Sekunden
Bestellaktionen (Abschließen, Erneut senden)
1.000 Anfragen
60 Sekunden
Webhook-Konfiguration (Abrufen, Aktualisieren)
600 Anfragen
60 Sekunden
Webhook-Test
10 Anfragen
60 Sekunden
⟩Fehlercodes
Fehlerantworten enthalten einen der folgenden Codes in error.code:
Code
HTTP
Beschreibung
UNAUTHORIZED
401
Fehlender oder ungültiger API-Token
FORBIDDEN
403
Zugriff verweigert
NOT_FOUND
404
Ressource nicht gefunden (Bestellung, Wechselkurs usw.)
CONFLICT
409
Doppelte Anfrage oder Ressourcenkonflikt
INSUFFICIENT_BALANCE
409
Unzureichendes Guthaben für die Bestellung
VALIDATION_ERROR
422
Anfrageparameter haben die Validierung nicht bestanden
RATE_LIMIT_EXCEEDED
429
Zu viele Anfragen (prüfen Sie den Retry-After-Header)
INTERNAL_ERROR
500
Interner Serverfehler
PROVIDER_ERROR
422
Vorgelagerter SMS-Anbieter hat die Anfrage abgelehnt. Bei fehlgeschlagener Bestellerstellung kann der Fehler details enthalten: cause_counts (Bestellungen mit altem product_id — eine nach Ursache gruppierte Zählung) oder attempts (Bestellungen mit catalog_product_id — Ergebnisse pro Versuch), mit den Werten ok, no_numbers, insufficient_balance, price_rejected, provider_unavailable, provider_account_balance, provider_error.
NO_OFFER_AVAILABLE
422
Kein aktives Angebot passt zum angeforderten Produkt und zur Richtlinie (Preisobergrenze, Verfügbarkeit).
CANCEL_TOO_EARLY
409
Bestellung zu neu zum Stornieren — warten Sie 2 Minuten
REQUEST_IN_PROGRESS
409
Eine Erstellungsanfrage mit diesem Idempotenzschlüssel läuft noch
IDEMPOTENCY_KEY_REUSED
422
Dieser Idempotenzschlüssel wurde bereits mit einem anderen Anfrage-Body verwendet
SERVICE_UNAVAILABLE
503
Dienst vorübergehend nicht verfügbar (Wartung)
FX_RATE_UNAVAILABLE
503
USD/IDR-Wechselkurs nicht verfügbar (v2-Geld-Endpoints) — gibt 503 mit einem Retry-After-Header zurück.
v1 → v2
⟩Migration von v1 zu v2
v1 liefert IDR; v2 liefert USD. Beide Versionen existieren dauerhaft parallel — es gibt keine Abschaltung. Wählen Sie pro Integration eine Version; mischen Sie keine Basispfade. v2 ist identisch mit v1, abgesehen davon, wie Geld dargestellt wird.
product_id ist die stabile SMSCode-ID des Preisstufen-Slots. Speichere sie, wenn du genau diese Preisstufe bestellen möchtest; Preis und Verfügbarkeit können sich in derselben Zeile ändern. catalog_product_id ist die stabile Umbrella-ID für Land+Plattform bei gerouteten Bestellungen; nutze sie mit optionalem operator_id, min_price, max_price, prefer_provider und policy, wenn der Server eine aktuell passende Preisstufe auswählen soll.
Parsen Sie Geldfelder als Objekte — lesen Sie amount als Dezimal-String; currency ist "USD".
Verwenden Sie für die Ledger-Abstimmung canonical_amount (exaktes IDR); der USD-amount ist eine Projektion zur Renderzeit, und der rate wird einmal in meta.fx offengelegt.
Behandeln Sie den neuen FX_RATE_UNAVAILABLE (503) — wiederholen Sie die Anfrage nach Retry-After. v1 gibt dies niemals zurück.