On this page

Risk scoring and agent trust API

Score a request, look up IP and device reputation, verify AI agents, and mint signed crawler vouchers from your server.

Call these operations from your own servers with an sk_ server API key (Authorization: Bearer sk_...). Every call is scoped to your organisation. Base URL: https://collect.noxtica.com (production, sk_prod_ keys).

Most operations need only the read:device scope, which every key carries by default. A Score API key created under Integrations & API is a server API key limited to read:device: it can call POST /v1/score and every other operation that needs only that scope. IP and device reputation (POST /v1/ip/reputation, POST /v1/verify/reputation) and agent verification are metered against your plan; the reputation module and Agent Passports are not enabled by default.

EnvironmentBase URL
Productionhttps://collect.noxtica.com

Credential: ApiKeyAuth. See Authentication.

How this page is organisedBar length shows each section’s share of the text. Select a section to jump to it.

Reputation

1 operation

Crawl Vouchers

1 operation

Agent Trust

3 operations

IP & Risk Scoring

2 operations

Operations in Risk scoring and agent trust API

Check email, website and phone reputation

POST /v1/verify/reputation

Evaluates the reputation of an email address, a website and/or a phone number supplied by your backend and returns a fused verdict. At least one of email, website or phone is required. The checks are bounded and fail open: a check that cannot complete contributes no signal instead of failing the call.

This operation is not enabled by default. When the reputation module is not enabled for your organisation the route answers the GatedNotFound 404, and it does so before the API key is checked. A served call counts toward your organisation’s reputation usage. Raw email and website values are not logged.

Authentication: Bearer token (ApiKeyAuth), scope read:reputation.

Request body

Content type application/json, required.

FieldTypeRequiredDescription
emailstringNo
websitestringNo
phonestringNo

Responses

StatusMeaningError codesContent
200The fused reputation verdict.application/json
400The request failed validation. error is a route-specific string such as Invalid body or invalid_request; read the operation description for the exact values it can return.Invalid bodyapplication/json ErrorEnvelope
401The Authorization: Bearer sk_... header is missing or malformed, or the key is unknown, revoked, or belongs to a suspended or deleted organisation. The body is deliberately identical for every cause.invalid_api_keyapplication/json InvalidApiKeyError
403The API key is valid but does not carry the scope this operation requires; error names the missing scope.API key does not have read:device scopeapplication/json ScopeForbiddenError
404The byte-identical “V1 endpoint not found” response returned when the route’s module is not enabled for your organisation, and also for a path that does not exist — indistinguishable by design (anti-enumeration), so do not treat it as proof the path is wrong.V1 endpoint not foundapplication/json
429Rate limit exceeded. Wait Retry-After seconds (also retryAfter in the body) before retrying; the response carries no other rate-limit headers.Rate limit exceededapplication/json
500Unexpected server fault. Retry with backoff and quote requestId to support if it persists.Internal server errorapplication/json ErrorEnvelope

Response headers

StatusHeaderTypeDescription
429Retry-AfterintegerSeconds until the bucket allows another request.

Response fields (200, application/json)

FieldTypeAlways returnedDescription
okbooleanYesAllowed values: true.
verdictstringYes
signalsobjectYesPer-signal sub-scores from evaluateReputation; the engine’s internal signal-shape union is not locally re-validated by this handler.
confidencenumberYes

Response example (200)

{
  "ok": true,
  "verdict": "example-verdict",
  "signals": {},
  "confidence": 1
}

Example request

curl

curl -X POST "https://collect.noxtica.com/v1/verify/reputation" \
  -H "Authorization: Bearer $NOXTICA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Node.js (global fetch, Node 18 or later)

const response = await fetch('https://collect.noxtica.com/v1/verify/reputation', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.NOXTICA_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({}),
});
console.log(response.status, await response.text());

Python (standard library)

import json
import os
import urllib.request

request = urllib.request.Request(
    "https://collect.noxtica.com/v1/verify/reputation",
    data=json.dumps({}).encode(),
    headers={
        "Authorization": f"Bearer {os.environ['NOXTICA_API_KEY']}",
        "Content-Type": "application/json",
    },
    method="POST",
)
with urllib.request.urlopen(request) as response:
    print(response.status, response.read().decode())

Mint a crawler-access voucher

POST /v1/crawl/vouchers

Mints a signed, stateless voucher that a verified crawler (identified by agentKey) presents to your Noxtica edge to satisfy a charge pricing rule. The edge verifies only the signature and binding. The response’s header field names the request header that carries the voucher.

The voucher is always scoped to the organisation that owns the API key; a tenant id in the body is never used. The route is fail-closed: it answers 503 when no signing key is available and never emits an unsigned voucher.

Payment capture is not part of this operation. It does not verify that a payment was taken; it only checks that a payment reference (paymentRef in the body, or the payment-reference request header) is present, and only requires one when your deployment is configured to. Outstanding vouchers are capped per month, and the cap is claimed only after the voucher has been signed, so a signing failure never consumes it.

Authentication: Bearer token (ApiKeyAuth), scope write:crawl_voucher.

Parameters

NameInTypeRequiredDescription
X-Nox-Payment-RefheaderstringNoAlternative to the body’s paymentRef; operator-attested, not independently verified this iteration.

Request body

Content type application/json, required.

FieldTypeRequiredDescription
agentKeystringYesThe crawler identity this voucher pays for (’*’ = the catch-all pricing rule). At most 256 characters.
ttlSecondsintegerNoMinimum 60, maximum 86400. Default 3600.
paymentRefstringNoOperator-attested payment reference; presence-only checked.

Responses

StatusMeaningError codesContent
200The minted voucher.application/json
400agentKey (non-empty string) is required, or Invalid JSON body.invalid_requestapplication/json ErrorEnvelope
401The Authorization: Bearer sk_... header is missing or malformed, or the key is unknown, revoked, or belongs to a suspended or deleted organisation. The body is deliberately identical for every cause.invalid_api_keyapplication/json InvalidApiKeyError
402Payment context required — returned only when the deployment requires a payment reference and neither paymentRef nor the payment-reference header was supplied.invalid_requestapplication/json ErrorEnvelope
403The API key is valid but does not carry the scope this operation requires; error names the missing scope.API key does not have read:device scopeapplication/json ScopeForbiddenError
413The request body exceeded this route’s byte cap.body_too_largeapplication/json ErrorEnvelope
415Content-Type must be application/json.invalid_requestapplication/json ErrorEnvelope
429Rate limit exceeded. Wait Retry-After seconds (also retryAfter in the body) before retrying; the response carries no other rate-limit headers.Rate limit exceededapplication/json
500Unexpected server fault. Retry with backoff and quote requestId to support if it persists.Internal server errorapplication/json ErrorEnvelope
503Crawl voucher minting is not configured (no signing key is available) or Voucher quota authority unavailable.invalid_requestapplication/json ErrorEnvelope

Response headers

StatusHeaderTypeDescription
429Retry-AfterintegerSeconds until the bucket allows another request.

Response fields (200, application/json)

FieldTypeAlways returnedDescription
okbooleanYesAllowed values: true.
voucherstringYes<base64url(payload)>.<base64url(hmac)>, or the HMAC-signing-trust envelope form when that feature is armed.
expiresAtintegerYesEpoch seconds.
headerstringYesAllowed values: X-Nox-Crawl-Voucher.

Response example (200)

{
  "ok": true,
  "voucher": "example-voucher",
  "expiresAt": 1768435200,
  "header": "X-Nox-Crawl-Voucher"
}

Example request

curl

curl -X POST "https://collect.noxtica.com/v1/crawl/vouchers" \
  -H "Authorization: Bearer $NOXTICA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "agentKey": "example-agentKey",
  "ttlSeconds": 3600,
  "paymentRef": "example-paymentRef"
}'

Node.js (global fetch, Node 18 or later)

const response = await fetch('https://collect.noxtica.com/v1/crawl/vouchers', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.NOXTICA_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    agentKey: 'example-agentKey',
    ttlSeconds: 3600,
    paymentRef: 'example-paymentRef',
  }),
});
console.log(response.status, await response.text());

Python (standard library)

import json
import os
import urllib.request

request = urllib.request.Request(
    "https://collect.noxtica.com/v1/crawl/vouchers",
    data=json.dumps({
        "agentKey": "example-agentKey",
        "ttlSeconds": 3600,
        "paymentRef": "example-paymentRef",
    }).encode(),
    headers={
        "Authorization": f"Bearer {os.environ['NOXTICA_API_KEY']}",
        "Content-Type": "application/json",
    },
    method="POST",
)
with urllib.request.urlopen(request) as response:
    print(response.status, response.read().decode())

Issue a signed Agent Passport (GET)

GET /v1/agent/passport

Runs the same Web Bot Auth verdict as POST /v1/agent/verify (RFC 9421 signature verification plus your organisation’s agent policy registry) and returns one ES256-signed, offline-verifiable envelope. Verify the signature against the published JWKS (GET /.well-known/noxtica/agent-passport-jwks.json, falling back to /.well-known/noxtica/jwks.json) by kid; no round trip to Noxtica is needed.

The GET form reads only the three Web Bot Auth headers of the incoming request (signature-input, signature, signature-agent) and an optional forwarded attestation from the query parameters tier, anchored, riskBand and jti. sub is set only for a cryptographically verified verdict; every other verdict carries sub: null. An unverified allow is withheld or downgraded before signing.

Availability. Agent Passports are not enabled by default. When they are not enabled for the deployment the route answers 404 {"error":"Not found"}, a different body from the usual V1 endpoint not found; when your organisation has not opted into agent verification it answers 403 {"error":"feature disabled"}. The route shares its rate-limit bucket with POST /v1/agent/verify, and a verified issuance counts toward your agent-verification usage.

Authentication: Bearer token (ApiKeyAuth), scope read:device.

Parameters

NameInTypeRequiredDescription
urlquerystring (uri)NoThe signed target URI @authority is reconstructed from; degrades to the request’s own URL when absent/malformed.
tierquerystringNoOptional caller-forwarded attestation tier; a non-member value is silently dropped (fail-open). Allowed values: hardware, software, suspicious, unavailable, failed.
anchoredquerystringNoOptional caller-forwarded “server-anchored single-use claim succeeded” flag; only the literal string true is honoured. Allowed values: true, false.
riskBandquerystringNoAllowed values: critical, high, medium, low, minimal.
jtiquerystringNoOPTIONAL caller-forwarded device-correlation id, echoed back as the passport’s untrusted cid (never the server-minted replay jti).

Responses

StatusMeaningError codesContent
200The ES256-signed Agent Passport envelope (SignedEnvelope<AgentPassportPayload>). A tenant backend verifies this OFFLINE against the published JWKS by kid — no round-trip to Noxtica is required.application/json
401The Authorization: Bearer sk_... header is missing or malformed, or the key is unknown, revoked, or belongs to a suspended or deleted organisation. The body is deliberately identical for every cause.invalid_api_keyapplication/json InvalidApiKeyError
403Your organisation has not opted into agent verification (feature disabled).feature disabledapplication/json
404Agent Passports are not enabled for this deployment. The body is {"error":"Not found"}, returned before the API key is checked.Not foundapplication/json
429Rate limit exceeded. Wait Retry-After seconds (also retryAfter in the body) before retrying; the response carries no other rate-limit headers.Rate limit exceededapplication/json
500Unexpected fault; the handler otherwise never throws.invalid_requestapplication/json ErrorEnvelope
503The signing key is unavailable or invalid (fail-closed: there is no silent fallback to another key).invalid_requestapplication/json ErrorEnvelope

Response headers

StatusHeaderTypeDescription
429Retry-AfterintegerSeconds until the bucket allows another request.

Response fields (200, application/json)

FieldTypeAlways returnedDescription
algstringYesAllowed values: ES256.
kidstringYes
iatintegerYesEpoch seconds.
expintegerNoEpoch seconds; the signed expiry window (== the payload ttl).
kvintegerNoOPTIONAL signing key-version; present only when the trust-lifecycle signer is in use.
spvintegerNoOPTIONAL signing-policy-version; same presence contract as kv.
sigstringYesbase64url ES256 signature over the payload.
payloadobjectYes
payload.typstringYesAllowed values: agent-passport.
payload.issstringYesAllowed values: noxtica.
payload.audstringYesThe authenticated tenant id (audience binding).
payload.pvintegerYesPassport schema version: 1 = legacy claims, 2 = explicit callerAsserted trust marker (when enabled for the deployment). Allowed values: 1, 2.
payload.verdictstringYesAllowed values: verified, unsigned, invalid_signature, expired, replay.
payload.attestationobjectYes
payload.attestation.tierstringNoAllowed values: hardware, software, suspicious, unavailable, failed.
payload.attestation.anchoredbooleanNo
payload.attestation.provenancestringNoAllowed values: caller_attested.
payload.callerAssertedbooleanNoPresent only when pv:2. Allowed values: true.
payload.riskBandstringYesAllowed values: critical, high, medium, low, minimal.
payload.policyActionstring, nullableYesAllowed values: allow, deny.
payload.graduatedActionstringNoPresent only when graduated agent policy is enabled for your organisation. Allowed values: allow, observe, challenge, deny.
payload.jtistring (uuid)YesSERVER-MINTED per-issuance id — the consumer MUST reject a repeated jti (replay).
payload.substring, nullableYesThe verified subject (keyid, else the signature-agent host); null unless verdict is ‘verified’.
payload.tenantIdstringYes
payload.cidstring, nullableYesOPTIONAL untrusted caller-forwarded correlation id — never the replay id.
payload.disclosureobject, nullableYes
payload.disclosure.requiredbooleanNoAllowed values: true.
payload.disclosure.regulationstringNoAllowed values: eu_ai_act_art_50.
payload.disclosure.obligationstringNo
payload.disclosure.agentVerifiedbooleanNo
payload.issuedAtstring (date-time)Yes
payload.ttlintegerYesSeconds; the signed envelope exp window.

Response example (200)

{
  "alg": "ES256",
  "kid": "kid-2026-09",
  "iat": 1,
  "exp": 1,
  "kv": 1,
  "spv": 1,
  "sig": "example-sig",
  "payload": {
    "typ": "agent-passport",
    "iss": "noxtica",
    "aud": "example-aud",
    "pv": 1,
    "verdict": "verified",
    "attestation": {
      "tier": "hardware",
      "anchored": true,
      "provenance": "caller_attested"
    },
    "callerAsserted": true,
    "riskBand": "critical",
    "policyAction": "allow",
    "graduatedAction": "allow",
    "jti": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "sub": "example-sub",
    "tenantId": "tenant_42",
    "cid": "example-cid",
    "disclosure": {
      "required": true,
      "regulation": "eu_ai_act_art_50",
      "obligation": "example-obligation",
      "agentVerified": true
    },
    "issuedAt": "2026-09-13T12:00:00.000Z",
    "ttl": 1
  }
}

Example request

curl

curl "https://collect.noxtica.com/v1/agent/passport" \
  -H "Authorization: Bearer $NOXTICA_API_KEY"

Node.js (global fetch, Node 18 or later)

const response = await fetch('https://collect.noxtica.com/v1/agent/passport', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.NOXTICA_API_KEY}`,
  },
});
console.log(response.status, await response.text());

Python (standard library)

import os
import urllib.request

request = urllib.request.Request(
    "https://collect.noxtica.com/v1/agent/passport",
    headers={
        "Authorization": f"Bearer {os.environ['NOXTICA_API_KEY']}",
    },
    method="GET",
)
with urllib.request.urlopen(request) as response:
    print(response.status, response.read().decode())

Issue a signed Agent Passport (POST)

POST /v1/agent/passport

Same verdict and signing pipeline as GET /v1/agent/passport; the POST form lets your backend forward the signature material in the JSON body instead of request headers, like POST /v1/agent/verify. The same availability rules, error responses, rate-limit bucket and usage counting apply.

Authentication: Bearer token (ApiKeyAuth), scope read:device.

Request body

Content type application/json, optional.

FieldTypeRequiredDescription
headersobjectNoThe forwarded Web Bot Auth signature headers (signature-input, signature, signature-agent, lower-cased keys); non-string values are dropped.
headers.*stringNo
urlstring (uri)NoThe signed target URI; a malformed value degrades to the request’s own URL.
methodstringNoThe signed HTTP method the signature covers; defaults to GET when omitted/blank.
attestationobjectNo
attestation.tierstringNoAllowed values: hardware, software, suspicious, unavailable, failed.
attestation.anchoredbooleanNo
riskBandstringNoAllowed values: critical, high, medium, low, minimal.
jtistringNoOPTIONAL caller-forwarded device-correlation id, echoed back as the passport’s untrusted cid.

Responses

StatusMeaningError codesContent
200The ES256-signed Agent Passport envelope (SignedEnvelope<AgentPassportPayload>). A tenant backend verifies this OFFLINE against the published JWKS by kid — no round-trip to Noxtica is required.application/json
401The Authorization: Bearer sk_... header is missing or malformed, or the key is unknown, revoked, or belongs to a suspended or deleted organisation. The body is deliberately identical for every cause.invalid_api_keyapplication/json InvalidApiKeyError
403Your organisation has not opted into agent verification (feature disabled).feature disabledapplication/json
404Agent Passports are not enabled for this deployment. The body is {"error":"Not found"}, returned before the API key is checked.Not foundapplication/json
413Payload too large — the request body exceeded the size limit.invalid_requestapplication/json ErrorEnvelope
429Rate limit exceeded. Wait Retry-After seconds (also retryAfter in the body) before retrying; the response carries no other rate-limit headers.Rate limit exceededapplication/json
500Unexpected fault.invalid_requestapplication/json ErrorEnvelope
503The signing key is unavailable or invalid (fail-closed: there is no silent fallback to another key).invalid_requestapplication/json ErrorEnvelope

Response headers

StatusHeaderTypeDescription
429Retry-AfterintegerSeconds until the bucket allows another request.

Response fields (200, application/json)

FieldTypeAlways returnedDescription
algstringYesAllowed values: ES256.
kidstringYes
iatintegerYesEpoch seconds.
expintegerNoEpoch seconds; the signed expiry window (== the payload ttl).
kvintegerNoOPTIONAL signing key-version; present only when the trust-lifecycle signer is in use.
spvintegerNoOPTIONAL signing-policy-version; same presence contract as kv.
sigstringYesbase64url ES256 signature over the payload.
payloadobjectYes
payload.typstringYesAllowed values: agent-passport.
payload.issstringYesAllowed values: noxtica.
payload.audstringYesThe authenticated tenant id (audience binding).
payload.pvintegerYesPassport schema version: 1 = legacy claims, 2 = explicit callerAsserted trust marker (when enabled for the deployment). Allowed values: 1, 2.
payload.verdictstringYesAllowed values: verified, unsigned, invalid_signature, expired, replay.
payload.attestationobjectYes
payload.attestation.tierstringNoAllowed values: hardware, software, suspicious, unavailable, failed.
payload.attestation.anchoredbooleanNo
payload.attestation.provenancestringNoAllowed values: caller_attested.
payload.callerAssertedbooleanNoPresent only when pv:2. Allowed values: true.
payload.riskBandstringYesAllowed values: critical, high, medium, low, minimal.
payload.policyActionstring, nullableYesAllowed values: allow, deny.
payload.graduatedActionstringNoPresent only when graduated agent policy is enabled for your organisation. Allowed values: allow, observe, challenge, deny.
payload.jtistring (uuid)YesSERVER-MINTED per-issuance id — the consumer MUST reject a repeated jti (replay).
payload.substring, nullableYesThe verified subject (keyid, else the signature-agent host); null unless verdict is ‘verified’.
payload.tenantIdstringYes
payload.cidstring, nullableYesOPTIONAL untrusted caller-forwarded correlation id — never the replay id.
payload.disclosureobject, nullableYes
payload.disclosure.requiredbooleanNoAllowed values: true.
payload.disclosure.regulationstringNoAllowed values: eu_ai_act_art_50.
payload.disclosure.obligationstringNo
payload.disclosure.agentVerifiedbooleanNo
payload.issuedAtstring (date-time)Yes
payload.ttlintegerYesSeconds; the signed envelope exp window.

Response example (200)

{
  "alg": "ES256",
  "kid": "kid-2026-09",
  "iat": 1,
  "exp": 1,
  "kv": 1,
  "spv": 1,
  "sig": "example-sig",
  "payload": {
    "typ": "agent-passport",
    "iss": "noxtica",
    "aud": "example-aud",
    "pv": 1,
    "verdict": "verified",
    "attestation": {
      "tier": "hardware",
      "anchored": true,
      "provenance": "caller_attested"
    },
    "callerAsserted": true,
    "riskBand": "critical",
    "policyAction": "allow",
    "graduatedAction": "allow",
    "jti": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "sub": "example-sub",
    "tenantId": "tenant_42",
    "cid": "example-cid",
    "disclosure": {
      "required": true,
      "regulation": "eu_ai_act_art_50",
      "obligation": "example-obligation",
      "agentVerified": true
    },
    "issuedAt": "2026-09-13T12:00:00.000Z",
    "ttl": 1
  }
}

Example request

curl

curl -X POST "https://collect.noxtica.com/v1/agent/passport" \
  -H "Authorization: Bearer $NOXTICA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "headers": {
    "key": "example-headers"
  },
  "url": "https://verify.noxtica.com/s/kycs.tenant_42.9f3a8b7c6d5e4f3a2b1c0d9e8f7a6b5c",
  "method": "example-method",
  "attestation": {
    "tier": "hardware",
    "anchored": true
  },
  "riskBand": "critical",
  "jti": "example-jti"
}'

Node.js (global fetch, Node 18 or later)

const response = await fetch('https://collect.noxtica.com/v1/agent/passport', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.NOXTICA_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    headers: {
      key: 'example-headers',
    },
    url: 'https://verify.noxtica.com/s/kycs.tenant_42.9f3a8b7c6d5e4f3a2b1c0d9e8f7a6b5c',
    method: 'example-method',
    attestation: {
      tier: 'hardware',
      anchored: true,
    },
    riskBand: 'critical',
    jti: 'example-jti',
  }),
});
console.log(response.status, await response.text());

Python (standard library)

import json
import os
import urllib.request

request = urllib.request.Request(
    "https://collect.noxtica.com/v1/agent/passport",
    data=json.dumps({
        "headers": {
            "key": "example-headers",
        },
        "url": "https://verify.noxtica.com/s/kycs.tenant_42.9f3a8b7c6d5e4f3a2b1c0d9e8f7a6b5c",
        "method": "example-method",
        "attestation": {
            "tier": "hardware",
            "anchored": True,
        },
        "riskBand": "critical",
        "jti": "example-jti",
    }).encode(),
    headers={
        "Authorization": f"Bearer {os.environ['NOXTICA_API_KEY']}",
        "Content-Type": "application/json",
    },
    method="POST",
)
with urllib.request.urlopen(request) as response:
    print(response.status, response.read().decode())

Verify a Web Bot Auth agent signature

POST /v1/agent/verify

Your backend forwards an incoming request’s signature headers and target URL. Noxtica verifies the Web Bot Auth (RFC 9421) signature and joins the verdict to your organisation’s agent policy registry for an allow or deny decision.

Verification fails open end to end: any fault yields verdict unsigned and matchedAction: null. The endpoint is advisory and never blocks an agent itself. A structurally matched but unverified identity can never receive a binary allow (it is withheld to null), and a graduated allow is downgraded to challenge.

Some response fields are additive and appear only when the matching capability is enabled for your organisation: kya and policyAction (the graduated ladder) and disclosure (EU AI Act Article 50 disclosure, only for a detected or verified agent).

Authentication: Bearer token (ApiKeyAuth), scope read:device.

Request body

Content type application/json, required.

FieldTypeRequiredDescription
headersobjectYesThe forwarded Web Bot Auth signature headers (signature-input, signature, signature-agent).
headers.*stringNo
urlstring (uri)NoThe signed target URI the signature covers.
attestationobjectNo
attestation.tierstringNoAllowed values: hardware, software, suspicious, unavailable, failed.
attestation.anchoredbooleanNo
riskBandstringNoAllowed values: critical, high, medium, low, minimal.
jtistringNoDevice-correlated token id; when graduated agent policy is enabled for your organisation and it has registry rows, it completes an agent_attestation_chain link.

Responses

StatusMeaningError codesContent
200A resolved Web Bot Auth verdict plus the KYA registry join.application/json
400The request failed validation. error is a route-specific string such as Invalid body or invalid_request; read the operation description for the exact values it can return.Invalid bodyapplication/json ErrorEnvelope
401The Authorization: Bearer sk_... header is missing or malformed, or the key is unknown, revoked, or belongs to a suspended or deleted organisation. The body is deliberately identical for every cause.invalid_api_keyapplication/json InvalidApiKeyError
403The API key is valid but does not carry the scope this operation requires; error names the missing scope.API key does not have read:device scopeapplication/json ScopeForbiddenError
413The request body exceeded this route’s byte cap.body_too_largeapplication/json ErrorEnvelope
415Content-Type must be application/json.invalid_requestapplication/json ErrorEnvelope
429Rate limit exceeded. Wait Retry-After seconds (also retryAfter in the body) before retrying; the response carries no other rate-limit headers.Rate limit exceededapplication/json
500Unexpected server fault. Retry with backoff and quote requestId to support if it persists.Internal server errorapplication/json ErrorEnvelope

Response headers

StatusHeaderTypeDescription
429Retry-AfterintegerSeconds until the bucket allows another request.

Response fields (200, application/json)

FieldTypeAlways returnedDescription
okbooleanYesAllowed values: true.
verdictstringYesAllowed values: verified, unsigned, invalid_signature, expired, replay.
keyidstring, nullableYes
signatureAgentstring, nullableYes
matchedActionstring, nullableYesAllowed values: allow, deny.
attestationobjectNoPresent ONLY when the caller forwarded a valid tier.
attestation.tierstringNoAllowed values: hardware, software, suspicious, unavailable, failed.
attestation.anchoredbooleanNo
attestation.provenancestringNoAlways caller_attested — this handler never independently corroborates the forwarded tier. Allowed values: caller_attested.
riskBandstringNoAllowed values: critical, high, medium, low, minimal.
kyaobjectNoPresent only when graduated agent policy is enabled for your organisation.
kya.verifiedbooleanNo
kya.agentIdstring, nullableNo
kya.sourcestringNoAllowed values: web-bot-auth, skyfire.
kya.attestationTierstringNoAllowed values: hardware, software, suspicious, unavailable, failed.
kya.attestationTierProvenancestringNoAllowed values: caller_attested.
kya.cfVerifiedbooleanNoPresent ONLY on a Cloudflare Verified AI Agents match.
kya.cfVerifiedNamestringNo
kya.trustCaveatstringNoPresent ONLY when the identity came from the Skyfire interop adapter. Allowed values: structural_only_signature_unverified.
disclosureobjectNoPresent only when EU AI Act disclosure is enabled for your organisation and a detected or verified agent is present.
disclosure.requiredbooleanNoAllowed values: true.
disclosure.regulationstringNoAllowed values: eu_ai_act_art_50.
disclosure.obligationstringNo
disclosure.agentVerifiedbooleanNo
policyActionstringNoPresent only when graduated agent policy is enabled for your organisation and an attributable identity exists — the advisory graduated enforcement tier (Noxtica never acts on it). Allowed values: allow, observe, challenge, deny.

Response example (200)

{
  "ok": true,
  "verdict": "verified",
  "keyid": "example-keyid",
  "signatureAgent": "example-signatureAgent",
  "matchedAction": "allow",
  "attestation": {
    "tier": "hardware",
    "anchored": true,
    "provenance": "caller_attested"
  },
  "riskBand": "critical",
  "kya": {
    "verified": true,
    "agentId": "example-agentId",
    "source": "web-bot-auth",
    "attestationTier": "hardware",
    "attestationTierProvenance": "caller_attested",
    "cfVerified": true,
    "cfVerifiedName": "example-cfVerifiedName",
    "trustCaveat": "structural_only_signature_unverified"
  },
  "disclosure": {
    "required": true,
    "regulation": "eu_ai_act_art_50",
    "obligation": "example-obligation",
    "agentVerified": true
  },
  "policyAction": "allow"
}

Example request

curl

curl -X POST "https://collect.noxtica.com/v1/agent/verify" \
  -H "Authorization: Bearer $NOXTICA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "headers": {
    "key": "example-headers"
  },
  "url": "https://verify.noxtica.com/s/kycs.tenant_42.9f3a8b7c6d5e4f3a2b1c0d9e8f7a6b5c",
  "attestation": {
    "tier": "hardware",
    "anchored": true
  },
  "riskBand": "critical",
  "jti": "example-jti"
}'

Node.js (global fetch, Node 18 or later)

const response = await fetch('https://collect.noxtica.com/v1/agent/verify', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.NOXTICA_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    headers: {
      key: 'example-headers',
    },
    url: 'https://verify.noxtica.com/s/kycs.tenant_42.9f3a8b7c6d5e4f3a2b1c0d9e8f7a6b5c',
    attestation: {
      tier: 'hardware',
      anchored: true,
    },
    riskBand: 'critical',
    jti: 'example-jti',
  }),
});
console.log(response.status, await response.text());

Python (standard library)

import json
import os
import urllib.request

request = urllib.request.Request(
    "https://collect.noxtica.com/v1/agent/verify",
    data=json.dumps({
        "headers": {
            "key": "example-headers",
        },
        "url": "https://verify.noxtica.com/s/kycs.tenant_42.9f3a8b7c6d5e4f3a2b1c0d9e8f7a6b5c",
        "attestation": {
            "tier": "hardware",
            "anchored": True,
        },
        "riskBand": "critical",
        "jti": "example-jti",
    }).encode(),
    headers={
        "Authorization": f"Bearer {os.environ['NOXTICA_API_KEY']}",
        "Content-Type": "application/json",
    },
    method="POST",
)
with urllib.request.urlopen(request) as response:
    print(response.status, response.read().decode())

Look up IP reputation

POST /v1/ip/reputation

Returns the reputation verdict {category, source, confidence} for one IP address supplied by your backend, from the same feed Noxtica uses to score its own submissions. When the address is not listed the response is listed: false; an unlisted address, an empty feed or a lookup fault never produces an error.

The queried IP is echoed back in the response, which is your own input. It is not stored or logged unless your organisation has opted into raw-IP storage; only the derived verdict is retained. A served call counts toward your organisation’s IP-reputation usage.

Authentication: Bearer token (ApiKeyAuth), scope read:device.

Request body

Content type application/json, required.

FieldTypeRequiredDescription
ipstringYesAn IPv4 dotted-quad or IPv6 address.

Responses

StatusMeaningError codesContent
200The derived reputation verdict, or listed:false when the engine has no signal.application/json
400The request failed validation. error is a route-specific string such as Invalid body or invalid_request; read the operation description for the exact values it can return.Invalid bodyapplication/json ErrorEnvelope
401The Authorization: Bearer sk_... header is missing or malformed, or the key is unknown, revoked, or belongs to a suspended or deleted organisation. The body is deliberately identical for every cause.invalid_api_keyapplication/json InvalidApiKeyError
403The API key is valid but does not carry the scope this operation requires; error names the missing scope.API key does not have read:device scopeapplication/json ScopeForbiddenError
429Rate limit exceeded. Wait Retry-After seconds (also retryAfter in the body) before retrying; the response carries no other rate-limit headers.Rate limit exceededapplication/json
500Unexpected server fault. Retry with backoff and quote requestId to support if it persists.Internal server errorapplication/json ErrorEnvelope

Response headers

StatusHeaderTypeDescription
429Retry-AfterintegerSeconds until the bucket allows another request.

Response fields (200, application/json)

FieldTypeAlways returnedDescription
okbooleanYesAllowed values: true.
ipstringYesEchoed back verbatim (the caller’s own query input).
listedbooleanYes
verdictobjectNoPresent ONLY when listed is true.
verdict.categorystringNo
verdict.sourcestringNo
verdict.confidencenumberNo

Response example (200)

{
  "ok": true,
  "ip": "example-ip",
  "listed": true,
  "verdict": {
    "category": "example-category",
    "source": "example-source",
    "confidence": 1
  }
}

Example request

curl

curl -X POST "https://collect.noxtica.com/v1/ip/reputation" \
  -H "Authorization: Bearer $NOXTICA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "ip": "example-ip"
}'

Node.js (global fetch, Node 18 or later)

const response = await fetch('https://collect.noxtica.com/v1/ip/reputation', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.NOXTICA_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    ip: 'example-ip',
  }),
});
console.log(response.status, await response.text());

Python (standard library)

import json
import os
import urllib.request

request = urllib.request.Request(
    "https://collect.noxtica.com/v1/ip/reputation",
    data=json.dumps({
        "ip": "example-ip",
    }).encode(),
    headers={
        "Authorization": f"Bearer {os.environ['NOXTICA_API_KEY']}",
        "Content-Type": "application/json",
    },
    method="POST",
)
with urllib.request.urlopen(request) as response:
    print(response.status, response.read().decode())

Score a signals payload

POST /v1/score

Scores an already-collected signals payload from your backend and returns the headline score, confidence, tier and flags that the Noxtica collector computes for its own submissions. Call it from a server with an sk_ key that carries the read:device scope (the default scope of every key); never from a browser.

Request. Send either the complete enriched payload {"signals": {...}, "serverSideSignals": {...}, ...} or, for older callers, the inner signals object on its own, which is wrapped once. The body may be up to 256 KiB. The raw payload is not logged.

Response. score is the engine’s score, tier its risk band and flags the flags that fired. confidence is an integer from 0 to 100 (50 is neutral). attestation is always null on this route: the payload is supplied by the caller and cannot be trusted as hardware evidence, so no hardware-verification claim is ever made.

Allowance. Calls within your plan’s monthly Score API allowance are included. Beyond it the score is still served and the response carries a nudge object with code: free_tier_exceeded; the score is never withheld.

Errors. 400 Invalid body when the body is not a JSON object or is larger than 256 KiB, and Invalid signals when signals is present but is not an object; 401, 403, 429 and 500 as on every key-authenticated route. No 413 is returned: an oversized body is a 400.

Authentication: Bearer token (ApiKeyAuth), scope read:device.

Request body

Content type application/json, required.

Type: object.

Responses

StatusMeaningError codesContent
200The re-scored verdict, mapped onto the public 0-100 confidence scale.application/json
400The request failed validation. error is a route-specific string such as Invalid body or invalid_request; read the operation description for the exact values it can return.Invalid bodyapplication/json ErrorEnvelope
401The Authorization: Bearer sk_... header is missing or malformed, or the key is unknown, revoked, or belongs to a suspended or deleted organisation. The body is deliberately identical for every cause.invalid_api_keyapplication/json InvalidApiKeyError
403The API key is valid but does not carry the scope this operation requires; error names the missing scope.API key does not have read:device scopeapplication/json ScopeForbiddenError
429Rate limit exceeded. Wait Retry-After seconds (also retryAfter in the body) before retrying; the response carries no other rate-limit headers.Rate limit exceededapplication/json
500Unexpected server fault. Retry with backoff and quote requestId to support if it persists.Internal server errorapplication/json ErrorEnvelope

Response headers

StatusHeaderTypeDescription
429Retry-AfterintegerSeconds until the bucket allows another request.

Response fields (200, application/json)

FieldTypeAlways returnedDescription
okbooleanYesAllowed values: true.
scorenumberYes
confidenceintegerYesNormalised to 0-100 (the engine’s native value is 0-1), matching /v1/attest/verify’s scale. Minimum 0, maximum 100.
tierstringYesThe engine’s riskLevel band.
flagsarray of stringYes
attestationany, nullableYesALWAYS null on this surface — see the honesty-gate note above.
nudgeobjectNoPresent ONLY once the free monthly allotment is exceeded — informational only, never withholds the score.
nudge.codestringNoAllowed values: free_tier_exceeded.
nudge.messagestringNo
nudge.free_serving_allotmentintegerNo

Response example (200)

{
  "ok": true,
  "score": 1,
  "confidence": 0,
  "tier": "example-tier",
  "flags": [
    "example-flags"
  ],
  "attestation": null,
  "nudge": {
    "code": "free_tier_exceeded",
    "message": "example-message",
    "free_serving_allotment": 1
  }
}

Example request

curl

curl -X POST "https://collect.noxtica.com/v1/score" \
  -H "Authorization: Bearer $NOXTICA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Node.js (global fetch, Node 18 or later)

const response = await fetch('https://collect.noxtica.com/v1/score', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.NOXTICA_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({}),
});
console.log(response.status, await response.text());

Python (standard library)

import json
import os
import urllib.request

request = urllib.request.Request(
    "https://collect.noxtica.com/v1/score",
    data=json.dumps({}).encode(),
    headers={
        "Authorization": f"Bearer {os.environ['NOXTICA_API_KEY']}",
        "Content-Type": "application/json",
    },
    method="POST",
)
with urllib.request.urlopen(request) as response:
    print(response.status, response.read().decode())

This page is generated from the Noxtica OpenAPI specification release v0.4.0: v1.yaml version 1.3.0-2026-10-27 (SHA-256 3fd15257a022). Do not edit it by hand.