[Engineering]2026-07-106 min
The Two-Call Model: Why We Split Evaluate and Signal
by AbuseGraph Engineering
The Problem with Single-Call Fraud Detection
Most fraud detection SDKs work like this:
Browser → Third-party API → Verdict
The browser sends data directly to a third party, gets a verdict, and the consumer app acts on it. Simple. But wrong.
Problems:
- The third party sees your users' PII (email, IP, fingerprint)
- The verdict can't be enriched with server-side data (breach checks, velocity)
- The browser can tamper with the verdict before the backend sees it
- You have a third-party dependency in your critical signup path
The Two-Call Model
AbuseGraph splits evaluation into two calls:
Call 1: Browser SDK → Edge Worker (evaluate)
- Fast edge path (no PII)
- Fingerprint + probes only
- Returns: signed verdict token + preliminary score
Call 2: Consumer Backend → Edge Worker (signal)
- Authoritative
- Enriches with: email breach check, disposable email, velocity, identity graph
- Returns: final verdict {score, verdict, riskSignals}
Call 1: Evaluate (Browser → Edge)
// Browser SDK
const data = await palisade.collect()
const result = await palisade.evaluate(data)
// result = { verdictToken, score: 25, verdict: 'allow' }
The browser sends fingerprint + behavioral + probe data. The edge worker computes a preliminary score and returns a signed HMAC verdict token. No PII crosses the wire.
Call 2: Signal (Backend → Edge)
// Consumer backend
const result = await palisade.signal({
verdictToken: token, // from the browser
email: 'user@example.com',
ip: '203.0.113.42'
})
// result = { score: 85, verdict: 'block', riskSignals: [...] }
The backend sends the verdict token + email + IP. The edge worker:
- Re-verifies the HMAC token (prevents tampering)
- Checks disposable email domains
- Checks velocity (sliding windows)
- Queries the identity graph
- Computes the final score
Why This Is Better
| Concern | Single-Call | Two-Call |
|---|---|---|
| PII exposure | Third party sees everything | Edge worker only sees PII in Call 2 |
| Enrichment | Limited to browser data | Full server-side data |
| Tamper resistance | Browser can modify verdict | HMAC token prevents tampering |
| Critical path | Third-party dependency | Self-hosted, no external dependency |
| Latency | One round trip | Two round trips (Call 1 stays PII-free and edge-local) |
The Verdict Token
The HMAC token is the bridge between the two calls:
// Edge worker signs the token
const token = signVerdictToken(
{ visitorId, score, verdict },
hmacSecret // only the edge worker and consumer backend know this
)
// Consumer backend re-verifies
const { valid, payload } = verifyVerdictToken(token, hmacSecret)
if (!valid) rejectSignup()
The token is:
- Short-lived (5 minute TTL)
- HMAC-SHA256 signed (constant-time comparison)
- Tamper-proof (any modification invalidates the signature)
Trade-offs
The two-call model adds ~50ms to the signup flow (Call 1 runs in parallel with form submission). In exchange, you get:
- Zero PII exposure to third parties
- Full server-side enrichment
- Tamper-proof verdicts
- Self-hosted infrastructure
For a security product, that tradeoff is clear.