API-Referenz
Integrieren Sie unsichtbare Bot- & Proxy-Erkennung in Ihr Produkt. Keine CAPTCHAs. Keine Reibung. Unter 150 ms serverseitig pro Auswertung.
Zuletzt aktualisiert im August 2026 · jede API-Änderung landet im Changelog · Stabilitätsrichtlinie: nur additive Änderungen
sk_test_sandbox-Schlüssel — kein Konto erforderlich.Playbooks je Angriff: Kontoübernahme, Card Testing, Bonusmissbrauch, und mehr →
Schnellstart
Von null zur funktionierenden Integration in 5 Minuten. Erstellen Sie einen kostenlosen Schlüssel unter /signup — 1.000 Anfragen/Stunde, keine Karte.
Sie nutzen einen KI-Coding-Assistenten? Fügen Sie diesen Prompt ein, und er baut Maskbreak Ende-zu-Ende in Ihre App ein — Frontend-Script, Backend-Prüfung, Umgebungsvariable und ein Test. Er folgt der maschinenlesbaren Anleitung unter maskbreak.com/integrate.md.
Fetch https://maskbreak.com/integrate.md and follow it to add Maskbreak fraud protection to this app — protect signup, login, and checkout. My API key is sk_live_YOUR_API_KEY; put it in a SENTINEL_KEY env var, never in client-side code. Then show me how to test it.
Lädt…
// ——— STEP 1: Add SDK to your HTML <head> ————————————————————————————————————— <script async src="loading..."></script> <form class="monocle-enriched" id="login-form"> <input type="email" name="email" /> <!-- SDK auto-injects BOTH: name="monocle" (network) + name="sentinel_fp" (device) --> </form> // ——— STEP 2: Read both tokens in your frontend JS —————————————————————————————— document.getElementById('login-form').addEventListener('submit', async (e) => { e.preventDefault(); const email = e.target.email.value; // Sentinel.collect() waits for the device layer, then returns both. const { token, fingerprintEventId } = await window.Sentinel.collect(); // Send to YOUR backend (never call Maskbreak directly from the browser) await fetch('your-login-endpoint', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, token, fingerprintEventId }) }); }); // ——— STEP 3: Evaluate on your backend (Node.js) —————————————————————————————— app.post('/your-login-endpoint', async (req, res) => { const { email, token, fingerprintEventId } = req.body; const result = await fetch('https://maskbreak.com/v1/evaluate', { method: 'POST', headers: { 'Authorization': 'Bearer sk_live_YOUR_API_KEY', 'Content-Type': 'application/json' }, // Both layers — network + device — in one call. body: JSON.stringify({ token, fingerprintEventId }) }); const data = await result.json(); if (data.decision === 'block') { return res.status(403).json({ error: 'Bot or proxy detected.' }); } if (data.decision === 'review') { // e.g. require email verification or step-up auth } // ✓ Connection is clean — proceed res.json({ success: true }); });
Live ausprobieren
Rufen Sie den Sandbox-Endpunkt mit einem Klick auf. Keine Registrierung, kein API-Schlüssel — nur echte /v1/evaluate-Antwortstrukturen, die Sie in Ihren Code übernehmen können.
Produktionsaufrufe nutzen POST /v1/evaluate mit einem token aus dem SDK und einem Authorization: Bearer sk_live_...-Header. Der Beispiel-Endpunkt liefert dieselbe Antwortstruktur, sodass Sie Ihre Parsing-Logik vor der Registrierung verdrahten können.
So funktioniert es
Maskbreak nutzt einen dreistufigen Ablauf Client → Ihr Backend → Maskbreak-API, damit Ihr geheimer Schlüssel nie im Browser landet.
Das Maskbreak-SDK läuft unsichtbar im Browser Ihres Nutzers und sammelt Telemetrie. Es fügt Ihren Formularen ein verschlüsseltes token hinzu.
Ihr Frontend sendet das Token zusammen mit den übrigen Formulardaten an Ihren eigenen Backend-Server.
Ihr Backend ruft POST /v1/evaluate mit Ihrem geheimen Schlüssel auf. Maskbreak liefert sofort einen Threat-Intelligence-Bericht.
Authentifizierung
Alle Anfragen an /v1/evaluate müssen Ihren geheimen API-Schlüssel als Bearer-Token enthalten. Ihren Schlüssel finden Sie im Dashboard.
sk_live_… niemals in Ihr HTML, JavaScript oder anderen clientseitigen Code. Verwenden Sie ihn nur in Ihrer Backend-Serverumgebung.Schlüssel rotieren
Rotieren Sie in der Konsole (Integration → Rotieren, oder Einstellungen → API-Schlüssel; Ihr Passwort wird erneut abgefragt). Der neue Schlüssel funktioniert sofort, und der bisherige bleibt 24 Stunden gültig, damit ein Deployment ohne Lücke umstellen kann. Ist ein Schlüssel geleakt, beendet Alten Schlüssel jetzt widerrufen in den Einstellungen diese Frist sofort. Während der Frist beantwortet jeder Schlüssel /v1/usage mit seinem eigenen Stundenkontingent.
Zwei weitere Schlüssel gehören zu jedem Konto: ein persönlicher sk_test_…-Schlüssel, der die volle Pipeline ausführt, ohne zu zählen, zu speichern oder zu alarmieren (eigenes Stundenkontingent, von der IP-Allowlist ausgenommen), und der öffentliche sk_test_sandbox-Schlüssel, der ganz ohne Konto nur die deterministischen Test-Token beantwortet. Eine optionale IP-Allowlist (Einstellungen → API-Schlüssel-Sicherheit) beschränkt den Live-Schlüssel auf Ihre Serveradressen; Aufrufe von anderswo erhalten 403 mit der betreffenden Adresse im Hinweis.
OAuth 2.0 Client Credentials Neu
Tauschen Sie Ihre Konto-E-Mail und Ihren API-Schlüssel über den Standard-Grant client_credentials gegen ein kurzlebiges Bearer-Token. Das Token trägt Ihre Konto-ID, nie den Schlüssel selbst. Es gilt 60 Minuten und funktioniert über eine Schlüsselrotation hinweg (es löst auf den jeweils aktuellen Schlüssel auf), sodass eine Rotation bereits ausgestellte Token nicht widerruft — stellen Sie keine neuen mehr aus und lassen Sie die alten ablaufen. Ein mit Ihrem sk_test_-Schlüssel geprägtes Token bleibt ein Test-Credential. API-Schlüssel funktionieren genau wie zuvor; das hier ist additiv.
POST /oauth/token
/.well-known/oauth-authorization-server und /.well-known/oauth-protected-resource.curl -X POST https://maskbreak.com/oauth/token \
-H "Content-Type: application/json" \
-d '{"grant_type":"client_credentials","client_id":"your@email.com","client_secret":"sk_live_..."}'Verwenden Sie das zurückgegebene access_token überall dort im Authorization: Bearer-Header, wo ein API-Schlüssel akzeptiert wird. Token laufen ab; erneuern Sie sie durch Wiederholen des Austauschs. Der Schlüssel selbst verlässt Ihren Server nie.
SDK einbinden
Binden Sie das Maskbreak-SDK auf jeder Seite ein, auf der Sie Nutzer auswerten wollen. Ein Script lädt beide Erkennungsschichten — Netzwerkintelligenz (VPN, Proxy, Rechenzentrum) und Geräteintelligenz (Antidetect-Browser, Bots, Manipulation) — und fügt beide Token in Ihre Formulare ein.
<!-- Maskbreak SDK — network + device, paste inside <head> --> <script async src="loading..."></script> <!-- Add class="monocle-enriched" to any form you want evaluated --> <form class="monocle-enriched" id="my-form"> <!-- The SDK injects both automatically: --> <input type="hidden" name="monocle" value="eyJ..." /> // network <input type="hidden" name="sentinel_fp" value="a1b2..." /> // device </form>
Das SDK braucht etwa 1–2 Sekunden zum Laden und Erzeugen der Token. Wenn die Geräteschicht nicht laufen kann (z. B. weil ein gehärteter Browser sie blockiert), läuft die Auswertung allein über die Netzwerkschicht weiter.
Token einsammeln
Rufen Sie beim Absenden Sentinel.collect() auf — es wartet, bis sich die Geräteschicht gesetzt hat, und liefert { token, fingerprintEventId }. Leiten Sie beides an Ihr Backend weiter. (Oder lesen Sie die versteckten Felder monocle und sentinel_fp direkt aus.)
document.getElementById('my-form').addEventListener('submit', async (e) => { e.preventDefault(); // Both layers: network token + device event id const { token, fingerprintEventId } = await window.Sentinel.collect(); if (!token) { // Network SDK still loading — ask user to try again return showError('Security check loading. Please try again.'); } // Forward both to your backend with the rest of the form data const res = await fetch('/your-backend-endpoint', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: e.target.email.value, token, fingerprintEventId // ← both layers to your backend }) }); });
Den Evaluate-Endpunkt aufrufen
lädt…
Rufen Sie das von Ihrem Backend-Server auf — nie aus dem Browser. Übergeben Sie das Token vom Client und Ihren geheimen API-Schlüssel.
Request-Body
input[name="monocle"] des Clients.sentinel_fp ein; leiten Sie sie hier weiter (beide Namen werden akzeptiert), um die device.*-Signale freizuschalten (Antidetect, Automatisierung, Emulator, …). Ohne sie erhalten Sie ein reines Netzwerk-Urteil.fingerprintEventId zählt Maskbreak, mit wie vielen verschiedenen Konten dieses Gerät unter Ihrem API-Schlüssel verknüpft wurde, und liefert device.linked_accounts / device.multi_account — Multi-Accounting-Erkennung ohne zusätzliche Integration. Nur als Einweg-Hash gespeichert.email.disposable hinzu — geprüft gegen einen laufend aktualisierten Feed mit Tausenden Wegwerf-Domains. Ein Treffer fügt den Grund disposable_email hinzu, erhöht den risk_score und stuft allow zu review hoch. Die Adresse wird nur vorübergehend geprüft und nie gespeichert oder protokolliert.Europe/Tallinn. Unser Client-SDK sendet sie automatisch als sentinel_tz, was dieser Endpunkt ebenfalls akzeptiert; selbst auslesen können Sie sie mit Intl.DateTimeFormat().resolvedOptions().timeZone — ohne Berechtigungsabfrage und ohne Geolokalisierung. Fügt der Antwort einen timezone-Block hinzu. Sieht die Verbindung gewöhnlich aus, während die Uhr des Browsers zu einem anderen Land gehört, ist das die Form eines Residential-Proxys, den die Netzwerkschicht nicht erwischt hat: es fügt den Grund timezone_mismatch hinzu, erhöht den risk_score und stuft allow zu review hoch. Bewusst nicht ausgelöst bei VPN, Proxy, Tor oder Rechenzentrums-Exit — der Uhr zu widersprechen ist genau das, was die tun — und nie allein genug für block, weil Reisende und Auswanderer hier legitim landen.Testen ohne Browser: Senden Sie ein deterministisches Test-Token — test_clean, test_vpn, test_proxy, test_datacenter oder test_tor —, um Ihre allow-/review-/block-Behandlung Ende-zu-Ende zu prüfen. Testaufrufe werden wie echte authentifiziert und ratenlimitiert, aber nie berechnet, gespeichert oder per Webhook gemeldet, und die Antwort trägt "test": true.
CI & Staging ohne Konto: Der öffentliche Sandbox-Schlüssel sk_test_sandbox akzeptiert dieselben test_*-Token und liefert dieselben deterministischen Strukturen — keine Registrierung, nichts berechnet, nichts gespeichert, berührt nie eine echte Quote. Er beantwortet nur Test-Token (Live-Traffic braucht weiterhin Ihren echten Schlüssel) und ist pro IP ratenlimitiert. curl -X POST https://maskbreak.com/v1/evaluate -H "Authorization: Bearer sk_test_sandbox" -H "Content-Type: application/json" -d '{"token":"test_vpn"}'
Ihr eigener Testschlüssel (volle Pipeline, kein Fußabdruck): Jedes Konto hat zusätzlich einen persönlichen sk_test_…-Schlüssel (Einstellungen → API-Schlüssel), der anders als die Sandbox die komplette Live-Pipeline ausführt — echte Token, echte Geräteintelligenz, Ihre Regeln und Ausnahme-Pins eingeschlossen. Die Events, die er erzeugt, sind in der Konsole als Test markiert, aus Verbrauch und Statistik ausgenommen, lösen nie Webhooks oder Limit-E-Mails aus, und die Antwort trägt "test": true. Er hat sein eigenes Stundenkontingent und ist bewusst von der IP-Allowlist ausgenommen, damit CI und Laptops die Pipeline ausprobieren können, ohne Löcher in Ihre Produktionsbeschränkung zu schlagen.
const response = await fetch('https://maskbreak.com/v1/evaluate', { method: 'POST', headers: { 'Authorization': 'Bearer sk_live_YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ token: req.body.token // as sent by your frontend (see Quick Start Step 2) }) }); const data = await response.json(); // data.decision → 'allow' | 'review' | 'block' (covers VPN, proxy, // datacenter, Tor, antidetect, automation) — route on this // data.reasons → machine-readable why if (data.decision === 'block') { return res.status(403).json({ error: 'Suspicious connection.' }); }
# pip install sentinelsup from sentinel import Sentinel s = Sentinel(api_key='sk_live_YOUR_API_KEY') # or omit — reads SENTINEL_KEY env var result = s.evaluate(token=sentinel_token) # from the form POST body # result.decision → 'allow' | 'review' | 'block' — route on this # result.reasons → machine-readable why if result.is_blocked: return '403 Suspicious connection', 403
curl -X POST 'https://maskbreak.com/v1/evaluate' \ -H 'Authorization: Bearer sk_live_YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"token": "eyJ..."}'
// composer require sentinelsup/sdk $sentinel = new \Sentinel\Client(); // or pass the key — reads SENTINEL_KEY env var $result = $sentinel->evaluate([ 'token' => $_POST['monocle'], // hidden input the client SDK adds ]); // $result->decision → 'allow' | 'review' | 'block' — route on this // $result->reasons → machine-readable why if ($result->isBlocked()) { http_response_code(403); exit(); }
Antwortobjekt
Ein erfolgreicher Aufruf liefert 200 OK mit dieser JSON-Struktur.
| Feld | Typ | Beschreibung |
|---|---|---|
| decision | string | Empfohlene Aktion: "allow", "review" oder "block". Nur beratend — die Richtlinie legen Sie fest. Das reasons-Array erklärt jede Entscheidung, sodass Sie sie protokollieren oder Ihrem Endnutzer einen Ablehnungsgrund zeigen können. Wenn Sie in Ihrem Dashboard eigene Regeln konfigurieren, liefert dieses Feld Ihre Aktion für ein passendes Signal (die strengste Regel gewinnt). |
| engine_decision | string | decision_source wird immer dann zurückgegeben, wenn Ihre Richtlinie auf dieses Event gepasst hat: "rules" (mit rule_matched, das die Signale nennt, die eine Regel ausgelöst haben) oder "exception" (mit exception_matched, das den IP-/Besucher-Pin aus der Ausnahmenliste Ihres Dashboards nennt — explizite Pins schlagen Signalregeln). engine_decision erscheint zusätzlich, wenn der Treffer die Entscheidung tatsächlich verändert hat, und bewahrt das eigene Risiko-Score-Urteil der Engine. |
| risk_score | integer | Zusammengesetzter Risiko-Score 0–100 über alle Netzwerk- und Gerätesignale. Wird von eigenen Regeln nicht verändert. |
| isSuspicious | boolean | Legacy-Komfortflag. true, wenn VPN, Proxy, Antidetect, Automatisierung oder Emulator ausgelöst haben. Tor- und Rechenzentrumssignale erhöhen den risk_score und steuern decision (Tor blockiert), setzen dieses Flag aber nicht — routen Sie für volle Abdeckung über decision. |
| ip | string | Die entlarvte, echte IP-Adresse des Nutzers. Gespiegelt unter details.ip. |
| country | string | ISO-3166-1-Ländercode (z. B. "US", "EE"). Gespiegelt unter details.cc. |
| network. |
boolean | Kommerzielles VPN erkannt (NordVPN, Proton, ExpressVPN usw.). Gespiegelt unter details.vpn. |
| network. |
boolean | Residential- oder SOCKS/HTTP-Proxy erkannt. Gespiegelt unter details.proxied. |
| network. |
boolean | Traffic aus einem bekannten Rechenzentrums-/Cloud-Anbieter-ASN. Gespiegelt unter details.dch. |
| network. |
boolean | Tor-Exit-Node erkannt. Gespiegelt unter details.tor. |
| network. |
boolean | Irgendeine Anonymisierungsschicht erkannt. Gespiegelt unter details.anon. |
| network. |
boolean | true, wenn weder Rechenzentrum noch Proxy ausgelöst haben (sieht nach einer echten Heim-IP aus). |
| network. |
string | Identifizierter Anbieter, wenn bekannt (z. B. "PROTON_VPN", "BRIGHT_DATA"). Gespiegelt unter details.service. |
| device. |
boolean | Antidetect-/Fingerprint-Spoofing-Browser (Multilogin, Kameleo, GoLogin usw.). Nur vorhanden, wenn fingerprintEventId gesendet wurde. |
| device. |
boolean | Automatisierter Browser erkannt (Puppeteer, Playwright, Selenium). |
| device. |
boolean | Mobil-Emulator. |
| device. |
boolean | Virtuelle Maschine. |
| device. |
boolean | Privater / Inkognito-Modus erkannt. |
| device. |
boolean | Erweiterte Datenschutzeinstellungen aktiv (z. B. Brave Shields, Firefox resist-fingerprinting). |
| device. |
boolean | Die Besucher-IP steht auf E-Mail-Spam- oder Angriffsquellen-Blocklisten. |
| device. |
boolean | Dieses Gerät wird ungewöhnlich oft identifiziert (High-Activity Device). Informativ — häufige Besuche allein sind kein Betrug, aber in Kombination mit anderen Signalen deuten sie oft auf Automatisierung oder Farming hin. Fügt den Grundcode high_activity_device hinzu. |
| device. |
string | Stabiler Geräte-Fingerprint-Hash. Dasselbe Gerät liefert über Sitzungen hinweg dieselbe ID, auch nach dem Löschen der Cookies — nützlich für ATO-Abwehr und Geräte-Clustering. |
| device. |
number | Manipulations-Score 0–1. Über 0,6 deutet stark auf einen Antidetect-Browser hin; 0,3–0,6 bedeutet weiche Inkonsistenzen; unter 0,3 ist normal. |
| device. |
integer | Wie oft Maskbreak dieses Gerät in den letzten 90 Tagen gesehen hat, geschlüsselt über einen Einweg-Hash der Besucher-ID (die rohe ID wird nie gespeichert). 1 bedeutet ein brandneues Gerät — neue Geräte bei hochwertigen Aktionen sind ein klassisches Betrugsmerkmal. |
| device. |
string | ISO-8601-Zeitstempel, wann Maskbreak dieses Gerät unter Ihrem API-Schlüssel zum ersten Mal gesehen hat. Vorhanden, wenn das Gerät identifiziert wurde — ein sehr junges first_seen neben einer hochwertigen Aktion ist dasselbe Betrugsmerkmal wie times_seen: 1, mit explizit gemachtem Alter. |
| device. |
boolean | True, wenn times_seen > 1 — dieses Gerät wurde schon einmal ausgewertet. |
| device. |
integer | Mit wie vielen verschiedenen Konten dieses Gerät in den letzten 90 Tagen unter Ihrem API-Schlüssel gesehen wurde. Nur vorhanden, wenn Sie Ihre eigene accountId zusammen mit fingerprintEventId in der Anfrage übergeben. Beide Kennungen werden nur als Einweg-Hashes gespeichert. |
| device. |
boolean | True, wenn linked_accounts > 1 — das zentrale Multi-Accounting-Signal (Bonusmissbrauch, Trial-Farming, doppelte Registrierungen). Fügt den Grundcode multi_account_device hinzu. |
| email. |
boolean | Nur vorhanden, wenn die Anfrage den optionalen Parameter email enthielt. true, wenn die Adresse eine bekannte Wegwerf-Domain nutzt — fügt den Grund disposable_email hinzu und stuft allow zu review hoch. |
| timezone. |
string | Nur vorhanden, wenn die Anfrage eine erkannte tz enthielt. Die vom Browser gemeldete IANA-Zone, zurückgespiegelt. |
| timezone. |
string | ISO-3166-1-alpha-2-Land, zu dem diese Zone gehört. |
| timezone. |
boolean | true, wenn das Land der Zone gleich country (dem der Exit-IP) ist. Bauen Sie darauf Ihre eigene Regel, wenn Sie eine strengere Richtlinie als unsere wollen. |
| timezone. |
boolean | false bei VPN-, Proxy-, Tor- oder Rechenzentrums-Exit, wo eine Abweichung erwartet wird und wir nichts auslösen. Bei false lesen Sie matches_ip als Information, nicht als Urteil. |
| reasons | string[] | Maschinenlesbare Codes dafür, welche Signale ausgelöst haben (z. B. "vpn_detected", "datacenter_asn", "antidetect_browser"). |
| evaluated_in_ms | integer | Serverseitige Verarbeitungszeit für diese Anfrage in Millisekunden. |
{
"status": "success",
"isSuspicious": true,
"decision": "review",
"risk_score": 65,
"ip": "185.107.80.12",
"country": "EE",
"network": {
"vpn": true,
"proxy": false,
"datacenter": true,
"tor": false,
"anonymous": true,
"residential": false,
"service": "PROTON_VPN"
},
"reasons": ["vpn_detected", "datacenter_asn"],
"evaluated_in_ms": 126,
"details": { /* legacy mirror */
"ip": "185.107.80.12",
"cc": "EE",
"vpn": true,
"proxied": false,
"anon": true,
"dch": true,
"service": "PROTON_VPN"
}
}{
"status": "success",
"isSuspicious": false,
"decision": "allow",
"risk_score": 0,
"ip": "82.131.45.9",
"country": "DE",
"network": {
"vpn": false,
"proxy": false,
"datacenter": false,
"tor": false,
"anonymous": false,
"residential": true,
"service": null
},
"reasons": [],
"evaluated_in_ms": 118
}Wie die Entscheidung zustande kommt
block, wenn ein hartes Signal vorliegt: ein Proxy, ein Tor-Exit, ein Bot oder Automatisierung, ein Emulator oder ein Fake-Browser. review, wenn ein VPN oder ein manipulierter Browser ohne hartes Signal vorliegt. allow sonst — eine Rechenzentrumsadresse oder ein anonymisierendes Netz allein erhöht nur den risk_score. Ihre Regeln können die Antwort jedes Signals überschreiben; das eigene Urteil der Engine wird immer mitgeliefert.
Eingeschränkte Antworten. Erreicht kein Client-Token die API oder ist die Netzwerkschicht nicht erreichbar, liefert der Aufruf trotzdem 200 mit "ip": "unknown", allen Netzwerkflags auf false und decision: "allow". Er wird nicht berechnet und nicht gespeichert. Behandeln Sie das als „kein Beleg“, nicht als sauberen Besucher.
Zusätzliche Flags. test: true bei jeder Antwort auf ein Test-Token oder einen Testschlüssel, sandbox: true, wenn der öffentliche sk_test_sandbox-Schlüssel verwendet wurde, sample: true bei /v1/evaluate/sample. /v1/lookup trägt zusätzlich ein additives network.cloud-Objekt, das den Anbieter nennt, wenn die Adresse in einem veröffentlichten Cloud-Bereich liegt.
Grundcodes
Jeder Wert, den reasons[] tragen kann, und was er bedeutet. Neue Codes kommen nur hinzu.
anonymous_network— ein anonymisierendes Netz ohne benannten Betreiberantidetect_browser— ein Fake-Browser (Antidetect-Tooling oder eine manipulierte Umgebung)automation_detected— ein Script oder Headless-Browserdatacenter_asn— eine Rechenzentrums- oder Cloud-Adressedisposable_email— eine Wegwerf-E-Mail-Adresseemulator_detected— ein Emulatorhigh_activity_device— ein ungewöhnlich oft gesehenes Gerät (weiches Signal)ip_blocklisted— eine Adresse auf einer Blocklistemulti_account_device— ein Gerät, das bereits hinter mehreren Ihrer Konten stecktprivate_browsing— ein Inkognito- oder privates Fensterproxy_detected— ein Residential- oder Cloud-Proxytimezone_mismatch— die Zeitzone des Browsers widerspricht der Adresse (nur wenn geprüft)tor_exit_node— ein Tor-Exitvirtual_machine— eine virtuelle Maschinevpn_detected— ein VPN-Dienst (network.service nennt ihn, wenn bekannt)
Test-Token
Senden Sie eines davon als token mit Ihrem Live-Schlüssel, Ihrem Testschlüssel oder sk_test_sandbox. Mit Ihren eigenen Schlüsseln befolgen sie Ihre Regeln und Ausnahme-Pins (test_vpn ist damit ein Einzeiler, um eine Regel zu prüfen); sie werden nie berechnet. Aus der Konsole gemachte Aufrufe werden als Testzeilen gespeichert, damit das Events-Log etwas zu zeigen hat.
| Token | Vorgetäuschter Besucher | Signale | Entscheidung |
|---|---|---|---|
test_clean | 203.0.113.42 · US | nichts | allow |
test_vpn | 198.51.100.18 · NL | VPN, Rechenzentrum (PROTON_VPN) | review |
test_proxy | 203.0.113.9 · DE | Proxy, Rechenzentrum (BRIGHT_DATA) | block |
test_datacenter | 203.0.113.7 · DE | Rechenzentrum (AWS) | allow |
test_tor | 203.0.113.99 · null | Tor (TOR) | block |
IP-Lookup
Ein Urteil für eine bloße IP-Adresse — kein Browser-Token nötig. Gleicher Schlüssel, gleiches Stundenkontingent wie /v1/evaluate.
GET /v1/lookup/{ip} — für serverseitiges Screening, wo kein Client läuft: Allowlist-Prüfungen, Batch-Scoring, Anreichern Ihrer eigenen Logs. Nur Netzwerksignale (es gibt kein Gerät zum Fingerprinten), nutzen Sie also /v1/evaluate, sobald ein Browser beteiligt ist. Bei einer bloßen IP greifen die Tor-Exit- und Cloud-Bereichsprüfungen; VPN- und Proxy-Tunnel — und der Dienstname in network.service — werden bei einem Live-Besuch über /v1/evaluate erkannt, sodass signals.vpn und signals.proxied hier false zurückkommen.
curl https://maskbreak.com/v1/lookup/185.220.101.34 \
-H "Authorization: Bearer sk_live_YOUR_API_KEY"
{
"ip": "185.220.101.34",
"known": true,
"verdict": "block", // allow | review | block
"risk_score": 90,
"signals": { "vpn": false, "proxied": false, "tor": true, "dch": false, "anon": true },
"network": { "asn": 205100, "org": "F3 Netze", "country": "DE", "city": null },
"latency_ms": 121
}
known: false bedeutet, dass keine Intelligence-Quelle eine Meinung hatte — das Urteil ist dann allow mit risk_score: 0, was „nichts gefunden“ heißt, nicht saubere Garantie. Ausnahme-Pins, die Sie im Dashboard konfigurieren, gelten auch hier (verdict_source: "exception" mit additiv erhaltenem engine_verdict). Die Signalschreibweisen (proxied, dch) sind eingefroren — sicher zu parsen.
Ratenlimits
Maskbreak ist in der offenen Beta — jeder Zugang ist kostenlos. Zwei Limits laufen parallel; welches Sie zuerst erreichen, liefert 429.
| Geltungsbereich | Limit |
|---|---|
| Pro API-Schlüssel (Kostenlos) | 1.000 Anfragen / Stunde |
| Pro API-Schlüssel (öffentliches Interesse) | Kein Stundenlimit |
| Pro Quell-IP | 50.000 Anfragen / Stunde (freigegebene Schlüssel im öffentlichen Interesse passieren es) |
Kein Monatslimit während der Beta. Die Grenze pro IP ist ein Schutz gegen ausufernden Missbrauch von einer einzelnen Maschine. Retry-After ist in jeder 429-Antwort enthalten.
Mit Schlüssel aufgerufene /v1/evaluate- und /v1/lookup-Antworten tragen außerdem X-RateLimit-Limit, X-RateLimit-Remaining und X-RateLimit-Reset (Unix-Sekunden), damit Sie vor dem 429 bremsen können — sowie einen X-Request-Id-Header, den Sie dem Support nennen können, wenn etwas seltsam aussieht.
Schlüssel im Programm für das öffentliche Interesse (Krankenhäuser, öffentliche Gesundheit, Behörden, Wahlen, Rettungsdienste, Universitäten, eingetragene gemeinnützige Organisationen) haben kein Stundenlimit: die drei X-RateLimit-*-Header werden weggelassen statt mit einem Platzhalter gefüllt, und /v1/usage meldet hourly_limit: null mit uncapped: true.
Zuverlässigkeit & Fail-open-Verhalten
Maskbreak fällt offen aus: Ist ein vorgelagerter Anbieter für Netzwerk- oder Geräteintelligenz nicht erreichbar, liefert die Auswertung ihre besten verfügbaren Signale statt eines Fehlers, und ein fehlender Anbieter bedeutet, dass genau diese Signale einfach fehlen (nie eine falsche „sauber“-Garantie). So läuft Ihr Checkout oder Login bei einem Anbieter-Aussetzer weiter, statt alle zu blockieren. Behandeln Sie decision deshalb als beratend und setzen Sie eigene Schwellen — bei kritischen Aktionen ist eine Step-up-Verifizierung bei "review" dem harten Durchlassen vorzuziehen, damit eine eingeschränkte Auswertung eine Bedrohung nicht still durchwinkt. Tritt das ein, trägt die Antwort ein degraded: true auf oberster Ebene; ist das Urteil der bloße saubere Standard, wird der Aufruf nicht in total_evaluations gezählt (Ihr Verbrauch unter /v1/usage und im Dashboard) und nicht in Ihr Events-Log geschrieben — wie jeder authentifizierte Aufruf verbraucht er aber trotzdem eine Anfrage des Stundenlimits, sodass sich X-RateLimit-Remaining bewegt. Ein fehlendes oder leeres Token wird genauso behandelt. Ein Token, das der Anbieter ablehnt (fehlerhaft oder manipuliert), ist kein Anbieterausfall: das liefert 400 Invalid token. und wird ebenfalls nicht gezählt.
Fehlercodes
Alle Fehlerantworten der API enthalten ein error-Stringfeld. Eine Ausnahme, unter 403 vermerkt: eine Sperre am Edge liefert Klartext, kein JSON.
-
400
Bad Request — Ungültiges
token(vom Anbieter abgelehnt oder kein String). Ein fehlendes oder leeres Token ist kein Fehler: es wird fail-open mitdegraded: truebeantwortet. - 401 Unauthorized — Ungültiger oder fehlender API-Schlüssel.
-
403
Forbidden — Konto gesperrt (kontaktieren Sie support@maskbreak.com), oder die IP des Aufrufers steht nicht auf der IP-Allowlist Ihres Schlüssels (Einstellungen → API-Schlüssel-Sicherheit; das Feld
hintnennt die aufrufende Adresse). Von derselben Adresse nicht wiederholbar.
Dritte Ursache, und die verwirrende: Ein bloßeserror code: 1010alstext/plainohne JSON-Body kommt nicht von uns — das ist unser Edge, der den Standard-User-Agent Ihres HTTP-Clients ablehnt.Python-urllibist der häufige Fall. Setzen Sie irgendeinen echtenUser-Agent-Header, und es verschwindet; jedes offizielle SDK tut das bereits. - 429 Rate Limited — Stündliches Anfragelimit überschritten (1.000/Std. pro Schlüssel, 50.000/Std. pro Quell-IP). Wird für einen freigegebenen Schlüssel im öffentlichen Interesse nie zurückgegeben.
- 500 Server Error — Unerwarteter interner Fehler. Kann gefahrlos mit Backoff wiederholt werden.
Verbrauch
Der Quotenstand Ihres Schlüssels als Endpunkt — fragen Sie ihn ab, statt Ratenlimit-Header aus Ihrer letzten Antwort zu kratzen.
GET /v1/usage — authentifizieren Sie sich mit dem API-Schlüssel selbst (Authorization: Bearer …). Funktioniert mit beiden Schlüsseltypen — sk_live_ und sk_test_ melden jeweils ihr eigenes Stundenkontingent, benannt in key_type — und der Aufruf ist kostenlos: er verbraucht nie Quote, sodass ein Monitor, der ihn abfragt, Ihr Limit nicht anknabbern kann.
curl https://maskbreak.com/v1/usage \
-H "Authorization: Bearer sk_live_YOUR_API_KEY"
{
"key_type": "live", // or "test"
"hourly_limit": 1000,
"used_this_hour": 412,
"remaining": 588,
"resets_at": "2026-07-19T11:00:00.000Z", // end of the rolling 60 minutes that began with your first call; null if nothing used yet
"total_evaluations": 183204,
"limit_hits": 3
}
used_this_hour und remaining sind Richtwerte: die Zähler liegen im Speicher und pro Prozess, sie werden bei einem Deployment zurückgesetzt — behandeln Sie sie als Live-Anzeige, nicht als Prüfprotokoll (die Durchsetzung des eigentlichen Limits ist davon unberührt). total_evaluations und limit_hits sind dauerhafte Kontosummen.
Limits und Hinweise. Das Stundenkontingent ist ein rollierendes 60-Minuten-Fenster, das mit Ihrem ersten Aufruf beginnt. Erreicht ein Live-Schlüssel 80 % davon, und erneut, wenn er das Limit trifft, erhält der Kontoinhaber eine E-Mail pro 24 Stunden; der Testschlüssel mailt nie. /v1/usage ist kostenlos aufrufbar, hat aber eine eigene Grenze von 120 Anfragen pro Minute und Adresse (429 mit Retry-After) und antwortet mit 403, wenn die IP-Allowlist des Schlüssels den Aufrufer ausschließt. Wiederholte Aufrufe mit ungültigem Schlüssel sperren die Adresse für 15 Minuten (429, Retry-After: 900).
Webhooks
Bedrohungsalarme an Slack, Discord oder Ihren eigenen Endpunkt — konfiguriert im Integration-Tab der Konsole unter Alarme.
Wann sie auslösen. Bei von der Engine erkannten Bedrohungen (VPN, Proxy, Tor, Rechenzentrum mit Manipulation, Bots, Antidetect-Browser) und bei jeder Auswertung, die Ihre eigenen Regeln mit block entschieden haben. Slack- und Discord-URLs bekommen eine kanalfertige Nachricht; jeder andere HTTPS-Endpunkt erhält ein JSON-Event (event: "threat.detected" mit IP, Bedrohungstyp und den Signaldetails). Der Button Test senden im Dashboard liefert dieselbe Struktur mit event: "test" — wenn Ihr Empfänger strikt nach Event-Typ verzweigt, behandeln Sie beide, sonst sieht der Test-Button wie ein stiller Fehlschlag aus.
Echtheit prüfen. Jede Zustellung ist mit dem Signaturgeheimnis Ihres Kontos signiert (neben der Webhook-URL im Dashboard zu sehen). Berechnen Sie HMAC_SHA256(secret, timestamp + "." + rawBody) mit dem Header X-Maskbreak-Timestamp und vergleichen Sie es (in konstanter Zeit) mit dem Hex-Digest in X-Maskbreak-Signature (nach dem Präfix sha256=). Weisen Sie alles Unsignierte, Abweichende oder Ältere als 5 Minuten zurück.
Empfänger zum Kopieren. Die zwei klassischen Fehler sind, gegen den neu serialisierten geparsten Body statt gegen die rohen Bytes zu prüfen und mit == zu vergleichen. Diese Empfänger machen es richtig:
const crypto = require('crypto'); const express = require('express'); const app = express(); // Raw body required — verify the exact bytes Maskbreak signed, // never a re-serialized JSON.parse() of them. app.post('/webhooks/sentinel', express.raw({ type: 'application/json' }), (req, res) => { const secret = process.env.SENTINEL_WEBHOOK_SECRET; // shown next to the URL in the dashboard const ts = req.get('X-Maskbreak-Timestamp') || ''; const sig = req.get('X-Maskbreak-Signature') || ''; // Freshness: reject anything older than 5 minutes (replay defense) const age = Math.abs(Date.now() / 1000 - Number(ts)); if (!ts || !Number.isFinite(age) || age > 300) return res.status(400).end(); // "sha256=" + HMAC_SHA256(secret, timestamp + "." + rawBody), hex digest const expected = 'sha256=' + crypto.createHmac('sha256', secret) .update(ts + '.').update(req.body).digest('hex'); // Constant-time compare — never === const a = Buffer.from(sig), b = Buffer.from(expected); if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) { return res.status(401).end(); } const event = JSON.parse(req.body); // { event: "threat.detected", event_id, ip, threat_type, details } // ... handle it (queue it, alert, block the IP upstream) res.status(200).end(); // answer 2xx fast — deliveries time out after 10 s });
import hashlib, hmac, os, time from flask import Flask, request, abort app = Flask(__name__) SECRET = os.environ["SENTINEL_WEBHOOK_SECRET"].encode() # shown next to the URL in the dashboard @app.post("/webhooks/sentinel") def sentinel_webhook(): ts = request.headers.get("X-Maskbreak-Timestamp", "") sig = request.headers.get("X-Maskbreak-Signature", "") # Freshness: reject anything older than 5 minutes (replay defense) try: fresh = abs(time.time() - int(ts)) <= 300 except ValueError: fresh = False if not fresh: abort(400) # "sha256=" + HMAC_SHA256(secret, timestamp + "." + raw_body), hex digest. # Sign request.get_data() — the exact raw bytes, not request.json. expected = "sha256=" + hmac.new( SECRET, ts.encode() + b"." + request.get_data(), hashlib.sha256 ).hexdigest() # Constant-time compare — never == if not hmac.compare_digest(sig, expected): abort(401) event = request.get_json(force=True) # {"event": "threat.detected", "event_id": ..., "ip": ..., "details": ...} # ... handle it (queue it, alert, block the IP upstream) return "", 200
Zustellung & Wiederholungen. Jedes Event wird bis zu 3-mal versucht: eine fehlgeschlagene Zustellung wird nach etwa 1 Minute und dann nach etwa 8 Minuten wiederholt. Wiederholungen sind Best-Effort und laufen im Prozess — ein Deployment mitten in der Wiederholung verwirft die restlichen Versuche —, behandeln Sie also das Events-Log im Dashboard als Quelle der Wahrheit und den Webhook als Best-Effort-Push. Die 25 letzten Zustellungen (Event, Ergebnis, Fehler) stehen in der Tools-Schublade des Dashboards, 30 Tage aufbewahrt; der Header-Chip zeigt den aktuellen Zustand, und schlagen 5 Zustellungen in Folge fehl, mailen wir Ihnen — ein toter Webhook darf nie als „keine Bedrohungen“ gelesen werden. Zustellungen laufen nach 10 s ab und folgen nie Weiterleitungen.
Dedupe über event_id. Jede Payload trägt eine event_id — 32 Hex-Zeichen, eindeutig pro Event, auch bei Test-Events vorhanden —, und jede Zustellung trägt sie zusätzlich im Header X-Maskbreak-Event-Id. Wiederholte Zustellungen verwenden dieselbe event_id, schlüsseln Sie Ihre Verarbeitung also darüber, und jedes Event wird genau einmal verarbeitet, egal wie viele Versuche Sie erreichen.
Payload für generische Endpunkte. Was Ihr Empfänger tatsächlich bekommt (Slack-/Discord-URLs erhalten stattdessen eine formatierte Nachricht):
{
"event": "threat.detected",
"event_id": "9f2ce7a4c1d84b7fa3d2c05e8b6f4a19", // unique per event; same on retries
"timestamp": "2026-07-19T09:14:03.512Z",
"ip": "185.220.101.34",
"threat_type": "Tor", // or "Custom rule (…)" / "Customer exception (…)"
"details": {
"ip": "185.220.101.34", "cc": "DE",
"vpn": false, "proxied": false, "tor": true, "dch": false,
"bot": false, "tampering": false, "antidetect": false,
"decision": "block",
"rule_matched": null, // signals, when your rule caused the block
"exception_matched": null // pins, when your exception caused it
}
}
MCP für KI-Agenten
Ein gehosteter Model-Context-Protocol-Server — richten Sie einen KI-Agenten darauf, und er kann IPs mit echten Maskbreak-Urteilen prüfen.
Endpunkt: POST https://maskbreak.com/mcp (streamable HTTP, zustandslos). Tools: lookup_ip — dasselbe Urteil wie GET /v1/lookup — und service_status. Authentifizieren Sie sich entweder mit einem klassischen API-Schlüssel Authorization: Bearer sk_live_… oder mit einem OAuth-access_token aus POST /oauth/token. Anonyme Nutzung teilt sich die engen Pro-IP-Limits des kostenlosen Tools; authentifizierte Aufrufe laufen über Ihre Quote von 1.000/Stunde (Ihre IP-Allowlist gilt auch hier).
{
"mcpServers": {
"sentinel": {
"type": "http",
"url": "https://maskbreak.com/mcp",
"headers": { "Authorization": "Bearer sk_live_YOUR_API_KEY" }
}
}
}
API-Stabilität & Versionierung
Worauf Sie bauen können, ohne sich zu sorgen, dass sich der Boden bewegt.
Versionierung. Die API ist im Pfad versioniert (/v1/). Innerhalb einer Hauptversion machen wir nur additive Änderungen: neue Antwortfelder, neue optionale Anfrageparameter, neue Signalgründe. Ihre Integration muss unbekannte Felder in Antworten tolerieren — das ist die einzige Anforderung an Vorwärtskompatibilität, die wir an Sie stellen.
Breaking Changes. Antwortfelder umbenennen oder entfernen, Typen oder Bedeutungen ändern oder einen Endpunkt zurückziehen passiert nur in einer neuen Hauptversion (/v2/). Wenn dieser Tag kommt, funktioniert /v1/ noch mindestens 12 Monate nach der Ankündigung weiter.
Ankündigung von Abkündigungen. Jede Abkündigung wird mindestens 90 Tage im Voraus über das Changelog und per E-Mail an betroffene API-Schlüssel angekündigt, mit dokumentiertem Migrationspfad. Enterprise-Verträge können längere Supportfenster festschreiben — support@maskbreak.com.