Test your integration
There is no separate sandbox host. You test against https://api.noresponse.org with a key issued for testing, and the answers come from the same sources your production traffic will use.
Get a key
Section titled “Get a key”Contact us at [email protected] with your company name and the scopes you need. We send you a key for testing, with the assess scope and any others you ask for. Keys are not self-serve yet. When you are ready for production traffic, ask for a production key the same way and keep the two in separate environments.
Which identifiers you may send
Section titled “Which identifiers you may send”Send identifiers you are allowed to use.
- Your own email addresses, usernames and phone numbers, and those of colleagues who have agreed.
- Addresses under
example.com, such as the[email protected]used throughout these docs. They look up as having no footprint. - Phone numbers in strict E.164 form, such as
+447700900123. A number with spaces or brackets is refused with a 400.
Test with your own identifiers or the ones above. The API refuses a value shaped like a credential hash or a JWT in username, account_id and request_id.
For ip, send a public address. The API refuses every private, loopback, link-local, multicast and documentation address with 400 invalid_request, and invalid_params names the field. That includes the documentation ranges 192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24 that other APIs use in examples. The docs on this site use 81.2.69.160, which is accepted and resolves to a residential address in GB. Your own egress address works too.
import { BadRequestError, NoResponse } from "@noresponse/node";
const nr = new NoResponse();try { await nr.assessments.create({ accountId: "usr_8f2k1", identifiers: { email: "[email protected]", ip: "203.0.113.10" } });} catch (error) { if (error instanceof BadRequestError) console.log(error.invalidParams); // [{ field: "identifiers.ip", reason: "not a public address" }]}from noresponse import BadRequestError, NoResponse
client = NoResponse()try: client.assessments.create(account_id="usr_8f2k1", identifiers={"email": "[email protected]", "ip": "203.0.113.10"})except BadRequestError as error: print(error.invalid_params) # [InvalidParam(field='identifiers.ip', reason='not a public address', example=None)]_, err := client.Assessments.Create(ctx, noresponse.NewIdempotencyKey(), components.AssessmentRequest{ AccountID: "usr_8f2k1", Identifiers: components.AssessmentRequestIdentifiers{ IP: noresponse.Pointer("203.0.113.10"), },})var bad *apierrors.BadRequestErrorif errors.As(err, &bad) { for _, param := range bad.InvalidParams { fmt.Println(param.Field, param.Reason) // identifiers.ip not a public address }}curl https://api.noresponse.org/v1/assessments \ -H "Authorization: Bearer $NORESPONSE_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: signup-7c1f0a2b-3d4e-4f5a-9b6c-1d2e3f4a5b6c" \ -d '{ "account_id": "usr_8f2k1", "identifiers": { "email": "[email protected]", "ip": "203.0.113.10" } }'{ "type": "https://docs.noresponse.org/problems/invalid-request", "title": "Invalid request", "status": 400, "detail": "The request does not match the assessment contract.", "code": "invalid_request", "request_id": "032f3d56a1b2c3d4e5f60718293a4b5c", "invalid_params": [{ "field": "identifiers.ip", "reason": "not a public address" }]}What to expect
Section titled “What to expect”The first answer for an identifier nobody has seen is usually partial. The accounts lane is the slowest, so it often misses the 500 ms deadline and appears in incomplete_sources as timed_out. The score then moves when it answers. Poll the assessment, or use the SDK wait helper, and compare assessment_version between the two answers. Pending, retries and idempotency shows how.
A phone number on its own answers 202 pending, because phone sources run only after the synchronous answer. Send an email or username beside it to get a recommendation in the first answer.
Test identities keep state inside your platform’s data. Assessing the same email a second time under a different account_id fires the seen_before reason, and the same ip within 24 hours raises summary.ip.seen_in_tenant. Use a fresh address and a fresh account_id when you want a clean first answer. Each assessment also keeps its Idempotency-Key bound for 24 hours, so a new attempt needs a new key.
Every answer carries an X-Request-ID header. Quote it when you write to us about a response.
Webhooks
Section titled “Webhooks”Endpoint registration is not self-serve either. Send us the URL of your receiver and we register it, then send you the key id and secret that sign deliveries. Until we do, you can test your receiver by signing deliveries yourself with the published test vector in Webhooks.