Node.js SDK reference
@revokegpt/node is the RevokeGPT server SDK for Node.js 26 or later. It sends a response token to siteverify and
applies every relying-party check: success must be the boolean true, the hostname (or app) and the action must
match exactly, and the score must meet your threshold. It also wraps assessments, account protection, password and
credential pair checks, payments and erase. For a walkthrough, see the Node.js quickstart.
Install
Section titled “Install”npm install @revokegpt/node # after the first release; Node.js 26 or laterOptions
Section titled “Options”createClient(options) takes:
| Option | Type | Default | Meaning |
|---|---|---|---|
secret |
string |
required | Your site’s secret key (rgsk_...). A management key (rgmk_...) is refused. |
endpoint |
string |
required | The full siteverify URL. https:, or http: only on localhost or 127.0.0.1; no username, password, query or fragment. |
timeoutMs |
number |
5000 |
An integer from 1 to 60000. |
fetch |
typeof fetch |
global fetch |
A WHATWG-compatible fetch: its response body must be a web ReadableStream. A node-fetch v2 style body is not supported and every verification fails closed as network-error. |
An invalid secret throws TypeError('invalid secret key'); the message never includes the key. For the assessment and
password calls, endpoint must end in /siteverify (the other URLs are derived from it).
Methods
Section titled “Methods”createClient
Section titled “createClient”function createClient(options: ClientOptions): ClientCreate the client once and reuse it.
verify
Section titled “verify”verify(token: string, options: VerifyOptions): Promise<VerifyOutcome>| Option | Type | Meaning |
|---|---|---|
expectedHostname |
string |
For web tokens. Canonical: lowercase, no trailing dot, no port. Compared exactly. |
expectedApp |
{ platform: 'android' | 'ios'; id: string } |
For mobile app tokens. Android: the package name. iOS: the bare bundle id, no Team ID. |
expectedAction |
string |
Omit only if you use no actions; then a token that carries an action is refused. |
minScore |
number |
In [0, 1]. Always pass it: without it every verified result fails with threshold-missing. |
remoteip |
string |
The end user’s IPv4 or IPv6 address, sent only when given and not empty. An address with a zone id is invalid. |
sitekey |
string |
The site key the token must belong to, sent only when given and not empty. |
Give exactly one of expectedHostname and expectedApp. Returns:
type VerifyOutcome = | { ok: true; result: SiteverifyResult } | { ok: false; reason: VerifyFailureReason; result: SiteverifyResult };result is the parsed siteverify result (score, action, hostname, errorCodes, reasons, and the app id
fields), for logging. Gate on outcome.ok alone.
import { createClient } from '@revokegpt/node';
const revokegpt = createClient({ secret: process.env.REVOKEGPT_SECRET!, // rgsk_... endpoint: 'https://<api host>/v1/siteverify',});
const outcome = await revokegpt.verify(token, { expectedHostname: 'shop.example', expectedAction: 'signup', minScore: 0.5, remoteip: clientIp, // from your trusted proxy, not req.socket.remoteAddress});if (!outcome.ok) return reject(outcome.reason);For mobile tokens, pass expectedApp: { platform: 'android', id: 'com.example.app' } instead of a hostname.
createAssessment
Section titled “createAssessment”createAssessment(input: CreateAssessmentInput): Promise<Assessment>input fields: token?, expectedAction?, express?, userIpAddress?, userAgent?, headers?, userInfo?,
accountVerification?, transactionData?, fraudPrevention? ('ENABLED', 'DISABLED' or
'FRAUD_PREVENTION_UNSPECIFIED'). A token assessment spends the token. An invalid token is still a 200 with
tokenProperties.valid: false and score 0, so check valid. Express (express: true, no token) scores the IP
address alone, so pass the real end-user address.
const a = await revokegpt.createAssessment({ token, expectedAction: 'login' });if (a.tokenProperties.valid && a.riskAnalysis.score >= 0.5) allow();annotate
Section titled “annotate”annotate(aidOrName: string, input?: AnnotateInput): Promise<void>Labels an assessment. Accepts assessments/<aid> or the bare aid. input: annotation? ('LEGITIMATE' or
'FRAUDULENT'), reasons?, accountId? or hashedAccountId?, transactionEvent?. Annotate with ground truth you
learn later, not guesses.
await revokegpt.annotate(a.name, { annotation: 'FRAUDULENT', reasons: ['CHARGEBACK'] });isPasswordLeaked
Section titled “isPasswordLeaked”isPasswordLeaked(password: string): Promise<PasswordCheckResult> // { leaked, count }Hashes with SHA-1 locally and sends only the first 5 hex characters. A 503 throws RevokeGPTUnavailable, which
means “could not check”, never “not leaked”. See password check.
checkCredentialPair
Section titled “checkCredentialPair”checkCredentialPair(username: string, password: string): Promise<CredentialPairResult> // { leaked }Beta; off until enabled, otherwise RevokeGPTError with status: 403 and code: 'feature-disabled'. An RFC 9497
OPRF: neither value reaches the service. A username holding an unassigned code point is refused with a RangeError
and no request.
eraseAccount
Section titled “eraseAccount”eraseAccount(input: { accountId: string } | { hashedAccountId: string }): Promise<void>Erases what the service holds for an account. Use the same account id form you used to assess and annotate.
cardFields
Section titled “cardFields”function cardFields(i: { bin?: string; last4?: string }): { cardBin?: string; cardLastFour?: string }Builds the only card fields a payment assessment accepts (BIN of 6 or 8 digits and last four). Throws
RevokeGPTError('bad-request', 0) for anything else. Every string of transactionData is also scanned for a card
number before sending.
Errors and failure model
Section titled “Errors and failure model”verify never throws or rejects. Every failure is an outcome with a reason:
| Reason | Meaning |
|---|---|
invalid-expectation |
The expectation is invalid. Nothing was sent. |
invalid-options |
A given remoteip or sitekey is invalid. Nothing was sent. |
invalid-token-format |
Not 1 to 2048 characters of A-Z a-z 0-9 - _. Nothing was sent. |
network-error |
The request failed or timed out. |
http-error |
Siteverify answered with a status other than 200 (redirects included), or a body over 64 KiB. |
not-verified |
Siteverify did not verify the token, or its body was malformed. result.errorCodes says why. |
hostname-mismatch |
The token was issued for another hostname. |
app-mismatch |
The token was issued to another app, a web page or the other platform. |
action-mismatch |
Another action, or an action when you expect none. |
score-missing |
You set minScore and the result has no score. |
threshold-missing |
The result has a score and you set no minScore. |
score-below-threshold |
The score is below minScore. |
score-invalid |
The score is not a number in [0, 1]. |
Treat every reason as “do not accept”. A token is single use, and after network-error or http-error it may
already be spent, so a retry needs a new token from the widget.
All other methods throw RevokeGPTError on failure, and its subclass RevokeGPTUnavailable for HTTP 503. Fields:
code (for example unauthorized, feature-disabled, not-found, expired, rate-limited, payload-too-large,
unsupported-media-type, service-unavailable, network-error, invalid-response), status (0 when no response),
requestId, and retryAfterSeconds for a 429. See errors.
Configuration
Section titled “Configuration”The SDK reads no environment variables. Read the secret from your secret store and pass it to createClient (the
examples use REVOKEGPT_SECRET). Redirects are never followed, nothing is retried, and at most 64 KiB of response is
read.
Security notes
Section titled “Security notes”- The secret is held privately by the client: logging or serializing the client never shows it. It is sent only in the POST body (siteverify) or the
Authorizationheader, never in a URL. - The SDK form-encodes the siteverify body. If you call siteverify yourself, never build the body by string concatenation.
- Behind a proxy, pass the client address from your trusted proxy as
remoteip, notreq.socket.remoteAddress. - Never choose between the hostname and the app expectation from anything the client controls.