Case StudiesDocsBlogContact
Log InGet started
Developer Resources

Integrations & SDKs

Add fraud detection to any stack in under 5 minutes. Works with any language that can make HTTP requests — no proprietary SDK required.

< 40ms
Average global response time
Any lang
REST API works with any HTTP client
No SDK
Plain HTTP POST, zero dependencies

One endpoint. Full signal set.

A single POST request returns a decision, risk score, and all detection signals. No pagination, no setup, no webhooks required to get started. Full reference at /api.

Endpoint
Method POST
URL https://sntlhq.com/v1/evaluate
Auth Authorization: Bearer YOUR_API_KEY
Request { "token": "<token the client SDK injects into your form>", "fingerprintEventId": "<optional>" }
Response { "decision": "review", "risk_score": 71, "isSuspicious": true, "ip": "185.107.80.12", "country": "EE", "network": { "vpn": true, "proxy": false, "datacenter": true, "tor": false, "residential": false }, "reasons": ["vpn_detected", "datacenter_asn"], "evaluated_in_ms": 28 }

Pick your language

Copy-paste ready examples for the most common server-side languages. All examples show the full request/response flow with a block-or-pass pattern.

Official Node.js SDK npm install @sentinelsup/sdk npm ↗ · GitHub ↗
Node.js / JavaScript
// npm install @sentinelsup/sdk
const Sentinel = require('@sentinelsup/sdk');
const sentinel = new Sentinel({ apiKey: process.env.SENTINEL_KEY });

// token = the hidden "monocle" input the client SDK adds to your form
const result = await sentinel.evaluate({ token: req.body.sentinelToken });

if (result.decision === 'block') {
  return res.status(403).json({ error: 'Access denied' });
}
Python
import requests

response = requests.post(
    'https://sntlhq.com/v1/evaluate',
    headers={
        'Authorization': 'Bearer YOUR_API_KEY',
        'Content-Type': 'application/json'
    },
    # token = the hidden "monocle" input the client SDK adds to your form
    json={'token': request.json['sentinelToken']}
)
result = response.json()

if result['decision'] == 'block':
    return jsonify({'error': 'Access denied'}), 403
PHP
// token = the hidden "monocle" input the client SDK adds to your form
$response = file_get_contents('https://sntlhq.com/v1/evaluate', false, stream_context_create([
    'http' => [
        'method'  => 'POST',
        'header'  => "Authorization: Bearer YOUR_API_KEY\r\nContent-Type: application/json\r\n",
        'content' => json_encode([
            'token' => $_POST['sentinelToken']
        ])
    ]
]));
$result = json_decode($response, true);

if ($result['decision'] === 'block') {
    http_response_code(403);
    echo json_encode(['error' => 'Access denied']);
    exit;
}
Go
type EvaluateRequest struct {
    // Token = the hidden "monocle" input the client SDK adds to your form
    Token string `json:"token"`
}

func evaluate(token string) (*SentinelResult, error) {
    body, _ := json.Marshal(EvaluateRequest{Token: token})
    req, _ := http.NewRequest("POST", "https://sntlhq.com/v1/evaluate", bytes.NewReader(body))
    req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
    req.Header.Set("Content-Type", "application/json")

    resp, err := http.DefaultClient.Do(req)
    if err != nil { return nil, err }
    defer resp.Body.Close()

    var result SentinelResult
    json.NewDecoder(resp.Body).Decode(&result)
    return &result, nil
}
Ruby
require 'net/http'
require 'json'

uri  = URI('https://sntlhq.com/v1/evaluate')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

req = Net::HTTP::Post.new(uri.path)
req['Authorization'] = 'Bearer YOUR_API_KEY'
req['Content-Type']  = 'application/json'
# token = the hidden "monocle" input the client SDK adds to your form
req.body = { token: params[:sentinelToken] }.to_json

result = JSON.parse(http.request(req).body)

render json: { error: 'Access denied' }, status: 403 if result['decision'] == 'block'
Java
HttpClient client = HttpClient.newHttpClient();
// sentinelToken = the hidden "monocle" input the client SDK adds to your form
String body = String.format("{\"token\":\"%s\"}", sentinelToken);

HttpRequest httpRequest = HttpRequest.newBuilder()
    .uri(URI.create("https://sntlhq.com/v1/evaluate"))
    .header("Authorization", "Bearer YOUR_API_KEY")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(body))
    .build();

HttpResponse<String> response = client.send(httpRequest,
    HttpResponse.BodyHandlers.ofString());
JSONObject result = new JSONObject(response.body());

if ("block".equals(result.getString("decision"))) {
    response.setStatus(403);
    return Map.of("error", "Access denied");
}

Works with every framework

If your framework can make an outbound HTTP request, Sentinel works. No middleware, no plugins, no vendor lock-in.

NX
Next.js
Node / React
EX
Express.js
Node
FY
Fastify
Node
NS
NestJS
Node / TS
DJ
Django
Python
FA
FastAPI
Python
FL
Flask
Python
LV
Laravel
PHP
SF
Symfony
PHP
RR
Rails
Ruby
SB
Spring Boot
Java
GN
Gin
Go
EC
Echo
Go

Integrate with your platform

Step-by-step guides for Shopify, Stripe, iOS, and Android.

SH
Shopify
Protect checkout from card testing and bot signups

Step 1: Add the Sentinel SDK to your theme. In Shopify Admin → Online Store → Themes → Edit code → theme.liquid, add before </head>:

Liquid / HTML
<script async src="https://sntlhq.com/assets/edge.js" id="_mcl"></script>
<!-- add class="monocle-enriched" to your checkout/signup form;
     the SDK injects a hidden "monocle" token input automatically -->

Step 2: Create a serverless function (Shopify Functions or an external endpoint) that calls Sentinel before order creation:

Node.js — Shopify Webhook
// Called on orders/create webhook
const sentinel = await fetch('https://sntlhq.com/v1/evaluate', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.SENTINEL_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ token: req.body.sentinelToken })
});
const { isSuspicious } = await sentinel.json();
// If suspicious → flag order for review or cancel
if (isSuspicious) flagOrderForReview(order.id);
ST
Stripe
Block fraudulent payments before they hit your Stripe account

Check the customer with Sentinel before confirming a PaymentIntent. If suspicious, cancel the payment before it processes:

Node.js — Stripe Integration
const stripe = require('stripe')(process.env.STRIPE_SECRET);

app.post('/create-payment', async (req, res) => {
  // 1. Check with Sentinel first
  const check = await fetch('https://sntlhq.com/v1/evaluate', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.SENTINEL_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ token: req.body.sentinelToken })
  });
  const { isSuspicious } = await check.json();

  if (isSuspicious) {
    return res.status(403).json({ error: 'Payment blocked' });
  }

  // 2. Safe — create the PaymentIntent
  const intent = await stripe.paymentIntents.create({
    amount: req.body.amount,
    currency: 'usd',
    metadata: { sentinel_checked: 'true' }
  });
  res.json({ clientSecret: intent.client_secret });
});
SW
iOS (Swift)
Detect jailbroken devices and emulators from your iOS app

Call the Sentinel API from your backend when your iOS app submits a signup or login. The API detects VPNs, proxies, and suspicious devices:

Swift — URLSession
func checkWithSentinel(token: String) async throws -> Bool {
    var request = URLRequest(
        url: URL(string: "https://sntlhq.com/v1/evaluate")!
    )
    request.httpMethod = "POST"
    request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = try JSONEncoder().encode(["token": token])

    let (data, _) = try await URLSession.shared.data(for: request)
    let result = try JSONDecoder().decode(SentinelResponse.self, from: data)
    return result.isSuspicious
}

struct SentinelResponse: Decodable {
    let isSuspicious: Bool
}
KT
Android (Kotlin)
Detect emulators, rooted devices, and proxy traffic from Android

Call the Sentinel API from your Android app's backend. Use OkHttp or Retrofit to evaluate users at signup or login:

Kotlin — OkHttp
suspend fun checkWithSentinel(token: String): Boolean {
    val client = OkHttpClient()
    val json = JSONObject().put("token", token)

    val request = Request.Builder()
        .url("https://sntlhq.com/v1/evaluate")
        .addHeader("Authorization", "Bearer $apiKey")
        .addHeader("Content-Type", "application/json")
        .post(json.toString()
            .toRequestBody("application/json".toMediaType()))
        .build()

    val response = client.newCall(request).execute()
    val body = JSONObject(response.body!!.string())
    return body.getBoolean("isSuspicious")
}

Get your free API key

1,000 requests/hour free. No credit card required. Up and running in under 5 minutes.