- Skill ID
- sumsub/agent-skills/sumsub-integrate-dint-standalone
- Publisher
- sumsub
- Repository
- agent-skills
- Installs
- 0
- Files
- 8
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
sumsub/agent-skills/sumsub-integrate-dint-standaloneInstalls these files- README.md
- SKILL.md
- examples/behavior-token.sh
- examples/fisherman-react.tsx
- examples/fisherman-vanilla.html
- examples/submit-platform-event.sh
- references/standalone-flow.md
- scripts/preflight.sh
What this skill tells the agent
Sumsub — Device Intelligence standalone (no WebSDK)
Run Device Intelligence (DI) on your own pages that have no Sumsub verification widget — logins, signups, password resets, 2FA, checkouts. You embed the Fisherman JS module (npm @sumsub/fisherman) directly, capture the device on a user action, and confirm the action to Sumsub so it can screen for device fraud (bots, emulators, VPN/proxy, reused devices, multi-accounting).
This is Sumsub's ongoing-monitoring / pre-KYC path. If your page already shows the Sumsub WebSDK, stop — DI is built into it, use `sumsub-integrate-dint-websdk` instead.
⚠️ Sandbox tokens only
Do not accept or use a production App Token / secret during integration work. Insist on a sandbox pair from <https://cockpit.sumsub.com/checkus/home?sbx=true> — Connect Sumsub to your AI agent -> Build & configure -> Generate token. Token + secret are revealed once at creation; copy both before closing the dialog. The curl recipes here assume an sbx: token; the preflight enforces it with an sbx: prefix check. Deeper auth mechanics: `sumsub-api-auth`.
Before you start — fit DI into the existing app
DI should look like it was always part of their codebase — their framework, their components, their styling, their conventions. Don't scaffold over someone's app or introduce a new design system. Read enough of the repo to match it, then ask only what you can't infer:
- Which action to screen? The high-value submit to hook DI onto — login, signup, withdrawal, checkout, 2FA, password reset. (Show the ones you found in their routes/components as suggestions.)
- Where's the backend? The server file/route that can mint the behavior token and sign the Stage-3 confirm — HMAC must stay server-side. If they're frontend-only (SPA, no backend), flag that they need a server endpoint and offer to add a minimal one in their stack.
- Existing Sumsub footprint? Do they already call Sumsub / have App Token + secret wired, an
externalUserIdconvention, a webhook receiver? Reuse it; don't duplicate. - How are secrets / env handled? Match their existing pattern (
.env, secrets manager, config service) forSUMSUB_APP_TOKEN/SUMSUB_SECRET_KEY— sandbox values only during integration. - TypeScript or JS? Match the repo; don't add TS to a JS project or vice-versa.
Map the chosen action to its Stage-3 confirm event:
| Action | Stage-3 confirm event |
|---|---|
| Login / signup / password reset / 2FA | platform event |
| Money movement (transfer, withdrawal, deposit, payment) | platform event + financial txn |
| Pre-KYC signup where you also create the applicant | pre-KYC create-applicant |
| Guest / high-value checkout | financial txn |
Start with Stage 0 (preflight) to confirm the workspace has the DI entitlement before writing any code. Then implement Stages 1–4 against their files: a token route in their backend style, fisherman.fingerprint() on their existing submit handler (fail-open), the server-side confirm with the event mapped from the chosen action. Touch the minimum needed; follow surrounding code style.
The loop in one picture
┌─────────────────────────────┐ ┌──────────────────────────────────────┐
│ 1. Browser hits your page │─▶│ Your backend: POST .../accessTokens/ │
│ (login / signup form) │ │ behavior {sessionId} → {token} │
└─────────────┬───────────────┘ └──────────────────────────────────────┘
│ behavior access token
┌─────────────▼───────────────┐
│ 2. Browser: @sumsub/fisherman│ ← init(token) → fingerprint() on submit
│ captures the device │ returns { visitorId }
└─────────────┬───────────────┘
│ user submits (login succeeds / account created)
┌─────────────▼───────────────┐ ┌──────────────────────────────────────┐
│ 3. Your backend confirms the │─▶│ Sumsub runs DI analysis on the event │
│ event w/ captured device │ │ (platform event / txn / applicant) │
└─────────────┬───────────────┘ └──────────────────────────────────────┘
│ verdict + device signals
┌─────────────▼───────────────┐ ← Dashboard → Transactions (User
│ 4. You read results / act │ platform event); or webhook
└──────────────────────────────┘The headline: capturing the device is inert until you confirm the event server-side (Stage 3). Capturing alone produces no verdict — the confirm call is what makes Sumsub run the analysis.
Vocabulary (get these right — they're load-bearing)
| Term | What it is | Who sets it |
|---|---|---|
sessionId | The correlation key. Ties every fingerprint + event in one DI session together, and is the session the behavior token is minted with — so the Stage-3 confirm correlates the captured device to the event server-side, with no device fields in the body. | Your backend — generate one per logical session, opaque & unique. |
deviceBindingId | Optional alternative linking id. Sumsub is migrating device linking from sessionId to deviceBindingId; on the default flow it is not required. If you use it: pass it to fingerprint(), mint the token with it, and send it at applicant.device.deviceBindingId in the confirm body. | Your frontend — a fresh crypto.randomUUID() per action. |
linkedId | Optional — links the fingerprint to an entity (your user id / applicant id). | Frontend (optional). |
visitorId | The device identifier fingerprint() returns; surfaces in results. On the standalone confirm flow you do not forward it — the token's session ties the capture to the event. | Returned by Fisherman. |
Stage 0 — Preflight
`scripts/preflight.sh` machine-validates the workspace before you write any frontend code:
SUMSUB_APP_TOKEN=sbx:... SUMSUB_SECRET_KEY=... \
bash scripts/preflight.sh| Check | What it proves |
|---|---|
behavior_token | HMAC signing is accepted and Device Intelligence is enabled for this workspace — mints a real short-TTL behavior token (discarded, expires on its own; nothing else is mutated) |
levels | Verification levels exist. WARN-only — just the pre-KYC confirm path (create-applicant) needs one; platform events work without it |
Exit code: 0 on all-PASS / PASS+WARN, 10 on any FAIL. A 403 on behavior_token usually means the DI entitlement is off for the workspace — it's not self-serve; ask your CSM or support@sumsub.com to enable Device Intelligence, mentioning your clientId (Dashboard top-left) and environment (sandbox/production). Resolve all FAILs before Stage 1.
Stage 1 — Backend: mint a behavior access token
Separate endpoint from the WebSDK token — note the /behavior suffix and the JSON body:
POST https://api.sumsub.com/resources/accessTokens/behavior
Content-Type: application/json
{ "sessionId": "<your-session-id>", "ttlInSecs": 1800 }- Auth: App Token + HMAC. The body is part of the signature — sign
ts + "POST" + path + body(the empty-body shortcut from the WebSDK skill does not apply here). See `examples/behavior-token.sh`. - Response:
{ "token": "_act-jwt-..." }— the JWT is thetokenfield, notaccessToken. (Behavior tokens carry nouserId, unlike the WebSDK access-token endpoint.) - TTL defaults to 1800s. Mint on demand per session; don't cache globally.
Wire it as an auth-gated route on your backend (e.g. POST /api/di/token) that generates/looks up the sessionId, signs, calls Sumsub, and returns the response token to the browser.
Stage 2 — Frontend: capture the device with Fisherman
npm i @sumsub/fisherman --save// Shape only — the full impl (fail-open try/catch, React StrictMode teardown) is in
// examples/fisherman-vanilla.html and examples/fisherman-react.tsx.More from sumsub
Use this skill in a project
Open any RiverX project, search the Skills panel for sumsub/agent-skills/sumsub-integrate-dint-standalone, and install it in one click.
