Integrations
Integrate Radar
Radar looks at a sign-in attempt and returns a verdict: allow, challenge or block. Most of the signal comes from the request itself, so the common case needs no code at all — you turn rules on. This page covers that, plus the two places where a decision is worth taking into your own hands.
Before you begin
- A sign-in or sign-up flow already running through Paycux. Radar scores attempts it can see, so it sits behind AuthKit or the User Management API rather than beside them.
- A view of your current abuse pattern. Blocking is cheap; blocking the wrong people is expensive, so start from what you actually see in your logs.
- A step-up factor to challenge with. MFA or an email verification loop both work.
- If you run behind a proxy or CDN, correct client IP forwarding. A blocked signal is worthless if every request arrives from your own load balancer.
Install
Every example on this page uses the Node.js client. The same calls exist in the Python, Go, Ruby, PHP and Java SDKs, following the naming conventions of each language.
1npm i @paycux/node
Configure
Radar needs no keys of its own. It reads from the same environment as the rest of your integration; the only new value is the webhook secret used to verify risk events if you subscribe to them.
1PAYCUX_API_KEY=sk_example_7f4c1b9ad2e84c6f2PAYCUX_CLIENT_ID=client_01HQZX8N4T3PAYCUX_WEBHOOK_SECRET=whsec_example_2b6d9f31
Then, in the dashboard:
- 1Open Radar and switch it into observe mode. Nothing is blocked; every attempt is scored so you can see what a rule would have done.
- 2Turn on the detections that match your problem: credential stuffing, brute force, disposable email domains, impossible travel, or repeat trial sign-ups.
- 3Set the action per detection. Challenge is the right default for anything that can produce a false positive; block belongs to signals you are certain about.
- 4Add your own team's addresses and office ranges to the allow list so an internal test never trips a rule.
- 5After a few days of observing, switch the rules you trust into enforce mode one at a time.
Implement
In enforce mode Radar acts before your callback runs, so a blocked attempt simply never reaches you. The code below covers the two cases where you want the decision yourself: scoring an action of your own, and reacting to a risk event after the fact.
Score an action from your own server
Any sensitive action can be scored, not only sign-in. Pass the request context you have and branch on the verdict rather than on the raw score, so a change to your thresholds does not mean a deploy.
1import { Paycux } from "@paycux/node";23const paycux = new Paycux(process.env.PAYCUX_API_KEY);45export async function POST(request: Request) {6 const { userId, amount } = await request.json();78 const assessment = await paycux.radar.evaluate({9 action: "checkout",10 userId,11 ipAddress: request.headers.get("x-forwarded-for")?.split(",")[0],12 userAgent: request.headers.get("user-agent"),13 context: { amount },14 });1516 if (assessment.verdict === "block") {17 return Response.json({ error: "blocked", reason: assessment.reasons }, { status: 403 });18 }1920 if (assessment.verdict === "challenge") {21 return Response.json({ challenge: "mfa", assessmentId: assessment.id }, { status: 202 });22 }2324 return Response.json({ ok: true });25}
Resolve a challenge
When a challenge is satisfied, tell Radar. The outcome feeds the model and stops the same person being challenged again on the next request from the same device.
1import { Paycux } from "@paycux/node";23const paycux = new Paycux(process.env.PAYCUX_API_KEY);45export async function POST(request: Request) {6 const { assessmentId, factorId, code } = await request.json();78 const challenge = await paycux.mfa.verifyFactor({ factorId, code });910 await paycux.radar.resolve({11 assessmentId,12 outcome: challenge.valid ? "passed" : "failed",13 });1415 return Response.json({ ok: challenge.valid });16}
Handle risk events
Subscribe to risk events so your fraud queue and your product see the same picture. Verify the signature before you trust the body, and make the handler idempotent — a delivery can arrive twice.
1import { Paycux } from "@paycux/node";23const paycux = new Paycux(process.env.PAYCUX_API_KEY);45export async function POST(request: Request) {6 const payload = await request.text();7 const signature = request.headers.get("paycux-signature");89 const event = paycux.webhooks.verify({10 payload,11 signature,12 secret: process.env.PAYCUX_WEBHOOK_SECRET,13 });1415 if (await alreadyProcessed(event.id)) {16 return new Response("ok", { status: 200 });17 }1819 if (event.event === "radar.attempt_blocked") {20 await flagAccount(event.data.userId, event.data.reasons);21 }2223 await markProcessed(event.id);24 return new Response("ok", { status: 200 });25}
Verify
Radar is one of the few features where the interesting test is the negative one. Confirm that a legitimate person still gets through before you confirm that an abusive one does not.
- 1With observe mode on, sign in normally several times and check that every attempt is scored as allowed.
- 2Sign up with an address on a disposable domain and confirm the attempt is flagged, not silently accepted.
- 3Fail a password ten times in a row from the same address and confirm the brute-force rule fires at the threshold you set.
- 4Turn one rule into enforce mode and repeat the abusive case. The response should be a clean rejection, not a stack trace.
- 5Open Radar in the dashboard and read the attempt timeline: each entry names the rule, the signals and the action taken.
Reference
Request and response shapes for each of these live in the API reference. Paths are relative to https://api.paycux.com.
| Method | Path | What it does |
|---|---|---|
| POST | /radar/assessments | Score an action and receive a verdict with reasons. |
| GET | /radar/assessments/:id | Read one assessment, including the signals behind it. |
| POST | /radar/assessments/:id/resolve | Record how a challenge ended. |
| GET | /radar/attempts | List scored attempts, filtered by verdict, rule or user. |
| GET | /radar/rules | List the rules in the environment and their current mode. |
| PATCH | /radar/rules/:id | Move a rule between observe and enforce, or change its action. |
| POST | /radar/allowlist | Exempt an address, range or domain from scoring. |