Quickstarts
Developer Quickstart

Developer Quickstart

Get from zero to a working session-backed request in five steps. No portal account required.

💡

Want to skip setup? Open the playground — a fully-wired sandbox that runs in your browser, no install, no API key. Come back to this page when you're ready to wire it into your own project.

Prerequisites

  • Node.js 18+ or Bun
  • A browser supporting WebAuthn/Passkeys (Chrome 108+, Safari 16+, Firefox 118+)

That's it. You do not need a Veridex account, an API key, or a funded wallet to complete this quickstart — testnet sessions work with a default public relayer (rate-limited to 5 tx/hour per IP).

Step 1: Install the SDK

npm install @veridex/sdk ethers
# or
bun add @veridex/sdk ethers

Current published version: @veridex/sdk@1.1.5. The SDK targets the live EVM testnets today — Base Sepolia (hub), Ethereum Sepolia, Optimism Sepolia, Arbitrum Sepolia, Monad Testnet, and Polygon Amoy. Mainnet is not yet enabled.

Step 2: Initialize the SDK

The createSDK factory defaults to testnet. Pick a chain name; everything else has sane defaults.

import { createSDK } from '@veridex/sdk';
 
// Minimal: Base Sepolia, public relayer
const sdk = createSDK('base');

Need gasless transactions with your own quota? Create a developer account at app.veridex.network (opens in a new tab) (beta), grab an API key, and pass relayerApiKey: process.env.VERIDEX_RELAYER_API_KEY. Optional — only needed when you outgrow the shared rate limit.

new VeridexClient({...}) is not a supported entry point. Always use createSDK (or one of the createHubSDK / createSessionSDK variants) so the SDK can resolve the correct contract addresses for each chain.

Step 3: Register a Passkey

Passkey registration runs in the browser — it triggers a WebAuthn prompt on the user's device. Use the React hooks in @veridex/react for a production flow; the snippet below shows the raw SDK calls.

import { createSDK } from '@veridex/sdk';
 
const sdk = createSDK('base');                       // testnet + public relayer baked in
 
// One-time Passkey registration → vault provisioned on Base Sepolia
await sdk.passkey.register('user@example.com', 'My Wallet');
 
console.log('Vault address:', sdk.getVaultAddress());

Step 4: Ship a Gasless Transfer Through the Public Relayer

transferViaRelayer signs the action with the user's passkey and submits it via relayer.veridex.network (opens in a new tab) — no gas tank, no signer required.

import { parseEther } from 'ethers';
 
const tx = await sdk.transferViaRelayer(
  {
    targetChain: 10005,                 // Optimism Sepolia (Wormhole chain id)
    token: 'native',
    recipient: '0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18',
    amount: parseEther('0.01'),
  },
  (state) => console.log('relayer status:', state.status),
);
 
console.log('Transaction:', tx.transactionHash);

Run the full flow live: stackblitz.com/github/Veridex-Protocol/playground (opens in a new tab) (open in a top-level tab — passkeys are blocked inside iframes).

Step 5: Add a Session Key (optional)

Mint a key with hard caps (duration + per-tx max) that signs many transfers without re-prompting. Real signature — SessionManager(credential, hubClient, passkeySign, config):

import { SessionManager, EVMHubClientAdapter } from '@veridex/sdk';
import { JsonRpcProvider, Wallet, parseEther, getBytes } from 'ethers';
 
const provider = new JsonRpcProvider('https://sepolia.base.org');
const signer = new Wallet(process.env.PRIVATE_KEY!, provider);    // sponsor for the on-chain session-register tx
 
const hubClient = new EVMHubClientAdapter(sdk.getChainClient() as any, signer as any);
const manager = new SessionManager(
  sdk.getCredential()!,
  hubClient,
  (challenge) => sdk.passkey.sign(challenge),
  { duration: 3600, maxValue: parseEther('0.05') },
);
 
const session = await manager.createSession();                    // one passkey prompt
 
const payload = await sdk.buildTransferPayload({
  targetChain: 10005, token: 'native',
  recipient: '0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18',
  amount: parseEther('0.01'),
});
const signed = await manager.signAction({
  action: 'transfer', targetChain: 10005,
  payload: getBytes(payload),
  nonce: Number(await sdk.getNonce()),
  value: parseEther('0.01'),
});
// `signed` is ready to submit through the relayer (sdk.relayer.submitSignedAction).

maxValue: 0n (unbounded) throws unless you opt in with allowUnboundedMaxValue: true. Why this is a foot-gun and when to opt in: Threat Model → Session Key Security.

What's Next