Register a passkey, create a wallet, sign a transaction, and broadcast — using the prepare/confirm pattern
This guide results in real on-chain transactions when using production credentials. Use the sandbox environment (https://testnet.relayer.fi/v1) while testing. Blockchain transactions are irreversible once broadcast.
The Signing Kit uses a prepare → stamp → confirm pattern. Every signing operation (wallet creation, address creation, transaction signing) follows the same three steps:
Prepare — your backend calls the API to get an unsigned activity/transaction
Stamp — the user signs the payload with a passkey (WebAuthn, browser-side)
Confirm — your backend sends the stamped payload back; the enclave validates and processes it
The passkey stamping in step 2 must happen in a browser context that has access to WebAuthn. Server-only flows (cURL) can call prepare and confirm, but the stamping itself requires user interaction.
A Relayer API key with the Signing module enabled (see Authentication)
A user with a registered passkey in your workspace (see step 1 below)
export RELAYER_API_KEY="rk_client_key_v1_your_key_here"export RELAYER_BASE_URL="https://testnet.relayer.fi/v1" # sandbox; use https://api.relayer.fi/v1 for production
The first time a user enrolls in your workspace, they register a passkey. This creates the wallet workspace and binds the user’s WebAuthn credential to it.The full flow happens in the browser via the Relayer dashboard or your own WebAuthn-capable frontend. The API calls involved:
POST /v1/signing/passkeys/challenge → returns WebAuthn challengePOST /v1/signing/passkeys/register → registers the credential and creates the workspace
For end-user onboarding (Embedder integrators), the Widget Kit handles passkey enrollment automatically. See Widget Kit.
Same prepare/stamp/confirm pattern, this time for CREATE_WALLET_ACCOUNTS:
POST /v1/signing/wallets/accounts/prepare { walletId, curve, addressFormat } → user stamps the returned activity with their passkeyPOST /v1/signing/wallets/accounts/confirm { stampedActivity } → returns { address, addressId, walletId }
Use addressFormat: "ADDRESS_FORMAT_ETHEREUM" for all EVM-compatible networks (Ethereum, Polygon, Arbitrum, Base, etc.). Use addressFormat: "ADDRESS_FORMAT_SOLANA" for Solana.
Send the signed hex to confirm. The API validates the signature against the original unsigned transaction via hash comparison, persists the signed transaction, and broadcasts to the blockchain.
If your workspace has approval enabled and the transaction value exceeds the threshold, POST /v1/transactions/confirm returns HTTP 202 with { approvalId } instead of broadcasting. The transaction stays pending until an authorized team member stamps approval: