Overview
Verified Human is the credential the Billions Wallet issues after a user completes document-based verification, an NFC passport, Aadhaar, driving license, or national ID. Any backend can request proof of this credential from a user who holds it, then confirm the proof on its own servers before granting access, distributing a reward, or unlocking a feature. This guide covers the full verification flow: requesting the credential, the user completing it in the Billions Wallet, and confirming the resulting proof on your backend.This is a reference example to get you running locally and to show the shape of the integration. For a production rollout, reach out to the Billions integration team — they’ll provide the issuer and schema values your verifier needs, and can walk you through rate limits and the persistent storage your deployment requires.
Verification Flow
A verification request is a standard DID-authentication request with one addition: ascope naming the exact credential and issuer you’ll accept as proof.
1
User requests verification
Once a user is signed into your app, your frontend asks the backend for a verification request scoped to that user’s session.
2
Backend builds a scoped authorization request
The backend generates an authorization request and attaches a proof request to it, naming the Verified Human credential it’s asking the user to present.
3
User opens the Billions Wallet
The request is encoded into a Universal Link. Opening it in the Billions Wallet shows the user exactly what’s being asked: proof that they hold a genuine Verified Human credential.
4
Wallet generates the proof
If the user holds the credential, the wallet builds a zero-knowledge proof against it and signs a token, without exposing the underlying document data.
5
Wallet posts to your callback
The wallet sends the signed token to your backend’s callback endpoint, tagged with the session ID from Step 1.
6
Backend verifies and checks for replay
Your backend verifies the token against the request it stored, then checks the proof’s nullifier, a privacy-preserving identifier unique to that person, to confirm the same human hasn’t already verified through a different session.
7
Session marked verified
Once the nullifier check passes, mark the session verified in your store. From here you can gate access, unlock a reward, or anything else that depends on the user being a document-verified human.
Verification Query Structure
This is the structure of the verification query used to make a verification request, naming the credential you’re asking the user to present:circuitId: the circuit used to generate and verify the proof.allowedIssuers: the DIDs allowed to have issued the credential. Verified Human accepts proofs from either of Billions Network’s issuers listed above.context: the schema context for theBasicPersontype, hosted on IPFS.type: the credential type being requested, alwaysBasicPersonfor Verified Human.
Need a custom query for your specific requirements, whether that’s a variation on Verified Human, Proof of Uniqueness, or a combination of the two? Reach out to the Billions integration team to discuss it.
Setup Instructions
Prerequisites
- Public URL for callbacks (use ngrok for local development)
- A Verifier DID
Example Repository
The steps below follow the same verifier scaffold used for Proof of Uniqueness verification — clone it to follow along. Swapping in the query above is what adapts it to Verified Human.1. Server and Request Handler
Sets up the server and the endpoint that builds a scoped verification request for each new session.HOST_URL and AUDIENCE_DID are read from configuration; the Verified Human issuer DIDs and schema context are the same values shown in Verification Query Structure above.
Get Your Verifier DID: Sign in to your Billions Wallet and copy your profile DID to use during setup. This is your
AUDIENCE_DID — it represents the entity doing the verification, which in this case is your application.Generate
nullifierSessionId fresh for every request, as shown here. Computing it once at server startup and reusing it across sessions breaks the anti-replay check every subsequent verification depends on.2. Verification Callback
Verifies the proof the wallet sends back, and enforces that a given nullifier, a given real person, can only complete this verification once.userVerificationMap before marking a session verified is what stops the same human from claiming a reward twice under two different accounts.
Testing Steps
- Start the server:
node index.js - Visit
http://localhost:8080, the example ships a static demo page with a “Verify with Billions” button wired to the flow above. - Open the generated link in the Billions Wallet and complete verification with a Verified Human credential.
- Poll
GET /api/status/<sessionId>(or watch the demo page) until the status flips tosuccess.
Troubleshooting
The callback endpoint never fires
The callback endpoint never fires
HOST_URL must be a publicly reachable URL, not localhost. Use ngrok for local development, and confirm the callback URI includes the sessionId query parameter.'No valid proof found in response'
'No valid proof found in response'
The wallet returned a proof, but not one matching the
circuitId and id your backend is looking for. This usually means the id on the proofRequest doesn’t match the sessionId used to build the callback URI. They must be the same value.'This person has already verified'
'This person has already verified'
The nullifier from this proof already has a
verified: true record, meaning this same human has completed verification through a different session already. This is the anti-Sybil check working as intended. If you see this unexpectedly during testing, it likely means you’re reusing the same Verified Human credential across test sessions, which is expected behavior, not a bug.Verification fails with a state resolution error
Verification fails with a state resolution error
The
resolvers map only knows about the networks it’s configured for (billions:main , privado:main). Confirm your RPC and contract configuration is correct, and that the RPC endpoint is reachable from your server.Learn More
Verified Human
What the credential is, and how users claim it.