Create a wallet
Call registerWallet in response to a user action, such as a button click. The SDK opens the passkey prompt and reports progress. It returns a result whose branch identifies the available capability.
Register a passkey wallet
Use the hook when your product owns the registration button and result UI. Render CreateWalletButton inside the SeamsWebProvider from Start here. Supply its registration prop with an explicit authMethod. Select passkey or email authentication through authMethod. The server assigns a wallet ID when wallet is omitted. To supply an ID, pass wallet: { kind: 'provided', walletId }. When signerSelection is omitted, the SDK selects signers for the configured chains and enabled provisioning defaults. NEAR uses the configured account provisioning policy. Supply signerSelection to choose a custom signer set.
For example, this request creates a passkey wallet for the configured chains:
import type { SeamsWeb } from '@seams/wallet';
import { parseWebAuthnRpId } from '@seams/wallet/advanced';
const rpId = parseWebAuthnRpId('wallet.example.com');
if (!rpId.ok) throw new Error(rpId.error.message);
export const registration: Parameters<SeamsWeb['registration']['registerWallet']>[0] = {
authMethod: { kind: 'passkey', rpId: rpId.value },
};Use your wallet origin's relying-party ID in place of wallet.example.com. Pass registration to the button below, or call seams.registration.registerWallet(registration) from your own UI.
import type { RegistrationFlowEvent, SeamsWeb } from '@seams/wallet';
import { useSeams, type SeamsContextType } from '@seams/wallet/react';
function logRegistrationEvent(event: RegistrationFlowEvent): void {
console.log(event.phase, event.status, event.message);
}
function assertNever(value: never): never {
throw new Error(`Unexpected NEAR readiness result: ${JSON.stringify(value)}`);
}
async function createWallet(
registerWallet: SeamsContextType['registerWallet'],
seams: SeamsWeb,
registration: Parameters<SeamsContextType['registerWallet']>[0],
): Promise<void> {
try {
const result = await registerWallet({
...registration,
options: { ...registration.options, onEvent: logRegistrationEvent },
});
if (!result.success) {
console.error('Registration failed:', result.error);
return;
}
// `walletId` is the stable identifier for every later wallet operation.
console.log(`Wallet ${result.walletId} registered (${result.kind})`);
if (
result.kind === 'ecdsa_wallet_registered_near_pending' ||
result.kind === 'near_wallet_registered_pending'
) {
const near = await seams.registration.waitForNearAccount({ walletId: result.walletId });
switch (near.kind) {
case 'near_ready':
console.log('NEAR account ready:', near.nearAccountId);
break;
case 'near_failed_retryable':
console.warn('NEAR provisioning needs a retry:', near.reason);
break;
case 'timed_out':
console.warn('NEAR is still pending. Keep this wallet id and check readiness again.');
break;
default:
assertNever(near);
}
}
} catch (error) {
console.error('Wallet creation interrupted:', error);
}
}
export function CreateWalletButton({ registration }: {
registration: Parameters<SeamsContextType['registerWallet']>[0];
}) {
const { registerWallet, seams } = useSeams();
return (
<button onClick={createWallet.bind(null, registerWallet, seams, registration)}>
Create wallet
</button>
);
}The example checks result.success before logging the result's kind. Check the result branch before reading its fields, such as the NEAR provisioning state.
Read the result
wallet_registeredmeans the wallet and its returned capabilities are ready.ecdsa_wallet_registered_near_pendingmeans the EVM-family capability is ready while NEAR provisioning is pending or retryable. This branch carries no NEAR account ID. Awaitseams.registration.waitForNearAccount({ walletId })before signing NEAR.near_wallet_registered_pendingmeans NEAR provisioning still needs to reach a ready state before you read a NEAR account.wallet_signer_addedmeans a signer was added to an existing wallet.success: falsecontains the error text to show or log for the current attempt.
The returned walletId is the stable wallet identifier used by signing, session provisioning, and every other operation on that wallet. Store it with your application account record. Never store passkey or holder secrets in application state.
If registration stops
Passkey cancellation ends the current attempt. Let the person start a new attempt from the same button. A retryable NEAR provisioning result preserves the wallet identity. Check provisioning before offering a retry. Do not register a second wallet:
seams.registration.waitForNearAccount({ walletId })waits for provisioning to settle and resolves withnear_ready,near_failed_retryable, ortimed_out. It never rejects unless you abort it with asignal.seams.registration.getNearAccountState({ walletId })reads the current state without waiting.
Origin, publishable-key, and authentication errors require configuration or account changes before retrying.