DOCS / QUICKSTART: ACCOUNT

Your wallet. Your programmable keys.

Your wallet controls the keys. Approve an exact message off-chain, and two independent signers return one signature.

Try it with your wallet

Connect Phantom or Solflare. This uses your connected account as the authority. No registration transaction, SOL balance or destination-chain funds are needed for ordinary message approvals.

Connect your wallet to begin.

Derived public key

Your key will appear here.

Signature

Your signature will appear here.

Use it in your application

Download the browser SDK bundle (keep all three modules together), and provide @solana/web3.js v1. Your application uses our hosted signers; no PairKey processes run locally.

import * as web3 from '@solana/web3.js';
import { PairKey } from './hosted-v2.mjs';

const pairkey = new PairKey({ web3 }); // hosted /api/v2
const wallet = window.phantom.solana;
await wallet.connect();

const namespace = await pairkey.onboard(wallet); // public metadata, no transaction
const key = await pairkey.key(namespace, 'solana', [0]);
const prepared = await pairkey.prepare(namespace, wallet, {
  chain: 'solana', path: [0], message: 'Hello from my application.'
});
const recovery = await pairkey.recovery(prepared);
sessionStorage.setItem('my-pairkey-job', JSON.stringify(recovery));
const submission = await pairkey.approve(namespace, wallet, prepared);
const { job_id } = await pairkey.submit(submission);
const result = await pairkey.wait(job_id, { prepared, key });
console.log(key.public_key_hex, result.signature_hex);

// After a timeout or page reload, use the saved job. Never sign again to recover.
const saved = JSON.parse(sessionStorage.getItem('my-pairkey-job'));
const resumed = new PairKey({ web3, endpoint: saved.endpoint,
  deployment: saved.deployment });
await resumed.config();
await resumed.recover(saved.job_id);
const recovered = await resumed.wait(saved.job_id, saved);

What your wallet authorizes

Your wallet signs a domain-separated approval digest binding the identity, namespace, destination, derivation path, exact message commitment, request ID, policy revision and expiry. The browser recomputes these fields before asking for a signature. Both signers verify your authorization independently. Knowing your address or loading a public key does not authorize signing.

Account approval uses signMessage. It sends no Solana transaction and creates no per-message rent account. Solana, EVM, Zcash, NEAR and Bitcoin message signing use the same approval flow. Sessions are deferred in this API.

Set optional account rules

With no saved policy, every request still needs your wallet signature. To add persistent restrictions, write one compact policy account on Solana. The wallet authorizes edits, which reuse that account and increase its revision. Both signers read it on each signing request.

const current = await pairkey.rules(namespace);
const update = await pairkey.preparePolicy(namespace, {
  revision: current.rules.revision + 1,
  destinations: [key.account.destination],
  path_prefixes: [[0]],
  max_payload_bytes: 256,
  payload_prefix: [],
  disabled: false
});
// This explicit policy edit is a Solana transaction; use a funded devnet wallet.
await pairkey.setPolicy(namespace, wallet, update);

Policy creation needs transaction fees and a rent deposit; later same-size edits reuse that deposit. Ordinary off-chain signing adds neither approval rent nor a Solana transaction fee. The prefix applies to the canonical signing payload; use an empty prefix for unrestricted message contents. Read Policy & rules for identity-specific updates and custom program logic.

Verify and recover

The Verify button asks the service to verify the displayed message and signature. The browser also checks exact approval context and Ed25519 signatures locally. Use the offline Rust verifier for independent verification of all signature suites, key certificates and both signer receipts; service verification alone does not provide that independence.

// Save this public transcript for the offline Rust verifier.
// Check signer identities against a trusted deployment configuration.
const transcript = { request: prepared.signing_request, approval: prepared.request,
  key, result, identities: namespace.config.signer_identities };
// cargo run -p pairkey-sdk --example verify_hosted -- transcript.json

The client saves the public prepared request, key, deployment and deterministic job ID before submission. Keep that recovery record; it contains no wallet signature, JWT or passkey assertion, but it does contain your message. “Recover last job” only retrieves the original attempt. It never asks for another approval, submits another job or consumes another allowance. If the original submission never reached the service, recovery reports an unknown job. An uncertain outcome is not proof that no signature exists.

How addresses are scoped

The authority scopes the namespace. Destination, signature scheme and numeric path select keys inside it. The default namespace ID is 32 zero bytes; use a different 32-byte ID for another namespace. Keep the deployment and namespace metadata to recover the same keys. Policy edits and program approval-mode changes preserve the authority.

The UI displays a Solana public key, a NEAR ed25519: public-key identifier or an EVM address where applicable. Zcash and Bitcoin display signing public keys. These guides do not construct shielded addresses, named NEAR accounts or destination transactions.