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.

Sending the command

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
};

Using the verify command:

app/page.tsx

import { MiniKit, VerifyCommandInput, VerificationLevel} 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 payload = MiniKit.commands.verify(verifyPayload);

Listening for the response

Upon receiving the command from your mini app, World App will open a drawer prompting the user to confirm the operation.

app/page.tsx

import { MiniKit, ResponseEvent, ISuccessResult, MiniAppVerifyActionPayload } from '@worldcoin/minikit-js';

// ...
  useEffect(() => {
    if (!MiniKit.isInstalled()) {
      return;
    }

    MiniKit.subscribe(ResponseEvent.MiniAppVerifyAction, async (response: MiniAppVerifyActionPayload) => {
      if (response.status === "error") {
        return console.log("Error payload", response);
      }

      // Verify the proof in the backend
      const verifyResponse = await fetch("/api/verify", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          payload: response 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!");
      }
    });

    return () => {
      MiniKit.unsubscribe(ResponseEvent.MiniAppVerifyAction);
    };
  }, []);

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 { verifyCloudProof, IVerifyResponse, ISuccessResult } from '@worldcoin/minikit-js'
import { NextRequest, NextResponse } from "next/server";

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 });
    }
};