Getting Started

Quick Start

Get an Althea-verified user into your Solana dApp in four steps. No backend changes. No data to store.

1. Install

Add the SDK and the Solana wallet adapter to your project.

terminal
npm install afrzk-sdk @solana/wallet-adapter-react

2. Check the connected wallet

Always start with checkAttestation(). Verified users carry their attestation in their wallet, so most users will already pass after the first check and never see your verification screen again.

check.ts
import { checkAttestation } from 'afrzk-sdk'
import { useWallet } from '@solana/wallet-adapter-react'

const { publicKey } = useWallet()

const status = await checkAttestation(
  publicKey!.toString(),
  'mainnet-beta'
)

if (status.verified) {
  // User already has a valid attestation on this wallet
}

3. Run the verification flow

Only if the wallet isn't already attested, kick off the three-step flow. The user enters their NIN or BVN once. Althea confirms it, generates a ZK proof inside the browser, and submits the proof to the Anchor program. You never see the NIN.

verify.ts
import {
  verifyIdentity,
  generateProof,
  submitProof,
} from 'afrzk-sdk'

async function runVerification(nin: string, dob: string, wallet) {
  // 1. Verify identity via Althea service
  const credential = await verifyIdentity({
    idType: 'NIN',
    idNumber: nin,
    dob,
  })

  // 2. Generate ZK proof in browser
  // The credential is wiped from memory after this call
  const proof = await generateProof(credential)

  // 3. Submit to Solana - user signs the transaction
  const result = await submitProof(proof, wallet, 'mainnet-beta')

  return result.txSignature
}

Wipe the credential immediately

The credential returned from verifyIdentity() is a signed bundle that lives in memory only. Pass it directly to generateProof() — never persist it, never log it, never send it anywhere.

4. Gate your features

Wrap any verified-only route or component in a small gate. Below is a complete React component you can copy-paste. It checks the wallet on every mount and either renders the protected content or shows a link to your verification page.

VerifiedGate.tsx
'use client'

import { useEffect, useState, type ReactNode } from 'react'
import { useWallet } from '@solana/wallet-adapter-react'
import { checkAttestation } from 'afrzk-sdk'

export function VerifiedGate({ children }: { children: ReactNode }) {
  const { publicKey } = useWallet()
  const [verified, setVerified] = useState<boolean | null>(null)

  useEffect(() => {
    if (!publicKey) {
      setVerified(false)
      return
    }
    checkAttestation(publicKey.toString(), 'mainnet-beta')
      .then((s) => setVerified(s.verified))
      .catch(() => setVerified(false))
  }, [publicKey])

  if (verified === null) return <p>Checking…</p>
  if (!verified) return <a href="/verify">Verify with Althea →</a>
  return <>{children}</>
}

That is the entire integration.

Five SDK functions, one component, one route. You are now serving verified Nigerian adults — without ever touching their personal data.

Where to go next