sentinelsup 0.2.2__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sentinelsup-0.2.4/.github/workflows/ci.yml +31 -0
- {sentinelsup-0.2.2 → sentinelsup-0.2.4}/.gitignore +7 -7
- {sentinelsup-0.2.2 → sentinelsup-0.2.4}/LICENSE +21 -21
- {sentinelsup-0.2.2 → sentinelsup-0.2.4}/PKG-INFO +106 -48
- {sentinelsup-0.2.2 → sentinelsup-0.2.4}/README.md +99 -41
- {sentinelsup-0.2.2 → sentinelsup-0.2.4}/examples/django_middleware.py +57 -48
- {sentinelsup-0.2.2 → sentinelsup-0.2.4}/examples/flask_signup_guard.py +48 -46
- {sentinelsup-0.2.2 → sentinelsup-0.2.4}/pyproject.toml +48 -48
- {sentinelsup-0.2.2 → sentinelsup-0.2.4}/sentinel/__init__.py +224 -208
- sentinelsup-0.2.4/tests/test_client.py +148 -0
- {sentinelsup-0.2.2 → sentinelsup-0.2.4}/sentinel/py.typed +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Python SDK
|
|
2
|
+
on: [push, pull_request]
|
|
3
|
+
|
|
4
|
+
permissions:
|
|
5
|
+
contents: read
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
timeout-minutes: 10
|
|
11
|
+
strategy:
|
|
12
|
+
fail-fast: false
|
|
13
|
+
matrix:
|
|
14
|
+
python: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14']
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v7
|
|
17
|
+
with:
|
|
18
|
+
persist-credentials: false
|
|
19
|
+
- uses: actions/setup-python@v7
|
|
20
|
+
with:
|
|
21
|
+
python-version: ${{ matrix.python }}
|
|
22
|
+
- run: python -m unittest discover -s tests -v
|
|
23
|
+
- name: Build and check distributions
|
|
24
|
+
if: matrix.python == '3.14'
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install build twine
|
|
27
|
+
python -m build
|
|
28
|
+
python -m twine check dist/*
|
|
29
|
+
python -m pip install --no-deps dist/*.whl
|
|
30
|
+
cd "$RUNNER_TEMP"
|
|
31
|
+
python -c "from sentinel import Sentinel, SentinelError; assert Sentinel('sk_test_fixture').api_key == 'sk_test_fixture'"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
__pycache__/
|
|
2
|
-
*.py[cod]
|
|
3
|
-
*.egg-info/
|
|
4
|
-
build/
|
|
5
|
-
dist/
|
|
6
|
-
.venv/
|
|
7
|
-
.pytest_cache/
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.egg-info/
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
.venv/
|
|
7
|
+
.pytest_cache/
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Sentinel Edge Networks LTD
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sentinel Edge Networks LTD
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sentinelsup
|
|
3
|
-
Version: 0.2.
|
|
4
|
-
Summary:
|
|
5
|
-
Project-URL: Homepage, https://
|
|
6
|
-
Project-URL: Documentation, https://
|
|
7
|
-
Project-URL: Repository, https://github.com/sentinelsup/
|
|
8
|
-
Project-URL: Issues, https://github.com/sentinelsup/
|
|
9
|
-
Author-email: Sentinel Edge Networks LTD <support@
|
|
3
|
+
Version: 0.2.4
|
|
4
|
+
Summary: Official Maskbreak SDK for browser-backed fraud checks and cloud/Tor IP lookups.
|
|
5
|
+
Project-URL: Homepage, https://maskbreak.com
|
|
6
|
+
Project-URL: Documentation, https://maskbreak.com/api
|
|
7
|
+
Project-URL: Repository, https://github.com/sentinelsup/maskbreak-python
|
|
8
|
+
Project-URL: Issues, https://github.com/sentinelsup/maskbreak-python/issues
|
|
9
|
+
Author-email: Sentinel Edge Networks LTD <support@maskbreak.com>
|
|
10
10
|
License: MIT
|
|
11
11
|
License-File: LICENSE
|
|
12
12
|
Keywords: antidetect-browser,api,bot-detection,device-fingerprinting,fraud-detection,proxy-detection,sentinel,vpn-detection
|
|
@@ -27,9 +27,13 @@ Classifier: Typing :: Typed
|
|
|
27
27
|
Requires-Python: >=3.8
|
|
28
28
|
Description-Content-Type: text/markdown
|
|
29
29
|
|
|
30
|
-
# sentinelsup —
|
|
30
|
+
# sentinelsup — Maskbreak Python SDK
|
|
31
31
|
|
|
32
|
-
Official Python SDK for [
|
|
32
|
+
Official Python SDK for [Maskbreak](https://maskbreak.com). Evaluate SDK-backed
|
|
33
|
+
visits for network and browser risk signals, or look up a public IP for cloud
|
|
34
|
+
range and Tor signals. These are different evidence sources, not interchangeable
|
|
35
|
+
checks. VPN/proxy service names are returned when known; a VPN alone routes to
|
|
36
|
+
review under the default policy, not automatic blocking.
|
|
33
37
|
|
|
34
38
|
[](https://pypi.org/project/sentinelsup/)
|
|
35
39
|
[](https://pypi.org/project/sentinelsup/)
|
|
@@ -37,18 +41,18 @@ Official Python SDK for [Sentinel](https://sntlhq.com) — a real-time fraud det
|
|
|
37
41
|
|
|
38
42
|
Zero dependencies — just the standard library. Works with Flask, Django, FastAPI, or bare `urllib`.
|
|
39
43
|
|
|
40
|
-
## Set up with AI
|
|
44
|
+
## Set up with an AI assistant
|
|
41
45
|
|
|
42
46
|
Using Claude Code, Cursor, Copilot, or any AI coding assistant? Paste this one
|
|
43
47
|
prompt and it wires the whole integration — frontend script, backend check,
|
|
44
48
|
env var, and a test:
|
|
45
49
|
|
|
46
|
-
> Fetch https://
|
|
47
|
-
> protection to this app — protect signup, login, and checkout.
|
|
48
|
-
>
|
|
49
|
-
> client-side code.
|
|
50
|
+
> Fetch https://maskbreak.com/integrate.md and follow it to add Maskbreak fraud
|
|
51
|
+
> protection to this app — protect signup, login, and checkout. Read the API key
|
|
52
|
+
> from the server-only SENTINEL_KEY environment variable; I will configure the
|
|
53
|
+
> secret separately. Never put it in client-side code. Show me how to test it.
|
|
50
54
|
|
|
51
|
-
[`integrate.md`](https://
|
|
55
|
+
[`integrate.md`](https://maskbreak.com/integrate.md) is the canonical
|
|
52
56
|
machine-readable integration guide, kept in sync with the live API.
|
|
53
57
|
|
|
54
58
|
## Install
|
|
@@ -57,7 +61,7 @@ machine-readable integration guide, kept in sync with the live API.
|
|
|
57
61
|
pip install sentinelsup
|
|
58
62
|
```
|
|
59
63
|
|
|
60
|
-
Python 3.8+. Get a free API key (no credit card) at [
|
|
64
|
+
Python 3.8+. Get a free API key (no credit card) at [maskbreak.com/signup](https://maskbreak.com/signup).
|
|
61
65
|
|
|
62
66
|
## Quick start
|
|
63
67
|
|
|
@@ -67,7 +71,10 @@ from sentinel import Sentinel
|
|
|
67
71
|
|
|
68
72
|
s = Sentinel(api_key=os.environ["SENTINEL_KEY"]) # or omit — reads the env var itself
|
|
69
73
|
|
|
70
|
-
result = s.evaluate(
|
|
74
|
+
result = s.evaluate(
|
|
75
|
+
token=request.json["sentinelToken"],
|
|
76
|
+
fingerprint_event_id=request.json.get("fingerprintEventId"),
|
|
77
|
+
)
|
|
71
78
|
|
|
72
79
|
if result.is_blocked: # decision == 'block'
|
|
73
80
|
abort(403)
|
|
@@ -78,6 +85,11 @@ print(result.network) # {'vpn': True, 'proxy': False, 'datacenter': True
|
|
|
78
85
|
print(result.reasons) # ['vpn_detected', 'datacenter_asn', ...]
|
|
79
86
|
```
|
|
80
87
|
|
|
88
|
+
This is a handler fragment, not a complete signup implementation. Route `review`
|
|
89
|
+
to your verification/review flow; only `allow` is an approval. Keep API keys on
|
|
90
|
+
the server. An unavailable device layer or `raw["degraded"]` is not proof of a
|
|
91
|
+
clean visit; `degraded` describes the network layer only.
|
|
92
|
+
|
|
81
93
|
Check the signup email against the disposable-domain feed (checked
|
|
82
94
|
transiently, never stored), or look up an arbitrary IP with no browser
|
|
83
95
|
token at all:
|
|
@@ -94,7 +106,8 @@ print(info["signals"]) # {'vpn': ..., 'proxied': ..., 'tor': ..., '
|
|
|
94
106
|
|
|
95
107
|
## What you get back
|
|
96
108
|
|
|
97
|
-
`evaluate()` returns an `EvaluateResult` dataclass
|
|
109
|
+
`evaluate()` returns an `EvaluateResult` dataclass. The type sketch below uses
|
|
110
|
+
Python 3.10+ annotation syntax for readability; the package minimum stays 3.8:
|
|
98
111
|
|
|
99
112
|
```python
|
|
100
113
|
@dataclass
|
|
@@ -112,25 +125,25 @@ class EvaluateResult:
|
|
|
112
125
|
test: bool # True for test-token / test-key calls
|
|
113
126
|
raw: dict # full upstream response
|
|
114
127
|
|
|
115
|
-
is_suspicious: bool # True
|
|
128
|
+
is_suspicious: bool # True for a non-null decision other than 'allow'
|
|
116
129
|
is_blocked: bool # True if decision == 'block'
|
|
117
130
|
```
|
|
118
131
|
|
|
119
132
|
Try the live sample (same shape, no key needed):
|
|
120
133
|
|
|
121
134
|
```bash
|
|
122
|
-
curl "https://
|
|
135
|
+
curl "https://maskbreak.com/v1/evaluate/sample?scenario=vpn"
|
|
123
136
|
```
|
|
124
137
|
|
|
125
|
-
Or use the [interactive playground](https://
|
|
138
|
+
Or use the [interactive playground](https://maskbreak.com/api#playground).
|
|
126
139
|
|
|
127
140
|
## Frontend setup
|
|
128
141
|
|
|
129
|
-
Add the
|
|
142
|
+
Add the Maskbreak SDK to your frontend. One script loads **both** layers —
|
|
130
143
|
network (VPN/proxy/datacenter) and device (antidetect/bot/tampering):
|
|
131
144
|
|
|
132
145
|
```html
|
|
133
|
-
<script async src="https://
|
|
146
|
+
<script async src="https://maskbreak.com/assets/sentinel.js"></script>
|
|
134
147
|
|
|
135
148
|
<!-- Add class="monocle-enriched" to any form you want evaluated -->
|
|
136
149
|
<form class="monocle-enriched" id="signup-form">
|
|
@@ -142,7 +155,7 @@ network (VPN/proxy/datacenter) and device (antidetect/bot/tampering):
|
|
|
142
155
|
|
|
143
156
|
Forward both fields to your backend with the form submission and pass them to
|
|
144
157
|
`evaluate()` as `token` and `fingerprint_event_id` — without the second one,
|
|
145
|
-
the device-layer signals (antidetect, automation, emulator)
|
|
158
|
+
the device-layer signals (antidetect, automation, emulator) are unavailable. For
|
|
146
159
|
fetch/XHR submissions, collect them explicitly:
|
|
147
160
|
|
|
148
161
|
```js
|
|
@@ -151,7 +164,7 @@ const { token, fingerprintEventId } = await window.Sentinel.collect();
|
|
|
151
164
|
|
|
152
165
|
## Examples
|
|
153
166
|
|
|
154
|
-
### Flask —
|
|
167
|
+
### Flask — route signup decisions
|
|
155
168
|
|
|
156
169
|
```python
|
|
157
170
|
from flask import Flask, request, abort, jsonify
|
|
@@ -164,7 +177,8 @@ sentinel = Sentinel() # reads SENTINEL_KEY (or SENTINEL_API_KEY) from env
|
|
|
164
177
|
def signup():
|
|
165
178
|
data = request.get_json()
|
|
166
179
|
try:
|
|
167
|
-
result = sentinel.evaluate(token=data["sentinelToken"]
|
|
180
|
+
result = sentinel.evaluate(token=data["sentinelToken"],
|
|
181
|
+
fingerprint_event_id=data.get("fingerprintEventId"))
|
|
168
182
|
except SentinelError as e:
|
|
169
183
|
# Fail open OR fail closed — your call. Logged either way.
|
|
170
184
|
app.logger.warning("Sentinel error: %s", e)
|
|
@@ -173,6 +187,11 @@ def signup():
|
|
|
173
187
|
if result and result.is_blocked:
|
|
174
188
|
abort(403, "Signup blocked")
|
|
175
189
|
|
|
190
|
+
if result and result.decision == "review":
|
|
191
|
+
return jsonify({"needs_verification": True}), 202
|
|
192
|
+
|
|
193
|
+
# This example explicitly fails open on SDK errors. Choose an endpoint-
|
|
194
|
+
# specific fallback; do not reuse this policy for transfers or withdrawals.
|
|
176
195
|
# ... your normal signup flow
|
|
177
196
|
return jsonify({"ok": True})
|
|
178
197
|
```
|
|
@@ -181,7 +200,7 @@ def signup():
|
|
|
181
200
|
|
|
182
201
|
```python
|
|
183
202
|
from django.http import JsonResponse
|
|
184
|
-
from sentinel import Sentinel
|
|
203
|
+
from sentinel import Sentinel, SentinelError
|
|
185
204
|
|
|
186
205
|
sentinel = Sentinel() # reads SENTINEL_KEY (or SENTINEL_API_KEY) from env
|
|
187
206
|
|
|
@@ -192,13 +211,17 @@ class FraudCheckMiddleware:
|
|
|
192
211
|
def __call__(self, request):
|
|
193
212
|
if request.path.startswith("/api/checkout"):
|
|
194
213
|
token = request.META.get("HTTP_X_SENTINEL_TOKEN")
|
|
195
|
-
if token:
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
214
|
+
if not token:
|
|
215
|
+
return JsonResponse({"error": "verification required"}, status=400)
|
|
216
|
+
try:
|
|
217
|
+
result = sentinel.evaluate(token=token,
|
|
218
|
+
fingerprint_event_id=request.META.get("HTTP_X_SENTINEL_FINGERPRINT_EVENT_ID"))
|
|
219
|
+
except SentinelError:
|
|
220
|
+
return JsonResponse({"error": "verification unavailable"}, status=503)
|
|
221
|
+
if result.is_blocked:
|
|
222
|
+
return JsonResponse({"error": "blocked"}, status=403)
|
|
223
|
+
if result.decision == "review":
|
|
224
|
+
return JsonResponse({"error": "additional verification required"}, status=409)
|
|
202
225
|
return self.get_response(request)
|
|
203
226
|
```
|
|
204
227
|
|
|
@@ -206,12 +229,12 @@ Runnable versions live in [`examples/`](./examples/).
|
|
|
206
229
|
|
|
207
230
|
## API
|
|
208
231
|
|
|
209
|
-
### `Sentinel(api_key=None, endpoint="https://
|
|
232
|
+
### `Sentinel(api_key=None, endpoint="https://maskbreak.com", timeout=5.0)`
|
|
210
233
|
|
|
211
234
|
| Option | Default | Description |
|
|
212
235
|
|--------|---------|-------------|
|
|
213
236
|
| `api_key` | `$SENTINEL_KEY` (falls back to `$SENTINEL_API_KEY`) | Your key starting with `sk_live_` |
|
|
214
|
-
| `endpoint` | `https://
|
|
237
|
+
| `endpoint` | `https://maskbreak.com` | Override base URL (for testing) |
|
|
215
238
|
| `timeout` | `5.0` | Per-request timeout in seconds |
|
|
216
239
|
|
|
217
240
|
### `sentinel.evaluate(token, fingerprint_event_id=None, account_id=None, email=None)`
|
|
@@ -222,31 +245,66 @@ Returns `EvaluateResult`. Raises `SentinelError` on network/API failure.
|
|
|
222
245
|
- `account_id` — your own user id for this session; enables multi-accounting detection (`device.linked_accounts` / `device.multi_account`).
|
|
223
246
|
- `email` — adds `email.disposable` to the raw response; burner domains escalate `allow` to `review`.
|
|
224
247
|
|
|
248
|
+
This synchronous SDK forwards only these named inputs. It does not expose a
|
|
249
|
+
timezone input, automatic retries, a circuit breaker, or every REST endpoint.
|
|
250
|
+
Device availability and `degraded` remain accessible through `raw`; missing
|
|
251
|
+
device evidence must not be treated as a clean device result. Account linking
|
|
252
|
+
(`linked_accounts`) is customer-scoped; device `first_seen`/`times_seen` history
|
|
253
|
+
is not customer-scoped.
|
|
254
|
+
|
|
225
255
|
### `sentinel.lookup(ip)`
|
|
226
256
|
|
|
227
257
|
Returns the raw response dict for any public IPv4/IPv6 address (wraps `GET /v1/lookup/{ip}`): `verdict` (`allow`/`review`/`block`), `risk_score` (0–100), `known`, `signals` (`{vpn, proxied, tor, dch, anon}` or `None`), `network` (`{asn, org, country, city}`), `latency_ms`. Shares the per-key hourly quota with `evaluate()`. `known: False` means our feeds hold no data — it is **not** a clean guarantee.
|
|
228
258
|
|
|
259
|
+
Production bare-IP lookup checks cloud ranges and Tor exits, not live-visit
|
|
260
|
+
VPN/proxy evidence. Legacy `vpn`/`proxied` keys in the shape do not imply those
|
|
261
|
+
checks ran. Use `evaluate()` with browser evidence for VPN/proxy checks. When
|
|
262
|
+
obtaining an IP behind a proxy, trust forwarded headers only from configured
|
|
263
|
+
trusted proxies; never blindly take the first client-supplied value.
|
|
264
|
+
|
|
229
265
|
## Testing
|
|
230
266
|
|
|
231
|
-
Deterministic
|
|
267
|
+
Deterministic `test_*` tokens exercise response handling, not detection quality.
|
|
268
|
+
SDK fixture calls use authentication and quota but do not increment billable
|
|
269
|
+
usage or trigger webhooks; console-originated live-key fixtures can be stored
|
|
270
|
+
as test events. Personal rules and exception pins can change fixture decisions.
|
|
232
271
|
|
|
233
272
|
```python
|
|
234
273
|
result = s.evaluate(token="test_vpn") # also: test_clean, test_proxy, test_datacenter, test_tor
|
|
235
|
-
assert result.decision == "review"
|
|
274
|
+
assert result.decision == "review" # default policy, no overriding rules/pins
|
|
236
275
|
assert result.test
|
|
237
276
|
```
|
|
238
277
|
|
|
239
278
|
No account yet? The public sandbox key accepts the same test tokens:
|
|
240
279
|
|
|
241
280
|
```python
|
|
242
|
-
s = Sentinel(api_key="sk_test_sandbox") #
|
|
281
|
+
s = Sentinel(api_key="sk_test_sandbox") # deterministic fixtures only, no live detection
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
The public sandbox is separately rate-limited, accepts only supported fixture
|
|
285
|
+
tokens, and does not store events or run live detection. It is not a production
|
|
286
|
+
allowance. A personal `sk_test_...` key runs the live pipeline with real browser
|
|
287
|
+
evidence and your policy; resulting events can be stored with `is_test` set,
|
|
288
|
+
without incrementing usage or firing webhooks. Test keys still have rate limits.
|
|
289
|
+
|
|
290
|
+
Local checks require no API credentials:
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
python -m unittest discover -s tests -v
|
|
294
|
+
python -m pip install build twine
|
|
295
|
+
python -m build
|
|
296
|
+
python -m twine check dist/*
|
|
243
297
|
```
|
|
244
298
|
|
|
245
|
-
|
|
299
|
+
The CI matrix targets Python 3.8–3.14 without raising the 3.8 minimum. A configured
|
|
300
|
+
matrix is not a claim that every interpreter was tested locally; inspect its run.
|
|
246
301
|
|
|
247
302
|
## Errors
|
|
248
303
|
|
|
249
|
-
|
|
304
|
+
Transport/API failures and unusable success responses raise `SentinelError`.
|
|
305
|
+
The exception carries `.status` (HTTP code) and `.body` (parsed error body) when
|
|
306
|
+
available. Redirects are rejected to avoid forwarding credentials. Configure the
|
|
307
|
+
final API base URL; the client does not retry automatically.
|
|
250
308
|
|
|
251
309
|
```python
|
|
252
310
|
from sentinel import Sentinel, SentinelError
|
|
@@ -259,15 +317,15 @@ except SentinelError as e:
|
|
|
259
317
|
elif e.status and 400 <= e.status < 500:
|
|
260
318
|
pass # bad input, won't recover by retrying
|
|
261
319
|
else:
|
|
262
|
-
pass #
|
|
320
|
+
pass # unknown outcome — use the endpoint's explicit fallback policy
|
|
263
321
|
```
|
|
264
322
|
|
|
265
323
|
## Rate limits
|
|
266
324
|
|
|
267
325
|
Free tier: **1,000 requests/hour** per API key. No monthly cap, no credit
|
|
268
|
-
card.
|
|
326
|
+
card.
|
|
269
327
|
|
|
270
|
-
## What
|
|
328
|
+
## What Maskbreak detects
|
|
271
329
|
|
|
272
330
|
VPNs (commercial + self-hosted) · residential proxies (Bright Data, IPRoyal,
|
|
273
331
|
and similar networks) · datacenter IPs · Tor exit nodes · antidetect browsers
|
|
@@ -277,10 +335,10 @@ virtual machines · browser tampering.
|
|
|
277
335
|
|
|
278
336
|
## Related
|
|
279
337
|
|
|
280
|
-
- **Node.js SDK** — [`@sentinelsup/sdk`](https://github.com/sentinelsup/
|
|
281
|
-
- **API docs** — [
|
|
282
|
-
- **Free IP lookup tool** — [
|
|
338
|
+
- **Node.js SDK** — [`@sentinelsup/sdk`](https://github.com/sentinelsup/maskbreak-node) on npm
|
|
339
|
+
- **API docs** — [maskbreak.com/api](https://maskbreak.com/api)
|
|
340
|
+
- **Free IP lookup tool** — [maskbreak.com/ip-lookup](https://maskbreak.com/ip-lookup)
|
|
283
341
|
|
|
284
342
|
## License
|
|
285
343
|
|
|
286
|
-
MIT © [Sentinel Edge Networks LTD](https://
|
|
344
|
+
MIT © [Sentinel Edge Networks LTD](https://maskbreak.com). See [LICENSE](LICENSE).
|