@a3api/node
v0.1.2
Published
Official Node.js client for the A3 Age Assurance API
Maintainers
Readme
@a3api/node
Official Node.js client for the Arcadia Age API (A3). Handles request construction, typed responses, automatic retries, and structured error handling.
- Full TypeScript types for requests and responses
- Automatic retry with exponential backoff (429, 5xx, network errors)
- Typed error classes for each failure mode
- ESM + CJS + type declarations
- Zero dependencies (uses native
fetch)
Install
npm install @a3api/nodeRequires Node.js 18 or later.
Quick Start
import { A3Client } from '@a3api/node';
const client = new A3Client({ apiKey: process.env.A3_API_KEY! });
const result = await client.assessAge({
os_signal: 'not-available',
user_country_code: 'US',
behavioral_metrics: {
avg_touch_precision: 0.72,
scroll_velocity: 1200,
form_completion_time_ms: 8500,
},
});
console.log(result.verdict); // "PROVISIONAL"
console.log(result.assessed_age_bracket); // "18-plus"
console.log(result.confidence_score); // 0.7Constructor Options
const client = new A3Client({
apiKey: 'your_api_key', // Required
baseUrl: 'https://...', // Default: https://api.a3api.io
timeout: 30_000, // Default: 30000 (ms)
maxRetries: 2, // Default: 2
});| Option | Type | Default | Description |
|--------|------|---------|-------------|
| apiKey | string | required | Your A3 API key |
| baseUrl | string | https://api.a3api.io | API base URL |
| timeout | number | 30000 | Request timeout in milliseconds |
| maxRetries | number | 2 | Max retries for transient failures |
client.assessAge(request)
Sends signals to POST /v1/assurance/assess-age and returns the assessment.
Request
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| os_signal | OsSignal | Yes | 'under-13' | '13-15' | '16-17' | '18-plus' | 'not-available' |
| user_country_code | string | Yes | ISO 3166-1 alpha-2 code (e.g., 'US') |
| behavioral_metrics | BehavioralMetrics | No | Touch precision, scroll velocity, form timing, etc. |
| device_context | DeviceContext | No | OS version, device model, accessibility settings |
| contextual_signals | ContextualSignals | No | IP type, timezone offset, referrer category |
| account_longevity | AccountLongevity | No | { account_age_days: number } |
| input_complexity | InputComplexity | No | Autocorrect rate, word complexity score |
Response
| Field | Type | Description |
|-------|------|-------------|
| verdict | Verdict | 'CONSISTENT' | 'OVERRIDE' | 'REVIEW' | 'PROVISIONAL' |
| assessed_age_bracket | AgeBracket | 'under-13' | '13-15' | '16-17' | '18-plus' | 'undetermined' |
| confidence_score | number | 0–1 certainty in the assessed bracket (Pro/Scale plans only) |
| os_signal_age_bracket | AgeBracket | OS signal echoed back |
| signal_overridden | boolean | true when verdict is OVERRIDE |
| evidence_tags | string[] | Audit trail of which signals influenced the verdict (Pro/Scale plans only) |
| verification_token | string | HMAC-SHA256 signed cryptographic receipt — store in your logs |
Error Handling
The client throws typed errors you can catch individually:
import {
A3Client,
A3ValidationError,
A3AuthenticationError,
A3RateLimitError,
A3ConnectionError,
} from '@a3api/node';
try {
const result = await client.assessAge(request);
} catch (err) {
if (err instanceof A3ValidationError) {
// 400 — bad request body
console.error(err.validationErrors); // string[]
} else if (err instanceof A3AuthenticationError) {
// 401 — invalid API key
} else if (err instanceof A3RateLimitError) {
// 429 — rate limited (auto-retried, this means retries exhausted)
console.error(err.retryAfter); // ms until retry, if provided
} else if (err instanceof A3ConnectionError) {
// Network failure or timeout (auto-retried, retries exhausted)
}
}| Error Class | Status | Auto-Retried | Description |
|-------------|--------|:------------:|-------------|
| A3ValidationError | 400 | No | Request body failed validation |
| A3AuthenticationError | 401 | No | Missing or invalid API key |
| A3RateLimitError | 429 | Yes | Rate limit or quota exceeded |
| A3ApiError | 5xx | Yes | Server error |
| A3ConnectionError | — | Yes | Network failure or timeout |
Usage with Express
import express from 'express';
import { A3Client } from '@a3api/node';
const app = express();
app.use(express.json());
const a3 = new A3Client({ apiKey: process.env.A3_API_KEY! });
app.post('/api/assess-age', async (req, res) => {
const result = await a3.assessAge({
os_signal: 'not-available',
user_country_code: 'US',
...req.body, // signals from @a3api/signals browser SDK
});
res.json({
verdict: result.verdict,
bracket: result.assessed_age_bracket,
});
});Links
License
MIT
