POST /api/public/v1/evaluate
Score a single action. Returns a decision, a risk score, and the signals behind it.
Endpoint
http
POST https://YOUR-APP.lovable.app/api/public/v1/evaluate
Authorization: Bearer vl_live_…
Content-Type: application/jsonRequest body
| Field | Type | Required | Description |
|---|---|---|---|
| userId | string | optional | Your own user ID. Strongly recommended — enables per-user behavior profiles. |
| ip | string | optional | Client IP (IPv4). Used for novelty, geo-jump, and VPN/Tor heuristics. |
| deviceId | string | optional | Stable device identifier from your client. |
| action | enum | required | login, api_call, payment, admin_action |
| userAgent | string | optional | Used for bot detection. |
Response
| Field | Type | Description |
|---|---|---|
| eventId | uuid | Use this to send feedback later. |
| riskScore | 0–100 | Higher = riskier. |
| decision | enum | ALLOW · REVIEW · STEP_UP_AUTH · BLOCK |
| confidence | 0–100 | How much the engine trusts this score — grows with data. |
| reasonSignals | string[] | Which signals fired. |
| signalContributions | object | Per-signal intensity, 0–1, used by feedback to target adjustments. |
| modelVersion | string | Workspace model version at scoring time, e.g. workspace-v14. |
Examples
curl
bash
curl -X POST https://YOUR-APP.lovable.app/api/public/v1/evaluate \
-H "Authorization: Bearer vl_live_…" \
-H "Content-Type: application/json" \
-d '{"userId":"u_42","ip":"203.0.113.7","deviceId":"d_xyz","action":"login"}'Browser fetch
javascript
const res = await fetch(
"https://YOUR-APP.lovable.app/api/public/v1/evaluate",
{
method: "POST",
headers: {
"Authorization": "Bearer vl_live_…",
"Content-Type": "application/json",
},
body: JSON.stringify({
userId: "u_42",
ip: "203.0.113.7",
deviceId: "d_xyz",
action: "login",
}),
},
);
const data = await res.json();
console.log(data.decision, data.riskScore);Node (server)
javascript
import { request } from "undici";
const { body } = await request(
"https://YOUR-APP.lovable.app/api/public/v1/evaluate",
{
method: "POST",
headers: {
authorization: `Bearer ${process.env.VERILOOP_KEY}`,
"content-type": "application/json",
},
body: JSON.stringify({ userId, ip, deviceId, action: "login" }),
},
);
const data = await body.json();Python
python
import requests, os
r = requests.post(
"https://YOUR-APP.lovable.app/api/public/v1/evaluate",
headers={
"Authorization": f"Bearer {os.environ['VERILOOP_KEY']}",
"Content-Type": "application/json",
},
json={
"userId": "u_42",
"ip": "203.0.113.7",
"deviceId": "d_xyz",
"action": "login",
},
timeout=5,
)
print(r.json()["decision"])PHP
php
<?php
$payload = json_encode([
"userId" => "u_42",
"ip" => "203.0.113.7",
"deviceId" => "d_xyz",
"action" => "login",
]);
$ch = curl_init("https://YOUR-APP.lovable.app/api/public/v1/evaluate");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("VERILOOP_KEY"),
"Content-Type: application/json",
],
]);
$response = json_decode(curl_exec($ch), true);
echo $response["decision"];Latency is typically under 100 ms once your workspace has a few hundred events. The first calls take a bit longer while the per-workspace cache warms.