Mask.ID Protect your identity. Prove your reputation.

The Mask.ID Attestation API

Let your users prove they are established, reputation-backed people — no email, no phone number, no bots. Your site receives the member’s Trust Index and, with their permission, the reputation evidence behind it. You never learn who they are on Mask.ID.

Quick start: download the single-file example relying party — maskid-example-rp.js (Node 18+, zero dependencies). Run node maskid-example-rp.js, open localhost:8080, and receive your first verified attestation in redirect mode with nothing publicly hosted. It implements the entire verify procedure documented below.

The privacy model, in three rules

  1. Pairwise identity. You receive a subject_id minted for your site alone. Two sites can’t correlate their users; nothing about the member is recoverable from it.
  2. Ranges, not records. Sensitive quantities arrive as buckets — "1k–10k PIV", "active within 30 days", "25+" — never exact amounts, dates, or ranks that could single a member out.
  3. Member-granted, member-revoked. Every data point beyond the Trust Index requires the member’s explicit consent, and any grant can be revoked at any time — your access ends that moment.

Scope packs

Your request's scopes list names the packs below by id; the member approves or unchecks each one at verification time. The Trust Index itself rides every grant — no scope needed.

Scope id Name Availability What the member is asked to share
profile Profile basics Live Broad account facts: profile type, that you cleared the real-person hurdle, account age and activity as ranges, Founding Member yes/no, invited yes/no.
referrals Referrals Live Aggregate referral strength: counts as ranges, your referrers' average Trust Index and verification rate. Never who they are.
reputation Trust Scores Live What your referrers said, averaged across all of them: real-person confidence, how well they know you, whether they'd recommend you. No individual answers.
presence Online Presence Live How verified your social footprint is: coverage score, verified platform count, crypto-key linkage. Not which accounts.
commitment Commitment Live Economic commitment as ranges: Trust Capital score, holdings and coin-age buckets, tip and username-market activity. Never exact amounts or addresses.
humanity Humanity Live Two "is this a person?" confidences and a roll-up: what your referrers witnessed (real-person and one-operator confidence, weighted up by video, audio or in-person contact) and how costly your profile would be to fake (real-person hurdle, oldest verified identity, key linkage, backing). Never who vouched or what any one of them said.
mno Masternode owner Live · Opt-in Reveal that you run a PIVX masternode.
location Location context Live · Opt-in Your region (continent only), language, and UTC offset — never your country or city.
platforms Verified platforms Live · Opt-in WHICH platforms you've verified (e.g. GitHub, X) — not your usernames on them. The combination is more identifying than the count alone.
competence Confirmed fields Live · Opt-in The fields of work you listed on your profile that at least 3 of your referrers confirmed, with the share who vouched. Never who vouched.
track_record Track record Live · Opt-in Counts of dealings that settled as agreed on other sites you've verified with — how many sites, how many people, and whether any were disputed. Never amounts, never which sites, never who.
pay_link Payment link Live · Opt-in Creates a private payment page for this site — a fresh shielded address just for them, behind a random link. People there can pay you directly; the site and its visitors never see your username, balance, or other addresses.

Data points

Each row names the scope that carries it. Live ships today. Live · Opt-in starts unchecked — the member must deliberately turn it on (the payment link is the one exception: it starts on, and the member may turn it off). Never available is a design guarantee, not a default: those rows can’t be requested, bought, or opted into.

Profile

The identity surface. Names, images, and free text never cross the API; dates and ranks travel only as ranges.

Data point Scope Availability Example
Trust Index (0–100) always Live "trust_index": 87
Trust Index tier — unproven · low · building · trusted (the platform's own bands) always Live "trust_index_tier": "trusted"
Profile type profile Live "profile_type": "individual"
Real-person hurdle cleared (anti-sybil gate) profile Live "earned_username": true
Account age profile Live "account_age": "1–2 years"
Recently active profile Live "active_within": "30 days"
Founding Member profile Live "founding_member": true
Invited by an existing member profile Live "invited": true
Masternode owner mno Live · Opt-in "mno_verified": true
Region / language / timezone location Live · Opt-in "region": "North America"
Username, Mask ID, display name, bio, avatar — Never available —
Member number, exact join date, exact last-seen time — Never available —

Referrals

Aggregates over the member's referral graph. The graph itself — who vouched for whom — is never exposed, in any direction.

Data point Scope Availability Example
Referrals pillar score (0–100) referrals Live "referrals_score": 72
Accepted referrals received referrals Live "referrals_received": "25+"
Accepted referrals given referrals Live "referrals_given": "10+"
Average Trust Index of referrers referrals Live "referrer_avg_ti": 64
Share of referrers with verified platforms referrals Live "referrers_verified_pct": 80
New referral accepted in the last 90 days referrals Live "referral_recent": true
Who referred whom — names, dates, notes, answers, connection paths — Never available —

Trust Scores

Averages of what referrers actually answered — computed only once ten or more referrers exist, so no individual answer is ever recoverable.

Data point Scope Availability Example
Overall Trust Score + tier reputation Live "trust_score": 78, "trust_tier": "Established"
Section scores — Confidence, Relationship, Identity, Reputation, Trust-with, Longevity reputation Live "identity_score": 84
“Real person” confidence (referrer average) reputation Live "real_person": 92
“Identity has stayed consistent” (referrer average) reputation Live "identity_consistent": 90
“The Mask ID belongs to them” confidence (referrer average) reputation Live "owns_user_id": 85
How well referrers know them (referrer average) reputation Live "familiarity": 80
In what capacity referrers know them (share per bucket; all-that-apply) reputation Live "capacity_mix": {"colleague": 40, "client": 60, "community": 30}
Still in contact this year (share of referrers) reputation Live "active_relationship_pct": 80
Known 5+ years and still in contact (share of referrers) reputation Live "long_standing_current_pct": 30
Would trust them with money (share of referrers who answered) reputation Live "trust_money_pct": 80
Would trust them with their home, vehicle or belongings (share) reputation Live "trust_property_pct": 70
Would trust them with the care of a person or animal (share) reputation Live "trust_care_pct": 60
Would trust their advice in their field (share) reputation Live "trust_advice_pct": 90
Would meet them alone in person (share) reputation Live "trust_meet_pct": 90
In contact weekly or more (share of referrers) reputation Live "frequent_contact_pct": 50
Have exchanged money or goods with them (share) reputation Live "transacted_pct": 60
Transactions went as agreed (share of those who transacted) reputation Live "settled_as_agreed_pct": 90
“One person controls this account” confidence (referrer average) reputation Live "sole_operator": 90
Respectful and civil (referrer average) reputation Live "conduct": 95
Responds and communicates clearly (referrer average) reputation Live "responsiveness": 85
Average familiarity / years known reputation Live "avg_years_known": "4 years"
Met in person / communicated directly (share of referrers) reputation Live "met_in_person_pct": 40
Video calls (share of referrers) reputation Live "video_calls_pct": 60
Audio calls (share of referrers) reputation Live "audio_calls_pct": 40
Completed a project together (share of referrers) reputation Live "project_together_pct": 50
Would recommend / would work with again (share) reputation Live "recommend_pct": 95
Professional reputation (referrer average) reputation Live "professional_rep": 88
Reliability as a person — shows up, keeps their word (referrer average) reputation Live "personal_reliability": 85
Commitment reliability — do they do what they say (referrer average) reputation Live "commitment_reliability": 85
Confirmed fields of work (≥3 referrers vouched; share who vouched) competence Live · Opt-in "competence": [{"code": "software.web", "domain": "Software & IT", "subdomain": "Web development", "endorsed_pct": 60}]
Any individual referrer's answers — Never available —

Online Presence

How much of the member's social footprint is cryptographically verified — never which accounts.

Data point Scope Availability Example
Coverage score (0–100) presence Live "presence_score": 75
Verified platform count presence Live "verified_platforms": 3
Cryptographic key linkage (Nostr / Vector) presence Live "crypto_linkage": true
Which platforms are verified platforms Live · Opt-in "platforms": ["github", "x"]
Oldest verified identity presence Live "oldest_identity": "5+ years"
Platform usernames, account names, profile URLs — Never available —

Trust Capital

Economic commitment behind the identity. Always ranges: an exact balance would identify the wallet on-chain, which is why exactness is never offered.

Data point Scope Availability Example
Trust Capital pillar score (0–100) commitment Live "capital_score": 61
Per-coin holdings + Coin Age, keyed by chain — native units, never FX commitment Live "capital": { "pivx": {"unit": "PIV", "commitment": "1k–10k", "coin_age_all": "10k–100k", "coin_age_6mo": "10k–100k", "coin_age_3mo": "1k–10k", "coin_age_30d": "100–1k"} }
Backing exists (referrers stake PIV behind them) commitment Live "backed": true
Tips received (distinct members) commitment Live "tipped_by": "5+ members"
Tips given (distinct members) commitment Live "tipped": "10+ members"
Parked Usernames held commitment Live "parked_held": "3+"
Usernames bought (lifetime) commitment Live "names_bought": "1+"
Usernames sold (lifetime) commitment Live "names_sold": "1+"
Which usernames — held, bought, or sold — Never available —
Exact balances, amounts, addresses, transactions — Never available —

Humanity

Is this a person? Two variables and a roll-up. Witnessed = people vouched. Costly = a bot could do this, but it wouldn't be cheap. Use human_confidence if you only want one number.

Data point Scope Availability Example
Witnessed (0–100): referrers' real-person and one-operator confidence, weighted up by video, audio or in-person contact. Absent below the 10-referrer threshold. humanity Live "human_witnessed": 90
Costly to fake (0–100): real-person hurdle, age of the oldest verified outside identity, cryptographic key linkage, PIV backing, and cross-site history (sites active in 90 days). Cost, not proof; available day one. humanity Live "human_costly": 55
Combined (0–100): Witnessed where it exists, else Costly capped at 60 so an unwitnessed profile never reads as confirmed. The one field to use if you want one. humanity Live "human_confidence": 90
A human/bot verdict — these are confidences, never a label — Never available —
Which referrers vouched, or what any one of them answered — Never available —

Cross-site

Reputation earned through this API itself — a network signal no single site can see alone.

Data point Scope Availability Example
Verified on other sites via this API commitment Live "attested_sites": "3+"
Other sites that re-read this member in the last 30 days (a re-read is a "session": the site checked them, typically at login). Never which sites. commitment Live "active_sites_30d": "1+"
Same, over 90 days — cross-site history is the best bot signal we hold. commitment Live "active_sites_90d": "3+"
Which sites those are — Never available —

Track record

Conduct reported by other sites the member verified with — dealings that settled as agreed, as counts of sites and people. Only sites with standing count, so a member's own fork moves nothing. Opt-in, and never an amount.

Data point Scope Availability Example
Sites with standing where dealings settled as agreed (a site earns standing by age and real members, so a member's own fork counts for nothing). track_record Live · Opt-in "settled_sites": "1+"
Distinct people dealt with, across those sites (a pair counts once per site). track_record Live · Opt-in "settled_counterparties": "5+"
Present (true) once at least five dealings settled and none were disputed; absent otherwise — never false. A negative only ever removes a positive. track_record Live · Opt-in "dispute_free": true
Amounts, prices, currencies, or totals — Never available —
Which sites, which counterparties, or when — Never available —
Disputes or flags as a number — a negative only removes a positive — Never available —

Payments

A verified payment endpoint, not payment processing. The pay link resolves to a fresh shielded address derived for your site alone; payments are peer-to-peer on-chain, and Mask.ID is never in the flow of funds.

Data point Scope Availability Example
Verified payment page (pairwise pay link) pay_link Live · Opt-in "pay_link": "https://app.mask.id/pay/hTgkxGkYyBWJow0KrTppBQ"
The member's wallet addresses or balances — Never available —
Any payment, amount, or transaction history — Never available —
The same pay address on any other site — links are pairwise, like subject IDs — Never available —

The full picture — every live field at once

A response with every pack and opt-in granted (generated from the same catalog the server builds payloads from; multi-value rows show a representative key). Real responses carry only the granted, statable fields.

{
  "v": 1,
  "type": "maskid.attestation",
  "key_id": "…", "subject_id": "msub_…",
  "rp_host": "your-site.example", "rp_user_id": "u_8347", "nonce": "…",
  "scopes": ["trust_index", "profile", "referrals", "reputation",
             "presence", "commitment", "humanity", "mno", "location",
             "platforms", "pay_link"],
  "trust_index": 87, "trust_index_tier": "trusted",
  "profile_type": "individual",
  "earned_username": true,
  "account_age": "1–2 years",
  "active_within": "30 days",
  "founding_member": true,
  "invited": true,
  "mno_verified": true,
  "region": "North America",
  "referrals_score": 72,
  "referrals_received": "25+",
  "referrals_given": "10+",
  "referrer_avg_ti": 64,
  "referrers_verified_pct": 80,
  "referral_recent": true,
  "trust_score": 78, "trust_tier": "Established",
  "identity_score": 84,
  "real_person": 92,
  "identity_consistent": 90,
  "owns_user_id": 85,
  "familiarity": 80,
  "capacity_mix": {"colleague": 40, "client": 60, "community": 30},
  "active_relationship_pct": 80,
  "long_standing_current_pct": 30,
  "trust_money_pct": 80,
  "trust_property_pct": 70,
  "trust_care_pct": 60,
  "trust_advice_pct": 90,
  "trust_meet_pct": 90,
  "frequent_contact_pct": 50,
  "transacted_pct": 60,
  "settled_as_agreed_pct": 90,
  "sole_operator": 90,
  "conduct": 95,
  "responsiveness": 85,
  "avg_years_known": "4 years",
  "met_in_person_pct": 40,
  "video_calls_pct": 60,
  "audio_calls_pct": 40,
  "project_together_pct": 50,
  "recommend_pct": 95,
  "professional_rep": 88,
  "personal_reliability": 85,
  "commitment_reliability": 85,
  "presence_score": 75,
  "verified_platforms": 3,
  "crypto_linkage": true,
  "platforms": ["github", "x"],
  "oldest_identity": "5+ years",
  "capital_score": 61,
  "capital": {
    "pivx": {"unit": "PIV", "commitment": "1k–10k", "coin_age_all": "10k–100k",
             "coin_age_6mo": "10k–100k", "coin_age_3mo": "1k–10k", "coin_age_30d": "100–1k"}
  },
  "backed": true,
  "tipped_by": "5+ members",
  "tipped": "10+ members",
  "parked_held": "3+",
  "names_bought": "1+",
  "names_sold": "1+",
  "attested_sites": "3+",
  "active_sites_30d": "1+",
  "active_sites_90d": "3+",
  "settled_sites": "1+",
  "settled_counterparties": "5+",
  "dispute_free": true,
  "human_witnessed": 90,
  "human_costly": 55,
  "human_confidence": 90,
  "competence": [{"code": "software.web", "domain": "Software & IT", "subdomain": "Web development", "endorsed_pct": 60}],
  "pay_link": "https://app.mask.id/pay/hTgkxGkYyBWJow0KrTppBQ",
  "issued_at": "2026-08-14T15:02:09Z",
  "api": "…/api/attest/v1/subject/msub_…"
}

Edge cases your integration must expect

  • Absent fields are normal, not errors. A field is omitted when the member declined its scope, the value is unset, or a privacy floor withholds it. Code for presence, never for position or completeness.
  • "trust_scores": "gated" replaces the whole reputation pack while the member has fewer than ten referrers — informative in itself.
  • The subject read answers 404 identically for unknown, revoked, and malformed subjects — treat any 404 as “no longer verified,” and expect it the moment a member revokes.
  • Ban the subject_id, not the account. It is stable for a member on your site: a member who revokes and later re-verifies receives the same subject_id, so a ban you keyed on it holds across revoke-and-rejoin. Getting a fresh one takes a whole new Mask.ID identity — the cost your tier gate sets.
  • Bucket values are display text ("1k–10k PIV", "25+") subject to refinement — compare for presence or equality, never parse them.
  • Webhook delivery retries a few times; any 2xx from you stops it. Verify-then-store must be idempotent per nonce.

How verification works

  1. Your site shows a verification request (QR + copyable string) to a user who clicked “Verify with Mask.ID”:
    {
      "v": 1,
      "rp_user_id": "u_8347",
      "nonce": "d41d8cd98f00b204e9800998",
      "webhook": "https://your-site.example/maskid/callback",
      "redirect": "https://your-site.example/settings/verified",
      "scopes": ["trust_index", "reputation", "commitment"]
    }
  2. The user reviews exactly what you’ll receive and approves it with a wallet signature on their Mask.ID.
  3. Mask.ID POSTs a signed response to your webhook (and/or returns the user to your redirect URL carrying the same response):
    {
      "v": 1,
      "type": "maskid.attestation",
      "subject_id": "msub_k5r2…",
      "rp_user_id": "u_8347",
      "nonce": "d41d8cd98f00b204e9800998",
      "scopes": ["trust_index", "reputation", "commitment"],
      "trust_index": 87, "trust_index_tier": "trusted",
      "trust_score": 78, "real_person": 92, "recommend_pct": 95,
      "capital": {"pivx": {"unit": "PIV", "commitment": "1k–10k", "coin_age_all": "10k–100k"}},
      "issued_at": "2026-08-13T14:02:09Z"
    }
  4. You verify one Ed25519 signature against the published platform key, store the subject_id, and may re-read the granted data while the member’s permission stands.

Endpoints

GET /.well-known/maskid-attest-key The Ed25519 verification key to pin. Currently key_id cdde5c8d68dbb162, public key 5REJlRin5SL5voivThSqUAqup7StIEpqauTQ38iOWgc.
Nostr (no endpoint) For members who opt in, Mask.ID’s Nostr key npub1uhq0ye3a9pjgml864ml38lenthgeuq2z0l3rh2pspl6wqrv8qrjq2mcrhf (NIP-05 _@mask.id) publishes their Trust Index tier as a NIP-85 kind 30382 assertion (d = the member’s pubkey; tags tier, username, NIP-32 label mask.id) plus NIP-58 badges for Building and Trusted. Read it from any relay; verify the signature against that key. Tier only — no number, no addresses.
GET /api/attest/v1/subject/:subject_id Re-read a verified member’s granted data. Answers 404 once the member revokes. Rate-limited; cache and poll gently.

API keys & pricing

Today, during the pilot, everything on this page is free and keyless — verification, webhooks, and the subject read. When API keys ship, pricing will meter monthly active verified members. The tier schedule, discounts, founding-site terms, and the free community tier live on the pricing page. Building against the API? We’d like to hear from you (Contact form in the footer) — early integrators get the founding-site terms.

Are you a Mask.ID member? The other half of this flow is yours: Verify Trust Index.