curl --request POST \
--url 'https://api.noresponse.org/v1/assessments' \
--header "Authorization: Bearer $NORESPONSE_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: account-acct_7f3a9c' \
--data '{
"account_id": "acct_7f3a9c",
"flow": "account_creation",
"identifiers": {
"email": "new.user@example.com"
}
}'
import { NoResponse } from "@noresponse/node";
const noResponse = new NoResponse({
apiKey: process.env["NORESPONSE_API_KEY"] ?? "",
});
async function run() {
const result = await noResponse.assessments.create({
idempotencyKey: "account-acct_7f3a9c",
body: {
accountId: "acct_7f3a9c",
flow: "account_creation",
identifiers: {
email: "new.user@example.com",
},
},
});
console.log(result);
}
run();
from noresponse import NoResponse
import os
with NoResponse(
api_key=os.getenv("NORESPONSE_API_KEY", ""),
) as no_response:
res = no_response.assessments.create(idempotency_key="account-acct_7f3a9c", account_id="acct_7f3a9c", flow="account_creation", identifiers={
"email": "new.user@example.com",
}, policy_context={
"region": "AU",
}, request_id="req-2026-10-14-0001", client_context={
"timezone": "Australia/Sydney",
"locale": "en-AU",
"app_version": "4.12.0",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0 Safari/537.36",
"device_id": "dev_5c1e8a",
"session_id": "sess_9b2d41",
"client_observed_at": "2026-10-14T08:59:58.000Z",
}, auth_context={
"provider": "clerk",
"issuer": "https://example-app.clerk.accounts.dev",
"audience": "https://app.example.com",
"audiences": [
"https://app.example.com",
],
"subject": "user_2EXAMPLE",
"session_id": "sess_2EXAMPLE",
"organization_id": "org_2EXAMPLE",
"tenant_id": "tenant_2EXAMPLE",
"token_id": "2EXAMPLEJTI",
"issued_at": "2026-10-14T08:59:40.000Z",
"expires_at": "2026-10-14T09:00:40.000Z",
"session_created_at": "2026-10-14T08:57:00.000Z",
"auth_time": "2026-10-14T08:55:00.000Z",
"account_created_at": "2026-10-14T08:56:00.000Z",
"verified": False,
"mfa": {
"methods": [
"totp",
],
},
"roles": [
"admin",
],
"scopes": [
"org:sys_profile:manage",
],
}, issued_credential={
"sha256": "2bdbf5c72f2a36df0ef40fb92203612274d4546f56dba946070a6a79c2401a1b",
})
# Handle response
print(res)
package main
import(
"context"
"os"
noresponse "github.com/noresponsehq/go/v5"
"github.com/noresponsehq/go/v5/models/components"
"log"
)
func main() {
ctx := context.Background()
s := noresponse.New(
noresponse.WithSecurity(os.Getenv("NORESPONSE_API_KEY")),
)
res, err := s.Assessments.Create(ctx, "account-acct_7f3a9c", components.AssessmentRequest{
AccountID: "acct_7f3a9c",
Flow: components.FlowAccountCreation,
Identifiers: components.AssessmentRequestIdentifiers{
Email: noresponse.Pointer("new.user@example.com"),
},
})
if err != nil {
log.Fatal(err)
}
if res != nil {
// handle response
}
}
package hello.world;
import java.lang.Exception;
import org.noresponse.NoResponse;
import org.noresponse.models.errors.AuthenticationException;
import org.noresponse.models.errors.BadRequestException;
import org.noresponse.models.errors.ConflictException;
import org.noresponse.models.errors.NotFoundException;
import org.noresponse.models.errors.PermissionDeniedException;
import org.noresponse.models.errors.RateLimitException;
import org.noresponse.models.operations.CreateAssessmentResponse;
import org.noresponse.models.shared.AssessmentRequest;
import org.noresponse.models.shared.AssessmentRequestIdentifiers;
import org.noresponse.models.shared.Flow;
public class Application {
public static void main(String[] args) throws Exception {
NoResponse sdk = NoResponse.builder()
.apiKey(System.getenv().getOrDefault("NORESPONSE_API_KEY", ""))
.build();
CreateAssessmentResponse res = sdk.assessments().create()
.idempotencyKey("account-acct_7f3a9c")
.body(AssessmentRequest.builder()
.accountId("acct_7f3a9c")
.flow(Flow.ACCOUNT_CREATION)
.identifiers(AssessmentRequestIdentifiers.builder()
.email("new.user@example.com")
.build())
.build())
.call();
if (res.assessment().isPresent()) {
System.out.println(res.assessment().get());
}
}
}
using NoResponse;
using NoResponse.Models.Shared;
using System;
var sdk = new NoResponseClient(apiKey: Environment.GetEnvironmentVariable("NORESPONSE_API_KEY"));
var res = await sdk.Assessments.CreateAsync(
body: new AssessmentRequest() {
AccountId = "acct_7f3a9c",
Flow = Flow.AccountCreation,
Identifiers = new AssessmentRequestIdentifiers() {
Email = "new.user@example.com",
},
},
idempotencyKey: "account-acct_7f3a9c"
);
// handle response
<?php
declare(strict_types=1);
require 'vendor/autoload.php';
use NoResponse;
use NoResponse\Models\Shared;
$sdk = NoResponse\NoResponseClient::builder()
->setSecurity(
getenv('NORESPONSE_API_KEY') ?: ''
)
->build();
$body = new Shared\AssessmentRequest(
accountId: 'acct_7f3a9c',
flow: Shared\Flow::AccountCreation,
identifiers: new Shared\AssessmentRequestIdentifiers(
email: 'new.user@example.com',
),
);
$response = $sdk->assessments->create(
body: $body,
idempotencyKey: 'account-acct_7f3a9c'
);
if ($response->assessment !== null) {
// handle response
}
require 'noresponse'
Models = ::NoResponse::Models
s = ::NoResponse::NoResponseClient.new(
api_key: ENV.fetch('NORESPONSE_API_KEY', '')
)
res = s.assessments.create(body: Models::Shared::AssessmentRequest.new(
account_id: 'acct_7f3a9c',
flow: Models::Shared::Flow::ACCOUNT_CREATION,
identifiers: Models::Shared::AssessmentRequestIdentifiers.new(
email: 'new.user@example.com'
)
), idempotency_key: 'account-acct_7f3a9c')
unless res.nil?
# handle response
end
Create an assessment
Assesses one signup, login or purchase, named by flow. depth sets how long the answer waits: quick waits only for the sources that answer within 500 ms, full waits up to 3,000 ms. It defaults to full for signup and purchase and quick for login, and deadline_ms can lower either.
The answer leads with account, the account’s one current risk, and acts on account.risk.decision. The assessment’s own facts are under detail.
- 200 carries a
completeorpartialassessment withaccount. - 202 carries a
pendingassessment, plusLocationandRetry-After.accountis present only when an earlier assessment of the account was decided. Poll theLocationor wait for theassessment.updatedwebhook.
Apply your own fallback when account is absent, and for 429, 503 or a timeout. Never treat them as allow.
Idempotency-Key is required. A retry with the same key and body replays the latest state of the same assessment with Idempotent-Replayed: true and starts no new work. The same key with a different body answers 409 idempotency_key_reused. Keys are kept for 24 hours.
Requires the assess scope. response_mode: "detailed" also needs the detailed scope.
curl --request POST \
--url 'https://api.noresponse.org/v1/assessments' \
--header "Authorization: Bearer $NORESPONSE_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: account-acct_7f3a9c' \
--data '{
"account_id": "acct_7f3a9c",
"flow": "account_creation",
"identifiers": {
"email": "new.user@example.com"
}
}'
import { NoResponse } from "@noresponse/node";
const noResponse = new NoResponse({
apiKey: process.env["NORESPONSE_API_KEY"] ?? "",
});
async function run() {
const result = await noResponse.assessments.create({
idempotencyKey: "account-acct_7f3a9c",
body: {
accountId: "acct_7f3a9c",
flow: "account_creation",
identifiers: {
email: "new.user@example.com",
},
},
});
console.log(result);
}
run();
from noresponse import NoResponse
import os
with NoResponse(
api_key=os.getenv("NORESPONSE_API_KEY", ""),
) as no_response:
res = no_response.assessments.create(idempotency_key="account-acct_7f3a9c", account_id="acct_7f3a9c", flow="account_creation", identifiers={
"email": "new.user@example.com",
}, policy_context={
"region": "AU",
}, request_id="req-2026-10-14-0001", client_context={
"timezone": "Australia/Sydney",
"locale": "en-AU",
"app_version": "4.12.0",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0 Safari/537.36",
"device_id": "dev_5c1e8a",
"session_id": "sess_9b2d41",
"client_observed_at": "2026-10-14T08:59:58.000Z",
}, auth_context={
"provider": "clerk",
"issuer": "https://example-app.clerk.accounts.dev",
"audience": "https://app.example.com",
"audiences": [
"https://app.example.com",
],
"subject": "user_2EXAMPLE",
"session_id": "sess_2EXAMPLE",
"organization_id": "org_2EXAMPLE",
"tenant_id": "tenant_2EXAMPLE",
"token_id": "2EXAMPLEJTI",
"issued_at": "2026-10-14T08:59:40.000Z",
"expires_at": "2026-10-14T09:00:40.000Z",
"session_created_at": "2026-10-14T08:57:00.000Z",
"auth_time": "2026-10-14T08:55:00.000Z",
"account_created_at": "2026-10-14T08:56:00.000Z",
"verified": False,
"mfa": {
"methods": [
"totp",
],
},
"roles": [
"admin",
],
"scopes": [
"org:sys_profile:manage",
],
}, issued_credential={
"sha256": "2bdbf5c72f2a36df0ef40fb92203612274d4546f56dba946070a6a79c2401a1b",
})
# Handle response
print(res)
package main
import(
"context"
"os"
noresponse "github.com/noresponsehq/go/v5"
"github.com/noresponsehq/go/v5/models/components"
"log"
)
func main() {
ctx := context.Background()
s := noresponse.New(
noresponse.WithSecurity(os.Getenv("NORESPONSE_API_KEY")),
)
res, err := s.Assessments.Create(ctx, "account-acct_7f3a9c", components.AssessmentRequest{
AccountID: "acct_7f3a9c",
Flow: components.FlowAccountCreation,
Identifiers: components.AssessmentRequestIdentifiers{
Email: noresponse.Pointer("new.user@example.com"),
},
})
if err != nil {
log.Fatal(err)
}
if res != nil {
// handle response
}
}
package hello.world;
import java.lang.Exception;
import org.noresponse.NoResponse;
import org.noresponse.models.errors.AuthenticationException;
import org.noresponse.models.errors.BadRequestException;
import org.noresponse.models.errors.ConflictException;
import org.noresponse.models.errors.NotFoundException;
import org.noresponse.models.errors.PermissionDeniedException;
import org.noresponse.models.errors.RateLimitException;
import org.noresponse.models.operations.CreateAssessmentResponse;
import org.noresponse.models.shared.AssessmentRequest;
import org.noresponse.models.shared.AssessmentRequestIdentifiers;
import org.noresponse.models.shared.Flow;
public class Application {
public static void main(String[] args) throws Exception {
NoResponse sdk = NoResponse.builder()
.apiKey(System.getenv().getOrDefault("NORESPONSE_API_KEY", ""))
.build();
CreateAssessmentResponse res = sdk.assessments().create()
.idempotencyKey("account-acct_7f3a9c")
.body(AssessmentRequest.builder()
.accountId("acct_7f3a9c")
.flow(Flow.ACCOUNT_CREATION)
.identifiers(AssessmentRequestIdentifiers.builder()
.email("new.user@example.com")
.build())
.build())
.call();
if (res.assessment().isPresent()) {
System.out.println(res.assessment().get());
}
}
}
using NoResponse;
using NoResponse.Models.Shared;
using System;
var sdk = new NoResponseClient(apiKey: Environment.GetEnvironmentVariable("NORESPONSE_API_KEY"));
var res = await sdk.Assessments.CreateAsync(
body: new AssessmentRequest() {
AccountId = "acct_7f3a9c",
Flow = Flow.AccountCreation,
Identifiers = new AssessmentRequestIdentifiers() {
Email = "new.user@example.com",
},
},
idempotencyKey: "account-acct_7f3a9c"
);
// handle response
<?php
declare(strict_types=1);
require 'vendor/autoload.php';
use NoResponse;
use NoResponse\Models\Shared;
$sdk = NoResponse\NoResponseClient::builder()
->setSecurity(
getenv('NORESPONSE_API_KEY') ?: ''
)
->build();
$body = new Shared\AssessmentRequest(
accountId: 'acct_7f3a9c',
flow: Shared\Flow::AccountCreation,
identifiers: new Shared\AssessmentRequestIdentifiers(
email: 'new.user@example.com',
),
);
$response = $sdk->assessments->create(
body: $body,
idempotencyKey: 'account-acct_7f3a9c'
);
if ($response->assessment !== null) {
// handle response
}
require 'noresponse'
Models = ::NoResponse::Models
s = ::NoResponse::NoResponseClient.new(
api_key: ENV.fetch('NORESPONSE_API_KEY', '')
)
res = s.assessments.create(body: Models::Shared::AssessmentRequest.new(
account_id: 'acct_7f3a9c',
flow: Models::Shared::Flow::ACCOUNT_CREATION,
identifiers: Models::Shared::AssessmentRequestIdentifiers.new(
email: 'new.user@example.com'
)
), idempotency_key: 'account-acct_7f3a9c')
unless res.nil?
# handle response
end
Authorizations
Your API key, sent as Authorization: Bearer <key>. A key is nrk_live_ or nrk_test_, a 26-character key id, _ and a 43-character secret. A key sees only its own environment's data.
Each key has one or more scopes: assess creates and reads assessments, records outcomes and reports key usage; history reads assessments, an account's current risk and an account's history, and erases an account; detailed adds the detailed view; webhooks registers, tests, rotates and deletes webhook endpoints; integrations registers and manages hosted provider integrations. A missing, unknown, revoked or expired key answers 401. A valid key without the scope an operation needs answers 403.
Headers
Opaque client key, 16 to 128 characters of [A-Za-z0-9._:-] (a UUID or ULID fits). Scoped to the workspace principal and bound to the canonical body for 24 hours.
16 - 128^[A-Za-z0-9._:-]{16,128}$Body
POST /v1/assessments body. flow names the customer event (account_creation, login or purchase) and depth how long the answer waits for sources (quick or full, defaulting per flow). The workspace is resolved from the bearer credential only, so the body has no workspace field and refuses one like any other unknown member. At least one of email, username or phone is required; name and ip only refine an assessment. No field is defined for a password, token or breach value, and the only hash accepted is issued_credential.sha256. Unknown members are refused, and account_id, request_id and username refuse exact secret shapes; keeping secrets out of them beyond that is a provider obligation. Server-side normalisation: the email local part is kept exactly as received (case preserved, NFC only) and only the domain is lower-cased; no alias rewriting of any kind. The username is echoed as received and compared and digested in its match form: NFC, Unicode default case fold (str.casefold), NFC again, so JaneDoe and janedoe are one username. The whole body is capped at 32768 bytes, above the largest body these limits allow; a larger body answers 413 before parsing. Optional client_context accepts bounded timezone, locale, platform, app version, raw user-agent for parsing, workspace-scoped opaque device/session IDs, form duration and a client timestamp. These are untrusted, privacy-minimised hints; the server does not echo or expose raw user-agent/device/session values and does not treat a single mismatch as a denial. Optional auth_context carries normalized claims from a customer backend after it verifies its WorkOS, Clerk, Auth0 or other OIDC/session token; raw tokens and provider secrets are refused. account_id is required, except when auth_context comes from a provider hook at pre_registration (transport provider_hook, hook_point pre_registration), where no account exists yet; the assessment then carries a server-issued account_id, pre: followed by its assessment_id.
The customer event this assessment gates. Required. The answer's account.risk.decision is the decision for this flow, and the flow sets the default depth.
account_creation, login, purchase, signup At least one of email, username or phone. name and ip are matching inputs only, never looked up on their own, so a body with only name or ip (or neither) is refused with 400.
- Option 1
- Option 2
- Option 3
Show child attributes
Show child attributes
The provider's own opaque identifier for the account being checked, scoped to the calling workspace. It must be provider-opaque and must not contain a direct identifier (email, phone, name, national id): that is a provider obligation the schema can only partly check. '|' is accepted so an Auth0 user id such as 'auth0|64abc' passes unchanged; '@', '+', '$' and whitespace are refused by the pattern, as is an exact-shape JWT; a hex digest such as a SHA-256 is allowed, because hashing an internal id is a common pseudonymous scheme. A value such as '07700900123' or 'jane.doe.gmail.com' cannot be told apart from an opaque id. It travels in bodies, and in a URL only as the path segment of GET /v1/accounts/{account_id} and its /assessments. An assessment requested by a provider hook at pre_registration, which has no account yet, carries the server-issued account_id pre: followed by its assessment_id.
1 - 128^[A-Za-z0-9][A-Za-z0-9._:|-]{0,127}$Optional. Absent means the flow's default depth in the workspace's settings, which is full for account_creation and purchase and quick for login until changed.
quick, full Optional policy inputs: region.
Show child attributes
Show child attributes
An optional provider correlation id, echoed back. It is not an idempotency key. Refuses an exact-shape JWT or a bare 40, 64 or 128 character hex digest; a UUID is accepted.
1 - 128^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$Optional tighter budget, 50 to 3000 ms, measured from HTTP ingress including authentication, decoding, queueing and serialisation. Absent means the 3000 ms server ceiling; a value above the ceiling is refused with 400 rather than clamped.
50 <= x <= 3000standard returns the consolidated risk response; detailed adds merged provider-neutral facts when the key has detailed scope. raw is never available to a workspace.
standard, detailed Optional, customer-observed context from the client of the user. These values are untrusted hints: the server parses them into privacy-preserving features, never echoes raw user_agent or opaque IDs, and never treats one mismatch as a block decision.
Show child attributes
Show child attributes
Optional server-derived authentication context. The customer verifies its WorkOS, Clerk, Auth0 or other OIDC/session token before sending this object from its backend, or a provider hook (an Auth0 Action or a WorkOS Action) describes the event it was called for with transport provider_hook. No raw token or unverified browser claim is accepted. Values are opaque correlation inputs and bounded authentication-strength signals.
Show child attributes
Show child attributes
Optional. When your platform issues an API key to the new account, send SHA-256 of that key, so later usage of the key, or a leaked copy, ties back to this assessment. Each SDK has a helper that computes it. Send only the hash: customer keys are high-entropy, so the hash reveals nothing about them. The assessment stores it, and no response, webhook or log carries it.
Show child attributes
Show child attributes
Response
A complete or partial assessment. Retry-After is present while a source is still continuing.
The assessment resource: the body of POST /v1/assessments (200 complete or partial, 202 pending), GET /v1/assessments/{assessment_id} and the assessment.updated webhook. Its main object is account: the account's one current risk, as GET /v1/accounts/{account_id} serves it, with risk.decision the decision for this assessment's flow. detail holds this assessment's own facts and score. The account's current risk comes from its latest assessment that has a decision, which is this one once it has a decision and no newer one does, and an earlier one while this one is pending. Concurrent assessments of one account each answer the account's risk as committed when they are served.
Version of the body shape.
This assessment's id, equal to detail.assessment_id.
^asm_[0-9A-HJKMNP-TV-Z]{26}$This assessment's status, equal to detail.status. While it is pending, account carries the risk of the account's previous decided assessment, or is absent.
complete, partial The flow the request named. account.risk.decision is the decision for it. An assessment made before flows existed reports account_creation.
account_creation, login, purchase The depth the assessment was served at: the request's, or its flow's default. An assessment made before depths existed reports full.
quick, full This assessment's own facts: its score, recommendation, signals, coverage and timing.
Show child attributes
Show child attributes
The account's one current risk when this assessment was served, decided for this assessment's flow: the body GET /v1/accounts/{account_id} would answer, with risk.decision equal to decisions_by_flow for flow. Absent only while the account has no assessment with a decision (its first assessment is still pending); a webhook or GET of the decided assessment then carries it.
Show child attributes
Show child attributes