Quickstart
Add a wallet to a web app: sign the user in, create their wallet, send a transaction. Everything below runs in the browser, with a passkey as the user's key.
1. Get a publishable key
Create an app in the Aligned dashboard and copy its publishable key (aligned_pk_test_...). The key identifies your app. It is not a secret and is meant to ship in your frontend.
Add every origin your app runs on to the key's allowed origins, including http://localhost:5173 or whatever your dev server uses. Requests from any other origin are rejected with 403 origin_not_allowed.
2. Install the SDK
npm install @aligned-waas/sdk3. Create a client
import { AlignedClient, localStorageAdapter, webPasskeyAdapter } from '@aligned-waas/sdk';
export const aligned = new AlignedClient({
publishableKey: 'aligned_pk_test_...',
storage: localStorageAdapter(), // keeps the session across reloads
passkey: webPasskeyAdapter(), // browser WebAuthn
});The client connects to the Aligned testnet by default. Pass baseUrl to point it at a backend you run yourself.
Construct it once, at module scope. A new client on every render restarts session restoration and throws away its caches.
4. Sign the user in
Email one-time code, no password:
The first successful verification creates the account. Google sign-in is available too, in a popup:
5. Create the wallet
That one call registers a passkey on the device, creates the account on chain, and selects that passkey as the signing key.
If the user already has a wallet it is returned as is, with created: false and no new passkey. Adding a second device to an existing wallet is a different flow, see Keys and recovery.
6. Send a transaction
The SDK asks the backend for the digest bound to the wallet's current nonce, prompts for the passkey, and submits. Aligned relays the transaction and pays the gas, so your users never need the chain's native token. status is 1 when the transaction succeeded on chain.
7. Sign a message
Nothing is submitted on chain. The result is a signature any verifier can check by calling isValidSignature (ERC-1271) on the wallet.
Plain strings are hashed as keccak256(utf8(message)), which is not what personal_sign (EIP-191) does. For EIP-191 or EIP-712 semantics, compute the digest yourself and pass { hash }.
Handling errors
Failed calls throw ApiError, carrying the HTTP status, a stable code, and the parsed response body. Codes worth handling explicitly:
unauthenticated
Session expired or missing. Send the user back through sign-in.
origin_not_allowed
The page origin is not on the publishable key's allowlist. Fix it in the dashboard.
rate_limited
Back off and retry.
step_up_required
The endpoint needs a fresh step-up proof, see Keys and recovery.
Passkey ceremonies throw whatever the browser throws, and a cancelled prompt is a normal outcome rather than a failure. Treat it as "the user said no".
A note on Node
The SDK is a browser and mobile library. The publishable-key path requires a real Origin header, which Node's fetch does not send, so calls from Node are rejected. Use it in Node only for tests or for building signing material that a browser will send.
Where next
How it works, what the contracts guarantee and why.
Keys and recovery, multiple devices and losing them.
React and React Native for the framework adapters.
Last updated
Was this helpful?