Developer Quickstart
Configure a self-hosted relayer and get from zero to a working session-backed request in five steps.
The former hosted relayer and Developer Portal are being redeployed. Check service status before using a Veridex hostname. For a complete payment flow that works today, use the Stellar x402 quickstart.
Prerequisites
- Node.js 18+ or Bun
- A browser supporting WebAuthn/Passkeys (Chrome 108+, Safari 16+, Firefox 118+)
- A reachable relayer deployment and its HTTPS API URL
No public relayer is currently claimed. Run the relayer from the Veridex monorepo or use another explicitly configured deployment. Never rely on an SDK default without first checking the endpoint.
Step 1: Install the SDK
npm install @veridex/sdk ethers
# or
bun add @veridex/sdk ethersCurrent 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 can target testnet, but the relayer URL must identify a
deployment you have verified.
import { createSDK } from '@veridex/sdk';
const sdk = createSDK('base', {
network: 'testnet',
relayerUrl: process.env.VERIDEX_RELAYER_URL,
});Do not use app.veridex.network, developers.veridex.network, or
relayer.veridex.network until the service status
page marks them live.
new VeridexClient({...})is not a supported entry point. Always usecreateSDK(or one of thecreateHubSDK/createSessionSDKvariants) 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', {
network: 'testnet',
relayerUrl: process.env.VERIDEX_RELAYER_URL,
});
// 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 Your Relayer
transferViaRelayer signs the action with the user's passkey and submits it to
the relayer URL configured above. The deployment operator owns its gas funding,
keys, limits, and availability.
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);The browser Playground can demonstrate local passkey and policy behavior, but an on-chain result still requires a reachable relayer. For a reproducible hosted-independent payment proof, run the Stellar x402 evaluator.
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 withallowUnboundedMaxValue: true. Why this is a foot-gun and when to opt in: Threat Model → Session Key Security.
What's Next
- Multi-Session Management — manage multiple concurrent sessions
- Agent SDK — build autonomous agents with session keys
- Session Studio — visual session management
- Threat Model — what Veridex protects against (and what it does not)