Skip to content

Installation and configuration

Quickstart

Goal: With the quick start example, you will get a complete and working application running in less than 15 minutes to verify user credentials. Follow the following steps to clone the starter repository, configure your Github token, and running a minimal Next.js application that uses the Averer Web SDK.

Prerequisites

  • Node.js v18 or later
  • A GitHub account with a Personal Access Token (classic) that has the read:packages scope

Step 1: Clone the starter kit

We've created a pre-configured Next.js starter kit with the basic backend and frontend structure already in place so you can use it as a guide for your implementation.

git clone https://github.com/averer/averer-websdk-quickstart.git
cd averer-websdk-quickstart

Step 2: Configure npm and install dependencies

The starter kit uses GitHub Packages for the @averer scope. To install Averer packages, you need to configure npm so it knows where to find them and how to authenticate.

  1. Create the .npmrc file: Inside the averer-websdk-quickstart directory, edit a file named .npmrc
  2. Add configuration: Paste the following lines into .npmrc, replacing YOUR_GITHUB_TOKEN with your actual token.
@averer:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN
  1. Install packages: Authenticate with your GitHub token when prompted.
npm install

Step 3: Setup env

Create a .env file by copying the .env.sample or use this command

cp .env.sample .env

Note: To obtain the VITE_CONFIG_ID, please contact Averer support.

Step 4: Run the application

The starter kit is configured to run both the backend verifier and the frontend application at the same time.

npm run dev

This starts the Next.js app at http://localhost:3000, where you can complete your first eligibility check using the Averer Web SDK.

SDK Setup

Prerequisites

  • Node.js v18 or later

Install the SDK

npm install @averer/averer-websdk

Initialise the SDK

The snippet below demonstrates how to render the SDK inside a Next.js App Router page. Adjust imports and component placement in your application.

Note: To obtain a configId, please contact Averer support.

'use client';

import {
  AvererWebSdk,
  AvererSdkProvider,
  type SdkQuery,
  type SdkSuccessRes,
} from '@averer/averer-websdk';

export default function EligibilityPage() {
  const sdkQuery: SdkQuery = [
    {
      id: 5,
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      circuitId: 'credentialAtomicQuerySigV2' as any,
      subjectTitle: 'Pass AML & CTF Checks',
      query: {
        allowedIssuers: [
          'did:receptor:redbelly:testnet:31K3oHpCV428AkXUYTL89q6LCvHcSqHirdv7z6LHtu9',
        ],
        type: 'AMLCTFCredential',
        context:
          'https://raw.githubusercontent.com/redbellynetwork/receptor-schema/refs/heads/main/schemas/json-ld/AMLCTFCredential.jsonld',
        skipClaimRevocationCheck: true,
        credentialSubject: {
          amlCheckStatus: { $eq: 'passed' },
        },
      },
    },
  ];

  const handleSuccess = (data: SdkSuccessRes) => {
    if (data.eligibility.passed) {
      console.log('✅ Verification successful', data);
    }
  };

  const handleError = (reason: string) => {
    console.error('❌ Verification failed:', reason);
  };

  return (
    <AvererSdkProvider configId="your-config-id">
      <AvererWebSdk
        appName="Refund"
        sdkQuery={sdkQuery}
        onSuccess={handleSuccess}
        onError={handleError}
      />
    </AvererSdkProvider>
  );
}

For other examples on how to setup the queries based on your preferred Proof Method and Eligibility Criteria, refer to Choosing Your Proof Method and Configuring Eligibility Criteria

API Reference

The AvererWebSdkProps type defines the configuration for the AvererWebSdk component.

type AvererWebSdkProps = {
  appName: string;
  sdkQuery: SdkQuery;
  onSuccess?: (data: SdkSuccessRes) => void;
  onError?: (reason: string) => void;
};
  • appName : Name of your application displayed in the averer-websdk UI.
  • sdkQuery : Eligibility criteria the external user must satisfy.
  • onSuccess : Callback fired when all queries are successfully proven.
  • onError : Callback fired when the user cancels, rejects, or an error occurs in the SDK flow.

Sub-types Used

1. SdkQuery

type SdkQuery = Array<{
  id: number;
  circuitId: string;
  subjectTitle: string;
  optional?: boolean;
  query: ZeroKnowledgeProofQuery;
  params?: {
    nullifierSessionId?: string | number;
  };
}>;
  • id : A unique numeric identifier for the query.
  • circuitId : The identifier of the circuit used for zero-knowledge proof generation(e.g., credentialAtomicQuerySigV2).
  • subjectTitle : A short title describing the verification purpose (e.g., “Age above 18 check”).
  • query : Contains the proof requirements and constraints defined in ZeroKnowledgeProofQuery.

2. ZeroKnowledgeProofQuery

type ZeroKnowledgeProofQuery = {
  allowedIssuers: string[];
  context: string;
  credentialSubject?: JsonDocumentObject;
  proofType?: string;
  skipClaimRevocationCheck?: boolean;
  groupId?: number;
  type: string;
};
  • allowedIssuers : List of issuer DIDs permitted to provide the credential for this proof.
  • context : JSON-LD context defining the schema/environment of the credential.
  • credentialSubject : Data object describing the fields required from the user’s verifiable credential (e.g. age, citizenship).
  • type : The credential type the query expects (e.g. a specific VC schema type).

3. SdkSuccessRes

type SdkSuccessRes = {
  walletAddress: string;

  user: {
    email?: string;
    isAuthenticated: boolean;
    did?: string;
  };

  proofs: Array<{
    id: string | number;
    circuitId: string;
    subjectTitle: string;
    status: 'valid' | 'failed';
    proofData: {
      credentialType: string;
      rawProof?: {
        id: number | string;
        circuitId: string;
        vp?: {
          type: string;
          verifiableCredential: {
            type: string | string[];
            credentialSubject: JsonDocumentObject;
          };
        };
      };
    };
  }>;

  eligibility: {
    passed: boolean;
    summary: string;
  };
};
  • proofs[].proofData.rawProof.vp.verifiableCredential.credentialSubject : Represents the actual credential data contained inside the user’s submitted verifiable credential. This includes the specific fields that were proven (for example: age, nationality, membership, etc.). This is the final resolved credential subject after verification.

  • eligibility.passed : Indicates whether the user satisfied all required proof checks.

Averer Wallet

Read only actions/Viem Public Client

If you want to read data from the blockchain, you will want a “Public Client” (Viem terminology)

import { useAvererWallet } from '@averer/averer-websdk';

const EnsName = () => {
  const wallet = useAvererWallet();

  const [ens, setEns] = useState<string | null>(null);

  const fetchEnsName = async () => {
    if (wallet) {
      const publicClient = await wallet.getPublicClient();
      const name = await publicClient.getEnsName({
        address: wallet.address,
      });
      setEns(name);
    }
  };

  return (
    <div>
      <button onClick={fetchEnsName}>Get ENS Name</button>
      {ens && <p>ENS Name: {ens}</p>}
    </div>
  );
};

Write actions/Viem Wallet Client

If you want to write data to the blockchain, you will need a “Wallet Client” (Viem terminology), or a “Signer” (Ethers terminology). Both allow you to sign transactions with the private key.

const SendTransaction = () => {
  const wallet = useAvererWallet();

  const SendTransaction = async () => {
    if (!wallet) {
      console.error('No wallet connected');
      return;
    }

    try {
      const walletClient = await wallet.getWalletClient();
      const txHash = await walletClient.sendTransaction({
        to: '0xRecipientAddressHere',
        value: 1000000000000000000n,
      });
      console.log('Transaction sent with hash:', txHash);
    } catch (error) {
      console.error('Error sending transaction:', error);
    }
  };

  return (
    <div>
      <button onClick={SendTransaction}>Send Transaction</button>
    </div>
  );
};

Get balance

const WalletBalance = () => {
  const avererWallet = useAvererWallet();

  const [balance, setBalance] = useState<string | undefined>(undefined);

  const fetchBalance = async () => {
    if (avererWallet) {
      const bal = await avererWallet.getBalance();
      setBalance(bal);
    }
  };

  return (
    <div>
      <button onClick={fetchBalance}>Get Wallet Balance</button>
      {balance && <p>Balance: {balance} ETH</p>}
    </div>
  );
};

Sign a message

const SignMessageButton = () => {
  const avererWallet = useAvererWallet();

  const handleSignMessage = async () => {
    if (!avererWallet) {
      console.error('No Averer wallet connected');
      return;
    }

    try {
      const message = 'Hello from Averer Wallet!';
      const signature = await avererWallet.signMessage(message);
      console.log('Message signed successfully:', signature);
    } catch (error) {
      console.error('Error signing message:', error);
    }
  };
  return <button onClick={handleSignMessage}>Sign Message</button>;
};