> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chipipay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# API Reference

> Every function and React hook exported from @chipi-stack/chipi-passkey. Grouped by which wallet type they apply to.

The package ships two parallel surfaces. Pick the one that matches your wallet type. Mixing them is fine — both can live on the same device under different localStorage keys.

| Wallet type                  | Surface                                                     | Use when                                            |
| ---------------------------- | ----------------------------------------------------------- | --------------------------------------------------- |
| SHHH (default since v14.5.0) | `createShhhPasskey`, `signShhhMessage`, `…ShhhCredential`   | New integrations, any SHHH wallet                   |
| Legacy CHIPI v29             | `createWalletPasskey`, `getWalletEncryptKey`, `…Credential` | Existing CHIPI v29 wallets you haven't migrated yet |

The React hooks (`usePasskeySetup`, `usePasskeyAuth`, `usePasskeyStatus`) wrap the **legacy** surface today. SHHH equivalents ship in a follow-on release; until then, call `createShhhPasskey` / `signShhhMessage` directly inside your own effects.

## SHHH passkey (modern path)

### createShhhPasskey

Registers a new P-256 platform passkey. No PRF extension, no PIN derivation. The private key stays inside the platform authenticator.

```ts theme={null}
import { createShhhPasskey } from "@chipi-stack/chipi-passkey";

const result = await createShhhPasskey(
  userId: string,
  userName: string,
  options?: { rpName?: string; rpId?: string; displayName?: string },
);
// result: {
//   credentialId: string,
//   publicKey: { x: Uint8Array(32), y: Uint8Array(32) },
//   publicKeyHex: { x: string, y: string },
//   rpId: string,
// }
```

Defaults: `rpId = window.location.hostname`, `rpName = "Chipi Wallet"`. Persists `{ credentialId, publicKey, userId, rpId, transports }` to localStorage under the key `chipi_wallet_shhh_passkey_credential`. Throws on `NotAllowedError` (user cancelled) or `InvalidStateError` (passkey already exists for this account on this device).

### signShhhMessage

Runs `navigator.credentials.get()` with `messageHash` encoded as the 32-byte big-endian WebAuthn challenge. Returns the raw assertion bytes ready to feed into `buildWebAuthnEnvelopeFromAssertion` from `@chipi-stack/backend`.

```ts theme={null}
import { signShhhMessage } from "@chipi-stack/chipi-passkey";

const result = await signShhhMessage({
  messageHash: bigint,           // SHHH SNIP-12 hash
  credentialId?: string,         // defaults to the stored credential
  rpId?: string,                 // defaults to the registered rpId
});
// result: {
//   authenticatorData: Uint8Array,
//   clientDataJSON: Uint8Array,
//   signatureDer: Uint8Array,
//   credentialId: string,
// }
```

### hasShhhPasskey

Synchronous check for a stored SHHH credential. Use it to branch between "Sign up" and "Sign in" UI without prompting.

```ts theme={null}
import { hasShhhPasskey } from "@chipi-stack/chipi-passkey";

const ready = hasShhhPasskey(); // boolean
```

### getStoredShhhCredential

Reads the persisted credential metadata.

```ts theme={null}
import { getStoredShhhCredential } from "@chipi-stack/chipi-passkey";

const stored = getStoredShhhCredential();
// stored | null:
// {
//   credentialId: string,
//   publicKey: { x: string, y: string },   // hex
//   createdAt: string,                       // ISO timestamp
//   userId: string,
//   rpId: string,
//   transports?: AuthenticatorTransport[],
// }
```

### removeStoredShhhCredential

Clears the stored credential id from localStorage. Use at logout, account reset, or when the user opts to re-register. The platform authenticator's stored credential is NOT deleted — only your app's reference to it.

```ts theme={null}
import { removeStoredShhhCredential } from "@chipi-stack/chipi-passkey";

removeStoredShhhCredential();
```

### Extraction utilities

Exported for tests and for advanced callers who want to verify a passkey's pubkey against a separately-stored copy.

```ts theme={null}
import {
  bigintToBe32,
  extractP256PubkeyFromRegistration,
  extractP256PubkeyFromSpki,
  extractP256PubkeyFromAttestationObject,
} from "@chipi-stack/chipi-passkey";
```

`extractP256PubkeyFromRegistration` is the dispatch helper — it tries the SPKI fast path first (Chrome, Safari, modern Edge), then falls back to decoding the CBOR `attestationObject` for older browsers. You only need these utilities if you're writing your own registration-response handler.

## Legacy PRF passkey \[#legacy-prf-passkey]

The PRF passkey path encrypts a STARK private key with a key derived from the WebAuthn PRF extension. It backs **CHIPI v29 wallets** — both legacy on-chain accounts and the dual-key (passkey primary + PIN backup) flow. New SHHH integrations don't need this surface; existing CHIPI v29 integrations still do.

### createWalletPasskey

Registers a passkey with the PRF extension enabled, derives an encryption key from the PRF output, and stores the credential metadata.

```ts theme={null}
import { createWalletPasskey } from "@chipi-stack/chipi-passkey";

const result = await createWalletPasskey(userId: string, userName: string);
// result: {
//   encryptKey: string,        // hex — use to encrypt the wallet's STARK key
//   credentialId: string,
//   prfSupported: boolean,     // false on Firefox without PRF
// }
```

Persists `{ credentialId, createdAt, userId, transports, prfSupported }` to localStorage under `chipi_wallet_passkey_credential`. **Separate** storage key from the SHHH path — both surfaces coexist on the same device.

### getWalletEncryptKey

Authenticates with an existing PRF passkey and returns the same `encryptKey` derived at registration time. Use it before every wallet operation that needs the STARK key (transfer, session-key registration, encryption rotation).

```ts theme={null}
import { getWalletEncryptKey } from "@chipi-stack/chipi-passkey";

const encryptKey = await getWalletEncryptKey(
  credentialId?: string,
  options?: { prfSupported?: boolean },
);
// encryptKey: string | null   // null if user cancels the biometric prompt
```

The PRF output is deterministic — same passkey, same PRF salt, same encryption key. If PRF is unavailable (Firefox before 122, or a browser switch after registering on Chrome), the function falls back to PBKDF2 derivation **only if** the credential was originally registered without PRF. Otherwise it throws — see [When passkeys fail](/sdk/passkeys/when-passkeys-fail).

### Status checks

```ts theme={null}
import {
  isWebAuthnSupported,
  isWebAuthnPRFSupported,
  hasWalletPasskey,
  verifyWalletPasskey,
  verifyWalletPasskeyDetailed,
} from "@chipi-stack/chipi-passkey";

isWebAuthnSupported();      // boolean
isWebAuthnPRFSupported();   // alias for isWebAuthnSupported (kept for backcompat)
hasWalletPasskey();         // boolean — is a credential stored locally?

await verifyWalletPasskey();        // boolean
await verifyWalletPasskeyDetailed(); // { valid, reason?, message? }
```

### Credential management

```ts theme={null}
import {
  getStoredCredential,
  removeStoredCredential,
} from "@chipi-stack/chipi-passkey";

const stored = getStoredCredential();
// stored | null:
// {
//   credentialId: string,
//   createdAt: string,
//   userId: string,
//   transports?: AuthenticatorTransport[],
//   prfSupported?: boolean,
// }

removeStoredCredential();
```

## React hooks (legacy passkey path)

The hooks today wrap the **legacy PRF** surface — `usePasskeySetup` calls `createWalletPasskey`, `usePasskeyAuth` calls `getWalletEncryptKey`. Import from the `/hooks` subpath so Next.js bundles get the right `"use client"` directives.

```ts theme={null}
import {
  usePasskeySetup,
  usePasskeyAuth,
  usePasskeyStatus,
} from "@chipi-stack/chipi-passkey/hooks";
```

### usePasskeySetup

```tsx theme={null}
function CreateWalletButton({ userId, userName }: { userId: string; userName: string }) {
  const { setupPasskey, isLoading, error, data } = usePasskeySetup();

  async function onClick() {
    const result = await setupPasskey(userId, userName);
    // result: { encryptKey, credentialId, prfSupported }
  }

  return (
    <button onClick={onClick} disabled={isLoading}>
      {isLoading ? "Creating…" : "Create wallet"}
    </button>
  );
}
```

### usePasskeyAuth

```tsx theme={null}
function SignButton() {
  const { authenticate, isLoading, error, data } = usePasskeyAuth();

  async function onClick() {
    const encryptKey = await authenticate(); // null if user cancelled
    if (encryptKey) {
      // use encryptKey for the next wallet operation
    }
  }
}
```

### usePasskeyStatus

```tsx theme={null}
function PasskeyStatusBanner() {
  const { status, hasPasskey, refresh } = usePasskeyStatus();
  // status: "loading" | "ready" | "not_supported" | "no_passkey" | "error"

  if (status === "no_passkey") return <SetupPrompt />;
  if (status === "not_supported") return <PinFallback />;
  return null;
}
```

## TypeScript types

```ts theme={null}
import type {
  ShhhPasskeyCredential,
  CreateShhhPasskeyResult,
  ShhhAssertion,
  CreateWalletPasskeyResult,
  WalletCredentialMetadata,
  PasskeyVerifyResult,
  UsePasskeySetupResult,
  UsePasskeyAuthResult,
  UsePasskeyStatusResult,
  PasskeyStatus,
} from "@chipi-stack/chipi-passkey";
```

## Related

* [Quickstart](/sdk/passkeys/quickstart) — end-to-end SHHH passkey flow
* [When passkeys fail](/sdk/passkeys/when-passkeys-fail) — recovery, PIN fallback, browser switching
