For businesses
Anonymous verification of humanity, age, and residence.
Confirm a visitor is a real human, an adult, or a resident of a specific country — without ever seeing their passport, date of birth, or address. The user keeps the data; you keep the proof.
What you get
What adding firmas does for your website
Add two short lines of code to your website — that’s the whole setup.
After that, when you need to check something about a visitor, they tap a button and hold up a code from their phone. You instantly get a simple yes or no: yes, a real person · yes, an adult · yes, a resident of a given country.
What you never see: their name, birthday, age, address, or any ID. Nothing about them is kept on our side, and they’re never followed from one website to another.
In plain terms, it does the job of two things you’d otherwise bolt on or pay for:
- the “Are you a robot?” check (like Google’s reCAPTCHA) — but with no puzzles, and
- age-verification services that make people upload an ID — but with no document and no data collected.
No puzzles. No ID uploads. No monthly bill to a third party. No personal data crossing your servers.
See it live
Try a real verification — no account needed.
Run a full credential check end to end, then drop the same button on your own page. This is exactly what your customers will see.
Run the full ceremony
Issue a test credential and verify it, start to finish, in your browser — the same round-trip your integration performs.
Open the live demo →The button your customers tap
This is the real Firmas widget. On your site it opens the camera, reads the customer’s QR, and returns a signed verdict — your page never sees their data.
Three traits, cryptographically attested.
Adult
The user is 18 or over.
Human
A real person, not a bot.
Resident
Resides in a specific country.
What we never see.
Trust is asymmetric: a verifier should learn nothing beyond yes/no.
No biometrics
No iris, face, or fingerprint capture. No camera-roll uploads. The phone's biometric sensor is used locally to unlock the user's own keys, never to identify them to us.
No raw documents on our servers
Bills, IDs, rentals, signatures — they all live encrypted on the user's device. We see ciphertext or nothing. Vouch is computed locally; only the verdict crosses the network.
No PII in the credential
A presentation says: "this person is over 18" — and nothing else. Not their name, not their birthday, not their address.
No cross-site linkability
Each verification mints a fresh, single-use presentation. Two sites that both verify the same user can't correlate them through Firmas.
How we know you're real.
Without biometrics, the trust signal has to come from somewhere. Ours: a graph of in-person, cryptographically-signed handshakes.
Anchored in real human-to-human exchanges.
Every contract a Firmas user co-signs in person — a rental, a freelance gig, a sublet, a small loan — produces an ECDSA P-256 signature pair: their device key and the counterparty's. We treat each unique counterparty pubkey as the strongest pro-human signal we can record without intruding. Two real handshakes plus one verified bill is enough to cross the threshold.
Documents alone can't cross the line.
A determined attacker could forge a portfolio of plausible PDFs in someone's name and ride OCR matches to the threshold. Our formula caps the document-only path below the 75% bar — to be vouched, the user must have at least one bilateral, signed handshake on file. Forging documents is cheap; forging real in-person interactions is not.
No volume hacks.
Same counterparty signing five deals collapses to one unit of credit. Self-signing (the user as their own counterparty) is filtered out. Diminishing returns on the curve cap how far a small ring of mutual-vouchers can boost each other.
Time honestly spent.
A small bonus rewards handshakes spread across weeks, not minutes. A burst of five sign-ups in one afternoon at one café earns less than two interactions a fortnight apart.
A forger's portfolio vs a real user's.
Documents only — bulk-forged PDFs
65%
Capped: cannot pass the 75% threshold.
Two real handshakes + one verified bill
92%
Crosses the threshold organically.
How a verification flows.
1
Visitor proves a trait.
Inside the Firmas app, the user picks the trait they want to share (e.g. Adult). Their device generates a fresh 60-second presentation, signed by the device key and our issuer key.
2
A short-lived QR is shown.
The QR encodes a URL of the form firmas.io/verify/<short_id>. Screenshots stop working within ~60 seconds because the underlying presentation expires.
3
Your site verifies.
Read the short_id, ask our verifier endpoint for a verdict — or verify the signature chain locally against our public JWKS. Either path returns a clean trait + traitValue + expiresAt.
Which integration fits you?
Pick what your stack already does — we’ll point you to the right path.
Recommended path · Easiest
Drop-in widget
Two lines of HTML and you have a verify button on your page. 14 KB minified, no dependencies, shadow-DOM isolated so it can't collide with your CSS. Listen for the firmas-verify:verdict event and you're done.
Best for sites that want age- or human-gating with zero protocol literacy.
Four integration paths.
Same credentials, four surfaces. Every credential issuable in two standard formats — SD-JWT VC and ISO 18013-5 mDoc. Pick the one that matches how your stack already works.
Easiest
Drop-in widget
Two lines of HTML and you have a verify button on your page. 14 KB minified, no dependencies, shadow-DOM isolated so it can't collide with your CSS. Listen for the firmas-verify:verdict event and you're done.
Best for sites that want age- or human-gating with zero protocol literacy.
Hosted verifier
OpenID4VP — we run the verifier, you poll the result
POST a Presentation Definition to /api/vouch/oid4vp-verifier/request, encode the returned openid4vp:// URL in a QR, poll /api/vouch/oid4vp-verifier/result/{id} for the verdict. firmas runs the full ceremony — Request Object signing, response intake, signature + status-list + key-binding verification — so you don't have to.
Best for businesses that want OpenID4VP without operating an OpenID4VP verifier of their own.
Bring your own verifier
OpenID4VP — full bilateral, both wire formats
Wallet-initiated and verifier-initiated flows both supported. The user presents from any OpenID4VP-aware wallet (the Firmas app, EUDI Reference Wallet, Walt.id, Procivis, Sphereon); your verifier validates against our public JWKS. Both wire formats accepted: SD-JWT VC (JSON, JWT, selective disclosure) and mDoc (ISO 18013-5, binary CBOR + COSE_Sign1).
Best for businesses already running a generic OpenID4VP verifier, or building their own verification UX with full protocol control.
Wallet developers
OpenID4VCI — issue Firmas credentials in the format you want
Discoverable at /.well-known/openid-credential-issuer per OpenID for Verifiable Credential Issuance 1.0. Six configurations: three SD-JWT VC (firmas_adult_v1, firmas_human_v1, firmas_residency_v1) and three mDoc (firmas_adult_mdoc_v1, firmas_human_mdoc_v1, firmas_residency_mdoc_v1). All ES256, holder-bound via cnf.jwk or COSE_Key, revocable via the IETF Token Status List.
Best for wallet developers, identity-platform aggregators, and federation builders who want Firmas attestations alongside other issuers in a multi-credential wallet.
Live in 60 seconds.
Three steps. The first two are front-end; the third is the one that makes the verdict trustworthy.
1 · Drop in the button
Two lines of HTML. No build step, no dependencies.
<script src="https://www.firmas.io/widget/v1.js"></script>
<firmas-verify trait="over_18"></firmas-verify>2 · Read the verdict
Listen for the result event and react in your UI.
document.querySelector('firmas-verify')
.addEventListener('firmas-verify:verdict', (e) => {
// e.detail = { ok, trait, traitValue, shortId, error, … }
if (e.detail.ok) showPending(); // optimistic UI
confirmOnServer(e.detail.shortId); // authoritative check ↓
});★ 3 · Confirm on your server
The browser event is for UX. Before you grant anything of value, re-check the short id from your backend — it can’t be forged and is valid for ~60 seconds.
// Your backend — the verdict you can trust.
// shortId can't be forged and is valid for ~60 seconds.
const r = await fetch(
`https://www.firmas.io/api/vouch/verify?id=${shortId}`);
const v = await r.json();
if (v.valid && v.trait === 'over_18') grantAccess();That’s it. Full patterns — curl, Node, Python, self-verification against our JWKS — live in the integration docs. Full integration docs →
Trust details.
All Firmas verifications are signed with ECDSA P-256. Our public keys live at /.well-known/firmas-vouch-jwks.json — fetch them, cache them, verify against them. Each presentation contains two signatures: one by the user's device key (proves freshness, only the user can mint a fresh presentation) and one by our issuer key (proves we vouched for the trait). The chain is verifiable in every major language; the JWKS endpoint serves a standard RFC 7517 keyset.
In-person contracts and Karma handshakes are anchored to Base Mainnet. The anchor is the audit trail for the handshake graph — tamper-evident and timestamped. It records that signatures existed at a point in time. It is not, and does not claim to be, a cryptographic proof of personhood: the strongest pro-human signal we can record without intruding is the bilateral signature itself, not the ledger entry. The trust in Human comes from the graph topology and the safeguards above, not from the blockchain.
Where we’re a great fit — and where we’re not (yet)
We’d rather be straight with you than oversell. firmas is a privacy-first proof — not a government ID card.
✓ Great fit for
- stopping bots and fake sign-ups
- confirming someone is an adult where a privacy-friendly check is accepted
- confirming someone lives in a particular country
Where we fall short, for now
Some laws ask for a government-grade or officially-certified age check. The European Union is building an official age-verification system (its “blueprint”), being piloted in several countries including Spain; and some places — like California’s upcoming phone-level age signal, in force from 2027 — set their own bars.
firmas is not yet certified under the EU blueprint, is not on any official EU trusted list, and is not a government-issued credential. Our level of assurance is “substantial” — strong, but not the very top “qualified” tier some rules demand.
So where the law specifically requires that top tier, firmas on its own isn’t a drop-in replacement. There, use firmas alongside an approved method — or wait for the formal certifications we’re working towards. We’ll tell you up front, every time.
Partner questions.
Go-live checklist
Stuck or scaling? firmasfb@rindogatan.com
Ready to integrate?
Four integration shapes — from a two-line widget to local JWKS verification. Pick whichever fits your stack.
Read the integration docs →Or email us: firmasfb@rindogatan.com