Commands
Verify
The verify command lets you use incognito actions inside of your mini app. Incognito actions are a primitive of World ID and allow you to gate functionality behind a unique human check.
To use incognito actions, first create one in the Developer Portal.
Using the command
Async handlersEvent listeners
Sending the command & handling the response
MiniKit uses a slightly different input payload than IDKit. We do not need to pass in the app_id
.
export type VerifyCommandInput = {
action: string
signal?: string
verification_level?: VerificationLevel // Default: Orb
}
type MiniAppVerifyActionSuccessPayload = {
status: 'success'
proof: string
merkle_root: string
nullifier_hash: string
verification_level: VerificationLevel
version: number
}
app/page.tsx
import { MiniKit, VerifyCommandInput, VerificationLevel, ISuccessResult } from '@worldcoin/minikit-js'
const verifyPayload: VerifyCommandInput = {
action: 'voting-action', // This is your action ID from the Developer Portal
signal: '0x12312', // Optional additional data
verification_level: VerificationLevel.Orb, // Orb | Device
}
const handleVerify = async () => {
if (!MiniKit.isInstalled()) {
return
}
// World App will open a drawer prompting the user to confirm the operation, promise is resolved once user confirms or cancels
const {finalPayload} = await MiniKit.commandsAsync.verify(verifyPayload)
if (finalPayload.status === 'error') {
return console.log('Error payload', finalPayload)
}
// Verify the proof in the backend
const verifyResponse = await fetch('/api/verify', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
payload: finalPayload as ISuccessResult, // Parses only the fields we need to verify
action: 'voting-action',
signal: '0x12312', // Optional
}),
})
// TODO: Handle Success!
const verifyResponseJson = await verifyResponse.json()
if (verifyResponseJson.status === 200) {
console.log('Verification success!')
}
}
Verifying the proof
You should pass the proof to your backend when verifying proofs via the API. Users can manipulate information in the frontend, so the proof must be verified in a trusted environment.
Successful responses will return a MiniAppVerifyActionSuccessPayload
.
type MiniAppVerifyActionSuccessPayload = {
status: 'success'
proof: string
merkle_root: string
nullifier_hash: string
verification_level: VerificationLevel
version: number
}
To verify the proof, you will need to make a backend route.
app/api/verify/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { verifyCloudProof, IVerifyResponse, ISuccessResult } from '@worldcoin/minikit-js'
interface IRequestPayload {
payload: ISuccessResult
action: string
signal: string | undefined
}
export async function POST(req: NextRequest) {
const { payload, action, signal } = (await req.json()) as IRequestPayload
const app_id = process.env.APP_ID as `app_${string}`
const verifyRes = (await verifyCloudProof(payload, app_id, action, signal)) as IVerifyResponse // Wrapper on this
if (verifyRes.success) {
// This is where you should perform backend actions if the verification succeeds
// Such as, setting a user as "verified" in a database
return NextResponse.json({ verifyRes, status: 200 })
} else {
// This is where you should handle errors from the World ID /verify endpoint.
// Usually these errors are due to a user having already verified.
return NextResponse.json({ verifyRes, status: 400 })
}
}
Success Result on World App
If implemented correctly, the user will see the following drawer on World App.