Quickstart
This page takes you from nothing to one assessment and the three fields you act on. It takes about five minutes.
-
Set your API key
Section titled “Set your API key”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_KEYand callhttps://api.noresponse.org. You set nothing else. -
Install an SDK
Section titled “Install an SDK”Terminal window npm install @noresponse/nodeNeeds Node.js 20 or later. The package ships ESM and CommonJS builds.
Terminal window pip install noresponseNeeds Python 3.11 or later. Import it as
noresponse.Terminal window go get github.com/noresponsehq/go/v2Needs Go 1.24 or later. The root package is
noresponse.Nothing to install. Every SDK call is one HTTPS request.
-
Assess a signup
Section titled “Assess a signup”Call the API from the backend route that creates the account, before you create it. Send at least one of
email,usernameorphone.nameandipmake 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 attemptconst assessment = await nr.assessments.create({accountId: "usr_8f2k1",policyContext: { flow: "signup", region: "GB" },},{ idempotencyKey: `signup-${attemptId}` },);console.log(assessment.status, assessment.risk?.score, assessment.risk?.recommendation);signup.py from noresponse import NoResponseclient = NoResponse()attempt_id = "att_0001" # your own id for this signup attemptassessment = client.assessments.create(account_id="usr_8f2k1",policy_context={"flow": "signup", "region": "GB"},idempotency_key=f"signup-{attempt_id}",)risk = assessment.risk if assessment.status != "pending" else Noneprint(assessment.status, risk.score if risk else None, risk.recommendation if risk else None)main.go package mainimport ("context""fmt""log""os"noresponse "github.com/noresponsehq/go/v2""github.com/noresponsehq/go/v2/models/components")func main() {attemptID := "att_0001" // your own id for this signup attemptclient := noresponse.NewClient(os.Getenv("NORESPONSE_API_KEY"))res, err := client.Assessments.Create(context.Background(), "signup-"+attemptID, components.AssessmentRequest{AccountID: "usr_8f2k1",Identifiers: components.AssessmentRequestIdentifiers{Name: noresponse.Pointer("Jordan Lee"),IP: noresponse.Pointer("81.2.69.160"),},PolicyContext: &components.AssessmentRequestPolicyContext{Flow: noresponse.Pointer(components.FlowSignup),Region: noresponse.Pointer("GB"),},})if err != nil {log.Fatal(err)}assessment := res.Resultif assessment.Risk != nil {fmt.Println(assessment.Status, assessment.Risk.Score, assessment.Risk.Recommendation)} else {fmt.Println(assessment.Status)}}Terminal window curl https://api.noresponse.org/v1/assessments \-H "Authorization: Bearer $NORESPONSE_API_KEY" \-H "Content-Type: application/json" \-H "Idempotency-Key: signup-att_0001" \-d '{"account_id": "usr_8f2k1","identifiers": {"email": "[email protected]","name": "Jordan Lee","ip": "81.2.69.160"},"policy_context": { "flow": "signup", "region": "GB" }}' -
Read the answer
Section titled “Read the answer”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.
statusiscomplete,partialorpending. Onlycompleteandpartialcarry a recommendation. This answer ispartialbecause the accounts lane did not answer in time, so the score can still move.risk.recommendationisallow,step_uporreview. Apply your own rules to it.risk.reasonssays why. Store it with your decision, together withpolicy_versionandassessment_version.
-
Decide, and plan for pending
Section titled “Decide, and plan for pending”A
pendinganswer 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 factorconst settled = await nr.assessments.wait(assessment.assessmentId, { timeoutMs: 10_000 });decide(settled);} else {decide(assessment);}if assessment.status == "pending":apply_fallback() # your choice: let it through, or ask for a second factorsettled = client.assessments.wait(assessment.assessment_id, timeout=10.0)decide(settled)else:decide(assessment)if assessment.Status == components.StatusPending {applyFallback() // your choice: let it through, or ask for a second factorwaitCtx, cancel := context.WithTimeout(ctx, 10*time.Second)defer cancel()settled, err := noresponse.WaitForAssessment(waitCtx, client, assessment.AssessmentID, nil)if err != nil {log.Println(err)return}decide(settled)} else {decide(&assessment)}Terminal window # A 202 answer carries Location and Retry-After. Poll no faster than Retry-After says.curl https://api.noresponse.org/v1/assessments/asm_01M5FNFQWDRBZZMWBPN0WEC40C \-H "Authorization: Bearer $NORESPONSE_API_KEY"
Next steps
Section titled “Next steps”- Send the full request, with your auth session and client context, in Assess signups and logins.
- Copy the ordered rules in Turn an assessment into a decision.
- Receive the final answer with Webhooks.
- Tell NoResponse what the account turned out to be with Report outcomes.