Skip to content

Quickstart

This page takes you from nothing to one assessment and the three fields you act on. It takes about five minutes.

  1. Email [email protected] for a key. It starts with nrk_ and is shown once. Put it in your server’s environment and keep it out of browser and mobile code.

    Terminal window
    export NORESPONSE_API_KEY="nrk_..."

    The SDKs read NORESPONSE_API_KEY and call https://api.noresponse.org. You set nothing else.

  2. Terminal window
    npm install @noresponse/node

    Needs Node.js 20 or later. The package ships ESM and CommonJS builds.

  3. Call the API from the backend route that creates the account, before you create it. Send at least one of email, username or phone. name and ip make the answer sharper.

    Every create call carries an Idempotency-Key. Derive it from your own signup attempt id, so a retry of the same attempt reuses it. The SDKs generate one when you leave it out.

    signup.ts
    import { NoResponse } from "@noresponse/node";
    const nr = new NoResponse();
    const attemptId = "att_0001"; // your own id for this signup attempt
    const assessment = await nr.assessments.create(
    {
    accountId: "usr_8f2k1",
    identifiers: { email: "[email protected]", name: "Jordan Lee", ip: "81.2.69.160" },
    policyContext: { flow: "signup", region: "GB" },
    },
    { idempotencyKey: `signup-${attemptId}` },
    );
    console.log(assessment.status, assessment.risk?.score, assessment.risk?.recommendation);
  4. This is the answer the request above returns.

    {
    "schema_version": "1",
    "assessment_id": "asm_01M5FNFQWDRBZZMWBPN0WEC40C",
    "account_id": "usr_8f2k1",
    "status": "partial",
    "recommendation": "allow",
    "confidence": "medium",
    "risk": {
    "score": 8,
    "band": "low",
    "recommendation": "allow",
    "confidence": "medium",
    "policy_version": "risk-2026-10.8",
    "policy_basis": "heuristic_unvalidated",
    "reasons": [{ "code": "new_email", "weight": 8, "identifier": "email" }],
    "summary": {
    "email": { "disposable": false, "accounts_found": 0 },
    "ip": { "country": "GB", "type": "residential", "seen_in_tenant": 0 },
    "consistency": { "name": "unknown", "phone": "unknown", "ip": "unknown", "country": "consistent" }
    },
    "coverage": { "answered": 6, "failed": 0, "pending": 3 }
    },
    "incomplete_sources": [{ "lane": "accounts", "reason": "timed_out" }],
    "policy_version": "heuristic-2026-10.1",
    "policy_basis": "heuristic_unvalidated",
    "assessment_version": 1,
    "created_at": "2026-10-21T16:42:36.813Z",
    "updated_at": "2026-10-21T16:42:37.238Z",
    "expires_at": "2027-10-21T16:42:36.813Z",
    "assessment_url": "/v1/assessments/asm_01M5FNFQWDRBZZMWBPN0WEC40C",
    "timing": { "deadline_ms": 500, "elapsed_ms": 426 }
    }

    Read three fields first.

    • status is complete, partial or pending. Only complete and partial carry a recommendation. This answer is partial because the accounts lane did not answer in time, so the score can still move.
    • risk.recommendation is allow, step_up or review. Apply your own rules to it.
    • risk.reasons says why. Store it with your decision, together with policy_version and assessment_version.
  5. A pending answer has no recommendation. A timeout, a 429 or a 503 has none either. Choose a fallback for those cases now, before you go live. The two usual choices are to let the signup through and re-check it when the final assessment arrives, or to ask for a second factor. Assess signups and logins explains both.

    if (assessment.status === "pending") {
    applyFallback(); // your choice: let it through, or ask for a second factor
    const settled = await nr.assessments.wait(assessment.assessmentId, { timeoutMs: 10_000 });
    decide(settled);
    } else {
    decide(assessment);
    }