Skip to main content
This page describes how partner applications can integrate with Proof to verify users. Partners can redirect users to Proof for verification and query the Proof API to check verification status.

Integration Overview

Deep Linking

Partners can redirect users to Proof with pre-populated data to streamline the verification flow. When the user completes verification, they are redirected back to your application.
ParameterRequiredDescription
walletYesThe Solana wallet address to link
signatureYesPre-signed ownership proof (base58 encoded)
timestampYesUnix timestamp in milliseconds when signature was created
redirect_uriYesURL to redirect the user after verification
projectIdNoYour project identifier for tracking
Build the deep link URL with query parameters:
https://dflow.net/proof?wallet={address}&signature={signature}&timestamp={timestamp}&redirect_uri={encodedRedirectUri}

Generating the Signature

The user must sign a message proving wallet ownership. The message format is:
Proof KYC verification: {timestamp}
Where {timestamp} is the Unix timestamp in milliseconds (13 digits).
import { Connection, PublicKey } from "@solana/web3.js";
import bs58 from "bs58";

async function createProofDeepLink(
  wallet: { publicKey: PublicKey; signMessage: (message: Uint8Array) => Promise<Uint8Array> },
  redirectUri: string
): Promise<string> {
  // Generate timestamp in milliseconds
  const timestamp = Date.now();
  
  // Create the message to sign
  const message = `Proof KYC verification: ${timestamp}`;
  const messageBytes = new TextEncoder().encode(message);
  
  // Request signature from wallet
  const signatureBytes = await wallet.signMessage(messageBytes);
  const signature = bs58.encode(signatureBytes);
  
  // Build the deep link URL
  const params = new URLSearchParams({
    wallet: wallet.publicKey.toBase58(),
    signature,
    timestamp: timestamp.toString(),
    redirect_uri: redirectUri,
  });
  
  return `https://dflow.net/proof?${params.toString()}`;
}

// Usage
const deepLink = await createProofDeepLink(wallet, "https://yourapp.com/callback");
window.location.href = deepLink;

Handling the Return

When the user completes verification (or cancels), they are redirected to your redirect_uri. Query the verification API to confirm their status.
async function handleProofCallback(walletAddress: string): Promise<boolean> {
  const response = await fetch(
    `https://proof.dflow.net/verify/${walletAddress}`
  );
  const { verified } = await response.json();
  return verified;
}

Verification API

The verification API lets you check if a wallet address is linked to a verified identity. This is a public endpoint that does not require authentication.

Endpoint

GET https://proof.dflow.net/verify/{address}

Parameters

ParameterLocationTypeDescription
addresspathstringSolana wallet address (32-44 characters)

Response

{
  "verified": true
}
FieldTypeDescription
verifiedbooleanWhether the wallet is linked to a verified identity

Example: Checking Verification Status

async function isWalletVerified(address: string): Promise<boolean> {
  const response = await fetch(
    `https://proof.dflow.net/verify/${address}`
  );
  
  if (!response.ok) {
    throw new Error(`Failed to check verification: ${response.status}`);
  }
  
  const { verified } = await response.json();
  return verified;
}

// Usage
const walletAddress = "DFlow1111111111111111111111111111111111111";
const verified = await isWalletVerified(walletAddress);

if (verified) {
  console.log("Wallet is verified");
} else {
  console.log("Wallet is not verified");
}

Example: Gating Features

async function handleRestrictedAction(walletAddress: string) {
  const verified = await isWalletVerified(walletAddress);
  
  if (!verified) {
    // Redirect to Proof for verification
    const redirectUri = encodeURIComponent(window.location.href);
    window.location.href = `https://dflow.net/proof?redirect_uri=${redirectUri}`;
    return;
  }
  
  // User is verified, proceed with action
  await performRestrictedAction();
}

Integration Flow

Here’s a complete integration flow combining deep linking and the verification API:

Best Practices

Cache Verification Status

Verification status is stable once a user is verified. Consider caching the result to reduce API calls:
const verificationCache = new Map<string, boolean>();

async function isWalletVerified(address: string): Promise<boolean> {
  // Check cache first
  if (verificationCache.has(address)) {
    return verificationCache.get(address)!;
  }
  
  const response = await fetch(
    `https://proof.dflow.net/verify/${address}`
  );
  const { verified } = await response.json();
  
  // Cache verified status (don't cache unverified as it may change)
  if (verified) {
    verificationCache.set(address, true);
  }
  
  return verified;
}

Handle Edge Cases

  • Signature expiration: Generate fresh signatures close to redirect time
  • User cancellation: Handle cases where users return without completing verification
  • Network errors: Implement retry logic for API calls

Security Considerations

  • Always verify wallet ownership server-side when performing sensitive actions
  • Do not trust client-side verification status alone for security-critical operations
  • Use HTTPS for all API calls and redirects

API Reference

For complete API documentation, see the Proof API Reference: