# Arcadia Age API (A3) — Full Documentation > Arcadia Age API (A3) provides compliant, frictionless age assurance built for the US market — without verification walls, identity friction, or storing a single byte of PII. Keep your users flowing. Stay compliant. A3 (Arcadia Age API) is the unified age compliance layer for web, iOS, and Android. California AB 1043 mandates age assurance, but browsers have no Apple or Google age signal — A3 fills that gap. On native apps, A3 normalizes Apple's Declared Age Range API and Google's Play Age Signals into a single response. On the web, A3 provides full age assurance through passive signal fusion. One API call, one response format, one audit trail — regardless of platform. Zero data retention. No verification walls. No stored PII. ## Key Links - [Documentation](https://www.a3api.io/docs) - [API Playground](https://www.a3api.io/playground) - [Pricing](https://www.a3api.io/pricing) - [Developer Portal (Get API Key)](https://portal.a3api.io) - [OpenAPI Spec](https://www.a3api.io/openapi.json) - [AB 1043 Compliance Guide](https://www.a3api.io/docs/compliance/ab-1043) - [Trust & Reliability](https://www.a3api.io/trust) - [Privacy Policy](https://www.a3api.io/privacy) - [Terms of Service](https://www.a3api.io/terms) - [Browser SDK (`@a3api/signals`)](https://www.a3api.io/docs/integration/sdks#browser-sdk-a3apisignals) - [Changelog](https://www.a3api.io/changelog) - [Contact](https://www.a3api.io/contact) --- ## Getting Started ### Overview Arcadia Age API (A3) is the unified age compliance API for web, iOS, and Android. It provides stateless, serverless REST endpoints that normalize Apple and Google OS age signals on native apps and deliver full age assurance on the web — where no OS signal exists. Every API is: - **Zero-Retention** — no user data is stored, logged, or persisted. Every response includes a cryptographically signed `verification_token` that you store in your own logs for audit purposes. - **Pass-Through** — A3 is a processor, not a controller. You provide the signals, we return the verdict. This simplifies enterprise Data Processing Addendums (DPAs) and makes A3 a "commercially reasonable" compliance layer under US law. - **Sub-Second** — responses are computed in-memory and returned immediately (cold starts under 200 ms, warm invocations in milliseconds). - **Auto-Scaling** — deployed on AWS Lambda with no provisioning required. ### Getting Your API Key 1. Sign up at [portal.a3api.io](https://portal.a3api.io). 2. A **Sandbox** API key is provisioned automatically on first login. 3. Manage your keys, view usage, and upgrade your plan from the developer portal. ### Authentication All production endpoints require an API key passed via the `Authorization` header: ```bash curl -X POST https://api.a3api.io/v1/assurance/assess-age \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"os_signal": "18-plus", "user_country_code": "US"}' ``` ### Base URL | Environment | Base URL | | ----------- | ------------------------------ | | Production | `https://api.a3api.io/v1` | ### Error Format All errors follow a consistent shape: ```json { "statusCode": 400, "message": ["os_signal must be a string"], "error": "Bad Request" } ``` | Status | Meaning | | ------ | ------- | | `400 Bad Request` | Request body failed validation (missing or invalid fields). | | `401 Unauthorized` | Missing or invalid API key. | | `429 Too Many Requests` | Rate limit or monthly quota exceeded. | ### Plans & Rate Limits | Plan | Requests / Minute | Monthly Quota | Response Fields | | ------- | -----------------:| -------------:| --------------- | | Sandbox | 600 | 100 | Basic | | Pro | 60,000 | Unlimited | Full | | Scale | 300,000 | Unlimited | Full | **Sandbox plan responses omit premium fields.** The `evidence_tags` and `confidence_score` fields are only included on Pro and Scale plans. Sandbox responses still include the verdict, assessed bracket, and verification token. --- ## Age Assurance API — Overview ### What is the Age Assurance API? The Age Assurance API is a **unified age compliance layer** for web, iOS, and Android — built around a **two-phase Signal Fusion engine** designed for **California AB 1043** (Digital Age Assurance Act) compliance. On **native apps**, A3 normalizes Apple's Declared Age Range API and Google's Play Age Signals into a single, consistent response. On the **web** — where no OS age signal exists — A3 provides full age assurance through behavioral biometrics, input complexity, device context, and other supplementary signals. The result is **one API call, one response format, and one audit trail** — regardless of whether the user is on Safari, Chrome, iOS, or Android. The API implements the statutory framework in **two distinct phases**: | Phase | Statute | What happens | | ----- | ------- | ------------ | | **Phase 1** | §1798.501(b)(3)(A) | OS signal is treated as the **primary** age indicator. This is the default. | | **Phase 2** | §1798.501(b)(3)(B) | Supplementary evidence is scored **independently**. The OS signal is overridden only when evidence meets the **"clear and convincing"** legal standard. | This two-phase design ensures the API never overrides the OS signal based on weak or ambiguous evidence, preserving the statutory primacy of the OS-provided signal. ### Key Properties | Property | Detail | | --------------- | --------------------------------------------------- | | Architecture | Stateless lambdalith (single Lambda per service) | | Data retention | **Zero** — user data is never stored, logged, or persisted | | Audit strategy | **Cryptographic Receipt** — a signed `verification_token` is returned to the customer | | Latency | Sub-200 ms cold start; single-digit ms warm | | Region | `us-west-2` (default) | ### Verdicts The API returns one of four verdicts describing the relationship between the OS signal and the supplementary evidence: | Verdict | Statute Reference | Meaning | | -------------- | ----------------- | ------- | | `CONSISTENT` | §1798.501(b)(3)(A) | Supplementary evidence **corroborates** the OS signal. The OS signal remains the primary indicator. | | `OVERRIDE` | §1798.501(b)(3)(B) | "Clear and convincing" evidence **contradicts** the OS signal. The developer SHALL use the assessed age bracket. | | `REVIEW` | §1798.501(b)(3)(A) | Evidence partially contradicts the OS signal but does **not** meet the "clear and convincing" threshold. OS signal remains primary; developer should investigate. | | `PROVISIONAL` | §1798.502 | OS signal is **not yet available** (transition period Jan–Jul 2027). Assessment is based solely on supplementary evidence. | ### Age Brackets The API uses the four statutory age brackets defined in §1798.500(b): | Bracket | Statute | Value | | ------------ | ------- | ----- | | Under 13 | §1798.500(b)(1) | `under-13` | | 13–15 | §1798.500(b)(2) | `13-15` | | 16–17 | §1798.500(b)(3) | `16-17` | | 18+ | §1798.500(b)(4) | `18-plus` | The response includes both `os_signal_age_bracket` (echoed from input) and `assessed_age_bracket` (the engine's determination). When the verdict is `OVERRIDE`, these two will differ — the developer should use `assessed_age_bracket` as the primary indicator. ### Signal Fusion Categories The engine evaluates five categories of supplementary evidence, each weighted by how difficult it is to fake: | Category | Weight | What it measures | Evidence type | | -------- | -----: | ---------------- | ------------- | | **Behavioral Metrics** | 43% | **Touch mode:** touch precision, scroll velocity, pressure variance, multi-touch frequency. **Pointer mode:** click precision, mouse velocity, path straightness, hover dwell time, typing speed, keystroke rhythm. Face estimation fallback (both modes). | Internal (face estimation: external) | | **Input Complexity** | 28% | Autocorrect reliance, word-length/syllable distributions | Internal | | **Contextual Signals** | 10% | IP reputation, timezone consistency, referrer source | Potentially external | | **Account Longevity** | 9% | Account age (days since creation) | Internal | | **Device Context** | 10% | OS version, device model, accessibility settings, display scale | Internal | The "internal" vs "potentially external" distinction matters legally. §1798.501(b)(2)(B) references "internal clear and convincing information." The API response includes an `internal_evidence_only` flag so you know whether the assessment relied on external databases (IP reputation, referrer classification) or only on signals your app collected directly. ### Device Normalization Not all touchscreens are created equal. A budget Android device (e.g., Galaxy A14, Redmi 12C) has a lower-quality digitizer that produces inherently lower touch-precision readings — even when the user is an adult with fully developed motor skills. Without compensation, the engine would flag these users with a "Precision Delta" tag and potentially trigger a false override. The engine solves this with a **Hardware Quality Offset** applied during touch-precision scoring: | Hardware Tier | Offset | Example devices | | ------------- | -----: | --------------- | | **HIGH** (flagship) | +0.00 | iPhone 15 Pro, Galaxy S24, Pixel 9 Pro | | **MID** (mid-range) | +0.05 | iPhone SE, Galaxy A54, Pixel 7a, OnePlus 12 | | **LOW** (budget) | +0.10 | Galaxy A14, Moto G Power, Redmi 12C, Tecno Spark | | **UNKNOWN** | +0.00 | No `device_model` provided or unrecognized model | To take advantage of device normalization, include `device_model` in your `device_context` payload. The SDK should use the hardware's reported model string (e.g., `Build.MODEL` on Android, `UIDevice.current.model` or `uname` on iOS). ### Consent Synchronizer Under §1798.501(c), parental consent is a "living" signal — a parent can approve, deny, or revoke consent at any time via the OS parental-control framework (Apple Screen Time, Google Family Link) or a third-party identity wallet. The API accepts an optional `parental_consent_status` and `consent_source` so that when the verdict is "Minor," the developer immediately knows whether the parent has already approved access — no second consent system required. | Field | Values | Notes | | ----- | ------ | ----- | | `parental_consent_status` | `pending`, `approved`, `denied`, `revoked` | Optional — omit for 18+ users or when no consent flow exists | | `consent_source` | `os-system`, `third-party-wallet`, `in-app` | **Required** when `parental_consent_status` is present | ### Zero-Retention Architecture The Arcadia Age API is a **Pass-Through Processor** — it computes scores and returns results, but **stores zero user data**. This design is built on four pillars: | Pillar | What it does | Who stores it | | ------ | ------------ | ------------- | | **Cryptographic Receipt** | Every response includes a `verification_token` — an HMAC-SHA256 signed payload containing the verdict, evidence tags, and confidence score. | **You** store it in your logs. | | **Aggregated Analytics** | The API emits hourly verdict counts (e.g., "1,400 OVERRIDE verdicts at 2 PM") with no session IDs, no behavioral values, and no country codes. | A3 infrastructure (counts only). | | **Billing Ledger** | A SHA-256 hash of your API key + timestamp + request status is logged for billing reconciliation. Zero assessment data. | A3 billing system (isolated). | | **Customer-Side Storage** | Your application stores the `verification_token` alongside your own user records. | **You** control retention. | If a dispute arises, send the `verification_token` back to A3. We verify the HMAC signature and decode the payload to see exactly what happened — without ever having stored a single byte of user data. This makes A3 a **Pass-Through Processor** under most Data Processing Addendums (DPAs), bypassing the majority of enterprise security checklists. ### Browser SDK (`@a3api/signals`) For web applications where no OS age signal exists, the `@a3api/signals` npm package passively collects behavioral and contextual signals and packages them into the exact payload shape expected by `POST /v1/assurance/assess-age`. The SDK does NOT make API calls — customers forward the payload from their backend (where API keys stay secure). **Install:** `npm install @a3api/signals` **Vanilla JS:** ```javascript import { createSignalCollector } from '@a3api/signals'; const collector = createSignalCollector(); // ... user interacts with the page ... const signals = collector.getSignals(); // signals = { behavioral_metrics, input_complexity, device_context, contextual_signals } // Send to your backend, which adds os_signal + user_country_code and calls A3 await fetch('/your-backend/assess', { method: 'POST', body: JSON.stringify(signals) }); collector.destroy(); // clean up event listeners ``` **React:** `import { useSignalCollector } from '@a3api/signals/react'` **Vue:** `import { useSignalCollector } from '@a3api/signals/vue'` The SDK is <5KB gzipped, has zero runtime dependencies, and collects: touch precision, scroll velocity, form timing, autofill detection, touch pressure variance, multi-touch frequency, autocorrect rate, word complexity, OS version, device model, high contrast, screen scale, referrer category, and timezone offset. ### Use Cases - **Web applications** — browsers have no OS age signal. A3's signal fusion engine provides full age assurance for any website serving California users, using behavioral biometrics, input complexity, and device context as primary signals. The `@a3api/signals` SDK makes collection drop-in. - **Cross-platform unification** — instead of integrating Apple's Declared Age Range API, Google's Play Age Signals API, and a separate web solution, use A3 as a single normalization layer. One API, one response format, one audit trail. - **Content gating** — restrict or adjust content when the assessed bracket indicates a minor, without asking users to prove their age. - **Age-gated purchases** — add a silent risk signal before checkout flows, using the specific bracket (under-13, 13–15, 16–17) to apply the right restrictions. - **Audit trails** — store the `verification_token` in your logs to demonstrate compliance if the AG investigates. The token is cryptographically signed and contains the full verdict, evidence tags, and confidence score — no raw user data stored anywhere. - **Transition period** — use `not-available` as the OS signal during Jan–Jul 2027 and still get a provisional assessment from behavioral data. - **Enterprise DPA compliance** — tell your customers' legal teams: "We are a Pass-Through Processor. We provide a cryptographically signed receipt. We store zero user data." --- ## POST /v1/assurance/assess-age — Full API Reference ### Request Body #### `os_signal` (required) OS-provided age bracket per AB 1043 §1798.501(a)(2). One of: `under-13`, `13-15`, `16-17`, `18-plus`, or `not-available` (§1798.502 transition period). #### `user_country_code` (required) Two-letter country code (ISO 3166-1 alpha-2) of the user's current jurisdiction (e.g., `US`). Age-threshold laws are geographic — California uses 13/16/18 brackets and other US states may define different thresholds. **The API is currently available in the United States only. EU/EEA/UK country codes return 403 Forbidden.** #### `interaction_mode` (optional) Interaction mode describing how the user interacts with the application. One of: `touch` (mobile/tablet), `pointer` (desktop/laptop with mouse/trackpad), or `hybrid` (convertible device). When omitted, the engine infers the mode from the behavioral signals provided. Explicitly setting this field ensures correct threshold calibration (e.g., scroll velocity thresholds differ between touch flick and mouse wheel). #### `behavioral_metrics` (optional) Anonymized behavioral biometrics — the hardest signals to fake. Qualifies as "internal" evidence under §1798.501(b)(2)(B). Supports both **touch-mode** (mobile/tablet) and **pointer-mode** (desktop/laptop) signals. All fields are optional — the engine scores whichever signals are present. **Touch-mode signals:** | Field | Type | Required | Description | | ----- | ---- | -------- | ----------- | | `avg_touch_precision` | number (0–1) | No | Average touch-target precision. Touch-mode only — omit for pointer-mode. | | `scroll_velocity` | number (px/s) | No | Average scroll/flick velocity. Engine applies different thresholds for touch (0–5000+ px/s) vs pointer (0–1500 px/s). | | `form_completion_time_ms` | number (ms) | No | Average form-field completion time. Works identically in both modes. | | `is_autofill_detected` | boolean | No | Whether browser/OS autofill was detected. When true, form_completion_time_ms is neutralized. | | `touch_pressure_variance` | number (0–1) | No | Normalized variance of touch pressure. Touch-mode only. | | `multi_touch_frequency` | number (events/min) | No | Accidental multi-touch events per minute. Touch-mode only. | **Pointer-mode signals (desktop/laptop):** | Field | Type | Required | Description | | ----- | ---- | -------- | ----------- | | `avg_click_precision` | number (0–1) | No | Average click-target precision — pointer-mode equivalent of avg_touch_precision. | | `mouse_velocity_mean` | number (px/s) | No | Average mouse/trackpad cursor velocity. Children move erratically; adults move smoothly. | | `mouse_path_straightness` | number (0–1) | No | Ratio of direct distance to actual cursor path distance. Children produce wobbly paths. | | `hover_dwell_time_ms` | number (ms) | No | Time between cursor entering a clickable target and the click. Adults deliberate; children click impulsively. | | `typing_speed_wpm` | number | No | Average typing speed in WPM. Adults: 40–80; children: 10–25. Can be used in both modes. | | `keystroke_interval_variance` | number (0–1) | No | Variance of inter-keystroke timing. Adults have consistent rhythms. Can be used in both modes. | **Face estimation fallback (both modes):** | Field | Type | Required | Description | | ----- | ---- | -------- | ----------- | | `face_estimation_result` | object | No | Privacy-preserving selfie-to-age face estimation. Used as fallback when OS signal is not-available. | | `face_estimation_result.estimation_provider` | enum | Required if face_estimation_result provided | One of: `yoti`, `privado`, or `facetec`. | | `face_estimation_result.estimated_age_lower` | number (0–150) | Required if face_estimation_result provided | Lower bound of estimated age range. | | `face_estimation_result.estimated_age_upper` | number (0–150) | Required if face_estimation_result provided | Upper bound of estimated age range. | | `face_estimation_result.confidence` | number (0–1) | Required if face_estimation_result provided | Provider confidence score. | #### `device_context` (optional) Device and OS metadata. When `device_model` is provided, the engine applies hardware-tier normalization to touch-precision scoring. | Field | Type | Required | Description | | ----- | ---- | -------- | ----------- | | `os_version` | string | Yes | OS version string (e.g., `iOS 18.2`). Legacy versions may indicate a hand-me-down device. | | `device_model` | string | No | Device model identifier (e.g., `iPhone 15 Pro`, `Galaxy A14`). Used for hardware-tier detection. | | `is_high_contrast_enabled` | boolean | Yes | Whether high-contrast accessibility is enabled. Correlates with 50+ demographic. | | `screen_scale_factor` | number (0.5–5.0) | Yes | Display scale factor. Values >= 2.0 correlate with older users. | #### `contextual_signals` (optional) Environmental and network context. Some fields may use external databases and will set `internal_evidence_only: false`. | Field | Type | Required | Description | | ----- | ---- | -------- | ----------- | | `ip_type` | enum | No | IP classification: `residential`, `education`, `datacenter`, or `corporate`. | | `timezone_offset_delta_minutes` | number | No | Client timezone offset in minutes from UTC (e.g., `-480` for US Pacific). The server compares against the expected geographic timezone — a mismatch > 60 min flags potential spoofing. The `@a3api/signals` SDK sends `Date.getTimezoneOffset()` automatically. | | `referrer_category` | enum | No | Referring source: `direct`, `social_minor`, `social_general`, `parental_control`, `search_engine`, or `unknown`. | #### `account_longevity` (optional) | Field | Type | Required | Description | | ----- | ---- | -------- | ----------- | | `account_age_days` | number | Yes | Days since account creation. < 7 days reduces adult confidence; > 1,825 days is a strong adult corroborator. | #### `input_complexity` (optional) | Field | Type | Required | Description | | ----- | ---- | -------- | ----------- | | `keyboard_autocorrect_rate` | number (0–1) | Yes | Ratio of autocorrect-modified keystrokes. Minors rely on autocorrect at higher rates. | | `average_word_complexity_score` | number (0–1) | Yes | Average word complexity from word length and syllable count. Computed on-device — no raw text transmitted. | #### Consent Synchronizer (optional) | Field | Type | Required | Description | | ----- | ---- | -------- | ----------- | | `parental_consent_status` | enum | No | One of: `pending`, `approved`, `denied`, or `revoked`. | | `consent_source` | enum | Required if parental_consent_status provided | One of: `os-system`, `third-party-wallet`, or `in-app`. | ### Example Request ```bash curl -X POST https://api.a3api.io/v1/assurance/assess-age \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "os_signal": "18-plus", "user_country_code": "US", "behavioral_metrics": { "avg_touch_precision": 0.25, "scroll_velocity": 4000, "form_completion_time_ms": 1500, "touch_pressure_variance": 0.82, "multi_touch_frequency": 9.3 }, "device_context": { "os_version": "iOS 14.0", "device_model": "iPhone 13", "is_high_contrast_enabled": false, "screen_scale_factor": 1.0 }, "contextual_signals": { "ip_type": "education", "timezone_offset_delta_minutes": 240 }, "account_longevity": { "account_age_days": 2 }, "input_complexity": { "keyboard_autocorrect_rate": 0.42, "average_word_complexity_score": 0.21 } }' ``` ### Example Response (201 Created) ```json { "confidence_score": 0.96, "verdict": "OVERRIDE", "os_signal_age_bracket": "18-plus", "assessed_age_bracket": "under-13", "signal_overridden": true, "internal_evidence_only": false, "evidence_tags": [ "low_touch_precision", "high_motor_precision_delta", "rapid_scroll_velocity", "rapid_form_completion", "erratic_touch_pressure", "high_multi_touch_frequency", "device_normalization_applied:mid", "legacy_device_detected", "known_education_network_ip", "inconsistent_timezone_offset", "very_new_account", "high_autocorrect_rate", "low_word_complexity", "signal_override_active", "rule_source:1798.501.b.3.B" ], "verification_token": "eyJ2IjoxLCJ0cyI6IjIwMjYtMDItMDdUMTQ6MzA6MDBaIiwidmVyZGljdCI6Ik9WRVJSSURFI..." } ``` ### Response Fields | Field | Type | Description | | ----- | ---- | ----------- | | `confidence_score` | number (0–1) | Certainty in the assessed age bracket. Higher values mean greater confidence. | | `verdict` | enum | `CONSISTENT`, `OVERRIDE`, `REVIEW`, or `PROVISIONAL`. | | `os_signal_age_bracket` | enum | The age bracket from the OS signal, echoed back. | | `assessed_age_bracket` | enum | The age bracket the fusion engine assessed. When verdict is `OVERRIDE`, this differs from `os_signal_age_bracket`. | | `signal_overridden` | boolean | True only when verdict is `OVERRIDE`. | | `internal_evidence_only` | boolean | True when only internal evidence was used. False when `ip_type` or `referrer_category` were used. | | `evidence_tags` | string[] | Audit trail of signals that influenced the assessment. | | `verification_token` | string | HMAC-SHA256 signed cryptographic receipt. Store this in YOUR logs. | ### Verdict Decision Tree | Condition | Verdict | `signal_overridden` | `assessed_age_bracket` | | --------- | ------- | :-----------------: | ---------------------- | | No supplementary evidence, or evidence agrees with OS signal | `CONSISTENT` | `false` | Same as OS signal | | Evidence contradicts OS signal **and** meets clear & convincing threshold | `OVERRIDE` | `true` | Differs from OS signal | | Evidence contradicts OS signal but **below** threshold | `REVIEW` | `false` | Same as OS signal (primary) | | OS signal is `not-available` (transition period) | `PROVISIONAL` | `false` | Based on supplementary evidence, or `undetermined` | When the verdict is `OVERRIDE`, you are legally obligated under §1798.501(b)(3)(B) to use `assessed_age_bracket` as the primary indicator of the user's age — not the OS signal. ### Evidence Tags Reference #### Behavioral Metrics | Tag | Meaning | | --- | ------- | | `low_touch_precision` | Touch precision below 0.4 — child-like motor skills | | `high_motor_precision_delta` | Low precision contradicts an 18+ OS signal claim | | `high_touch_precision` | Touch precision above 0.8 — adult-like precision | | `rapid_scroll_velocity` | Scroll velocity above 3,500 px/s — youthful "scan and flick" | | `deliberate_scroll_pattern` | Scroll velocity below 800 px/s — adult-like reading | | `rapid_form_completion` | Form time below 2,000 ms — impulsive interaction | | `deliberate_form_completion` | Form time above 15,000 ms — careful, deliberate reading | | `autofill_detected_form_completion_neutralized` | Autofill detected — form completion time neutralized to prevent false minor classification | | `erratic_touch_pressure` | Touch pressure variance above 0.7 — erratic, child-like motor pattern | | `stable_touch_pressure` | Touch pressure variance at or below 0.3 — stable, adult-like pressure | | `high_multi_touch_frequency` | Multi-touch events above 6/min — accidental palm/finger touches (strong minor corroborator) | | `elevated_multi_touch_frequency` | Multi-touch events above 3/min but at or below 6/min — moderate minor signal | | `low_multi_touch_frequency` | Multi-touch events at or below 1/min — controlled single-touch interaction (adult corroborator) | #### Device Context | Tag | Meaning | | --- | ------- | | `accessibility_settings_detected` | High-contrast enabled — correlates with 50+ demographic | | `large_display_scale` | Screen scale factor >= 2.0 — correlates with older users | | `legacy_device_detected` | Legacy OS version (iOS 10–15, Android 5–11) — possible hand-me-down | | `device_normalization_applied:low` | Budget-tier device detected — hardware quality offset (+0.10) applied | | `device_normalization_applied:mid` | Mid-tier device detected — hardware quality offset (+0.05) applied | #### Contextual Signals | Tag | Meaning | | --- | ------- | | `known_education_network_ip` | IP classified as an education network | | `datacenter_ip_detected` | IP classified as a datacenter — suggests VPN usage | | `inconsistent_timezone_offset` | System clock vs expected timezone mismatch > 60 minutes | | `parental_control_referrer` | Traffic from a parental-control hub | | `minor_platform_referrer` | Traffic from a social platform popular with minors | #### Account Longevity | Tag | Meaning | | --- | ------- | | `very_new_account` | Account age < 7 days | | `new_account` | Account age 7–30 days | | `established_account` | Account age 365–1,825 days | | `mature_account` | Account age >= 1,825 days (5+ years) | #### Input Complexity | Tag | Meaning | | --- | ------- | | `high_autocorrect_rate` | Autocorrect rate above 0.4 | | `low_autocorrect_rate` | Autocorrect rate at or below 0.1 | | `low_word_complexity` | Word complexity score below 0.25 | | `high_word_complexity` | Word complexity score 0.65 or above | #### Pointer-mode Behavioral (Desktop/Laptop) | Tag | Meaning | | --- | ------- | | `interaction_mode_touch` | Touch interaction mode detected or inferred | | `interaction_mode_pointer` | Pointer interaction mode detected or inferred | | `interaction_mode_hybrid` | Hybrid (touch + pointer) interaction mode detected or inferred | | `low_click_precision` | Click precision below 0.4 — child-like motor control | | `high_click_precision_delta` | Low click precision contradicts an 18+ OS signal claim | | `high_click_precision` | Click precision above 0.8 — adult-like precision | | `erratic_mouse_velocity` | Mouse velocity above 2,000 px/s — erratic cursor movement | | `deliberate_mouse_velocity` | Mouse velocity below 600 px/s — smooth, deliberate movement | | `wobbly_mouse_path` | Path straightness below 0.3 — curved, corrective paths | | `straight_mouse_path` | Path straightness above 0.7 — efficient, direct paths | | `impulsive_click_no_hover` | Hover dwell time below 100 ms — clicking without reading | | `deliberate_hover_before_click` | Hover dwell time above 800 ms — reading before clicking | | `rapid_pointer_scroll_velocity` | Pointer scroll above 1,500 px/s — rapid mouse wheel scrolling | | `deliberate_pointer_scroll_pattern` | Pointer scroll below 300 px/s — deliberate scrolling | | `very_slow_typing` | Typing speed below 15 WPM | | `fast_typing` | Typing speed above 50 WPM | | `erratic_keystroke_rhythm` | Keystroke interval variance above 0.7 | | `consistent_keystroke_rhythm` | Keystroke interval variance at or below 0.3 | #### Face Estimation | Tag | Meaning | | --- | ------- | | `face_estimation_used` | Face estimation score was included in the assessment | | `face_estimation_provider_{name}` | Provider: `yoti`, `privado`, or `facetec` | #### Consent Synchronizer | Tag | Meaning | | --- | ------- | | `parental_consent_approved` | Parent has approved access | | `parental_consent_denied` | Parent has explicitly denied access | | `parental_consent_revoked` | Parent previously approved but has since revoked consent | | `parental_consent_pending` | Consent requested but no parental response yet | | `consent_source_os-system` | Consent via native OS framework (highest trust) | | `consent_source_third-party-wallet` | Consent via third-party identity wallet | | `consent_source_in-app` | Consent via app's own prompt (lowest trust) | #### System Tags | Tag | Meaning | | --- | ------- | | `os_signal_under_13` | OS signal indicates under-13 bracket | | `os_signal_minor_bracket` | OS signal indicates 13–15 bracket | | `os_signal_borderline_bracket` | OS signal indicates 16–17 bracket | | `os_signal_not_available` | OS signal not yet available (§1798.502 transition) | | `signal_override_active` | Clear & convincing threshold met; OS signal overridden | | `supplementary_evidence_below_threshold` | Evidence contradicts but below clear & convincing threshold | | `rule_source:1798.501.b.3.B` | Regulatory rule reference — always present for audit trail | ### Verification Token (Cryptographic Receipt) Every response includes a `verification_token` — a cryptographically signed receipt that proves exactly what A3 assessed, without A3 storing any user data. Token format: `base64url(payload).base64url(hmac_sha256_signature)` Decoded payload example: ```json { "v": 1, "ts": "2026-02-07T14:30:00.000Z", "verdict": "OVERRIDE", "assessed_bracket": "under-13", "os_bracket": "18-plus", "confidence": 0.96, "overridden": true, "evidence": [ "low_touch_precision", "high_motor_precision_delta", "signal_override_active", "rule_source:1798.501.b.3.B" ] } ``` The token payload contains **zero PII** — no session IDs, no behavioral metric values, no country codes, no IP addresses. Only the verdict and the evidence tags that explain the decision. ### Code Examples #### JavaScript (fetch) ```javascript const response = await fetch( 'https://api.a3api.io/v1/assurance/assess-age', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ os_signal: '18-plus', user_country_code: 'US', behavioral_metrics: { avg_touch_precision: 0.72, scroll_velocity: 1200, form_completion_time_ms: 8500, touch_pressure_variance: 0.12, multi_touch_frequency: 0.4, }, account_longevity: { account_age_days: 730, }, input_complexity: { keyboard_autocorrect_rate: 0.06, average_word_complexity_score: 0.65, }, }), }, ); const data = await response.json(); // 1. Two-phase decision tree if (data.signal_overridden) { // §1798.501(b)(3)(B): use the assessed bracket console.log('Override:', data.assessed_age_bracket); } else { // §1798.501(b)(3)(A): OS signal remains primary console.log('Primary:', data.os_signal_age_bracket); } // 2. Store the cryptographic receipt in YOUR logs await saveToYourAuditLog({ user_id: yourUserId, verification_token: data.verification_token, verdict: data.verdict, assessed_bracket: data.assessed_age_bracket, timestamp: new Date().toISOString(), }); ``` #### Python (requests) ```python import requests resp = requests.post( "https://api.a3api.io/v1/assurance/assess-age", headers={"Authorization": "Bearer YOUR_API_KEY"}, json={ "os_signal": "18-plus", "user_country_code": "US", "behavioral_metrics": { "avg_touch_precision": 0.72, "scroll_velocity": 1200, "form_completion_time_ms": 8500, "touch_pressure_variance": 0.12, "multi_touch_frequency": 0.4, }, "account_longevity": { "account_age_days": 730, }, "input_complexity": { "keyboard_autocorrect_rate": 0.06, "average_word_complexity_score": 0.65, }, }, ) data = resp.json() # 1. Two-phase decision tree if data["signal_overridden"]: primary_bracket = data["assessed_age_bracket"] else: primary_bracket = data["os_signal_age_bracket"] print(f"Bracket: {primary_bracket}") print(f"Verdict: {data['verdict']}") # 2. Store the cryptographic receipt in YOUR logs save_to_your_audit_log( user_id=your_user_id, verification_token=data["verification_token"], verdict=data["verdict"], assessed_bracket=data["assessed_age_bracket"], ) ``` --- ## AB 1043: The Digital Age Assurance Act — Developer Guide The California Digital Age Assurance Act (AB 1043) represents a fundamental shift in how applications handle user age. It moves away from scattered "age gates" and toward a standardized, device-level signaling infrastructure. ### Key Compliance Deadlines - **January 1, 2027** — The law becomes fully operative. All new application downloads must request age signals. - **July 1, 2027** — "Look-back" deadline. Developers must request signals for any app updated since January 1, 2026, even if it was downloaded before the law took effect. ### What AB 1043 Means for Developers #### 1. The "Actual Knowledge" Clause The most critical part of AB 1043 is that **receipt of a signal is deemed "actual knowledge" of a user's age**. Once your app receives a signal (e.g., "Under 13"), you are legally responsible for treating that user as a minor across all platforms and points of access. #### 2. Authoritative Signal Developers must treat the OS signal as the **primary indicator of age**. You cannot willfully disregard the signal unless you have "clear and convincing" internal information that the age is different. #### 3. Data Minimization The law prohibits developers from requesting more information than is strictly necessary for compliance. ### The Cost of Non-Compliance The California Attorney General has sole authority to enforce these provisions. Civil penalties are steep: | Violation Type | Penalty | | --- | --- | | Negligent violations | **$2,500** per affected child | | Intentional violations | **$7,500** per affected child | At scale, these fines compound quickly. An app with 100,000 minor users facing an intentional violation could be liable for up to **$750 million** in penalties. ### The Web Gap AB 1043 mandates OS-level age signals for app store-distributed applications. But browsers have no OS age signal. If your product has a web presence serving California users, the law creates compliance obligations without providing the mechanism. A3 solves this by treating the web as a first-class platform — when `os_signal` is `not-available`, the engine shifts to full supplementary assessment. ### How A3 Solves for AB 1043 - **Web-Native Age Assurance** — Browsers have no OS age signal. A3's signal fusion engine provides full age assessment for web applications through passively collected behavioral and contextual signals. - **Cross-Platform Normalization** — One API call normalizes Apple's Declared Age Range API, Google's Play Age Signals API, and browser-based signals into the four California-mandated brackets. One response format regardless of platform. - **No Friction, No Drop-Off** — Assessment runs passively using signals your app already has. Users never encounter a verification wall. - **Zero-Persistence Logs** — Generates audit logs required to prove "Good Faith Reliance" without storing user PII. - **Signed Receipts** — Provides HMAC-SHA256 receipts to prove the signal was requested and received across every platform — zero user data stored. ### Official Resources - [California Legislative Information: AB 1043 Full Text](https://leginfo.legislature.ca.gov/faces/billNavClient.xhtml?bill_id=202520260AB1043) (external; open in new window) --- ## Tech Stack - **Runtime**: AWS Lambda (serverless, auto-scaling) - **Framework**: NestJS (Node.js / TypeScript) - **Architecture**: Stateless REST API, zero data retention - **Validation**: Class-validator DTOs with strict input validation - **Latency**: Cold starts under 200 ms, warm invocations in single-digit milliseconds - **Scaling**: Automatic from zero to thousands of concurrent executions - **Documentation Site**: Next.js (App Router), MDX, deployed as standalone ## Pricing A3 uses transparent, usage-based pricing. No hidden fees, no minimum commitments. Developers pay only for API calls consumed. See [Pricing](https://www.a3api.io/pricing) for current tiers. ## Frequently Asked Questions ### What is A3 (Arcadia Age API)? Arcadia Age API (A3) provides compliant, frictionless age assurance built for the US market — without verification walls, identity friction, or storing a single byte of PII. Keep your users flowing. Stay compliant. Built specifically for California AB 1043 with zero data retention and audit-ready confidence scoring. ### How does A3 handle California AB 1043 compliance? A3 implements a two-phase signal fusion engine purpose-built for AB 1043. On native apps, the OS-provided age bracket is the primary indicator per §1798.501(b)(3)(A), with supplementary evidence able to override it only when meeting the "clear and convincing" standard per §1798.501(b)(3)(B). On the web — where no OS signal exists — supplementary signals become the primary assessment mechanism. A3 normalizes all platforms into one API call, one response format, and one audit trail. The architecture is fully stateless with zero data retention. ### Does A3 store facial images or biometric data? No. A3 is completely stateless. No images, biometric templates, or personally identifiable information are stored, logged, or persisted. Each request is processed and immediately forgotten. ### What is the latency of the A3 API? Cold starts are under 200 ms and warm invocations complete in single-digit milliseconds. The API runs on AWS Lambda for automatic scaling. ### What tech stack does A3 use? A3 is built with NestJS (TypeScript) on AWS Lambda. The documentation site uses Next.js with the App Router. All endpoints use class-validated DTOs with strict input validation. ### How much does A3 cost? A3 uses transparent, pay-per-use pricing with no hidden fees or minimum commitments. Visit a3api.io/pricing for current rates. ### How do I get started with A3? Sign up at portal.a3api.io for a free API key, then follow the quick start guide at www.a3api.io/docs.