Skip to main content

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.

If your wallet is a SHHH V8.4 wallet — the default since v14.5.0 — use X402ShhhClient. The existing X402Client only works for CHIPI v29 and Argent X wallets; it signs payments with a raw {r, s} pair that V8.4 rejects on chain. X402ShhhClient is in @chipi-stack/backend (and re-exported from @chipi-stack/x402 for convenience). Same fetch(url, init) surface as the regular client.

Which buyer client do I need?

Your walletUse
SHHH V8.4 (default for new wallets in v14.5.0+)X402ShhhClient (this page)
CHIPI v29 (legacy default)X402Client
READY (Argent X v0.4.0)X402Client
Not sure which? Read wallet.walletType off any wallet returned from getWallet / createWallet / useChipiWallet.

Install

npm install @chipi-stack/backend @chipi-stack/x402
# or pnpm / yarn
@chipi-stack/x402 re-exports X402ShhhClient so a single import covers facilitator + client surfaces.

Construct the client

import { X402ShhhClient, ChipiClient } from "@chipi-stack/backend";

const client = new X402ShhhClient({
  wallet: {
    publicKey: wallet.publicKey,
    encryptedPrivateKey: wallet.encryptedPrivateKey,
    signerKind: "STARK", // defaults to "STARK" if omitted
  },
  encryptKey,
  chipiClient: new ChipiClient({ apiPublicKey }),
  bearerToken,
});
Required:
  • wallet — the wallet’s publicKey (deployed account address) and encryptedPrivateKey (ciphertext). Same WalletData-derived shape every other SDK call uses.
  • encryptKey — passkey-derived key or PIN that decrypts the wallet’s STARK key client-side at sign time.
  • chipiClient — Chipi HTTP client (the same one your server uses elsewhere).
  • bearerToken — your chipi-back auth token. Server-side only; never crosses the wire to the x402 seller.
Optional config:
new X402ShhhClient({
  wallet,
  encryptKey,
  chipiClient,
  bearerToken,
  config: {
    maxPaymentAmount: "1.00",                      // hard cap per request in USDC
    allowedRecipients: ["0xtrusted-merchant…"],   // whitelist of payTo addresses
    headerName: "X-PAYMENT",                       // default — override only if the seller wants a different name
    chainId: undefined,                            // defaults to Starknet mainnet
  },
});
PIN is weak — not recommended for production.A user-typed PIN is a short, low-entropy string. Anyone who shoulder-surfs the PIN, observes a phishing form, or compromises the browser at typing time can decrypt the wallet’s private key. PIN remains in the SDK only as a fallback recovery surface for users who lose access to their platform authenticator.Production embedded-wallet apps should default to a platform passkey (Touch ID, Face ID, Windows Hello, Android biometrics) via the @chipi-stack/chipi-passkey package. For SHHH V8.4 wallets, signerKind: "WEBAUTHN_P256" keeps the private key inside the platform authenticator — it never leaves the device, never reaches Chipi servers, and is never derived from a user-typed secret.Only prompt for a PIN as the encryption key when:
  • The user explicitly opted into a PIN-only flow (e.g. cold-storage / paper-backup recovery), or
  • The platform genuinely has no WebAuthn / biometric support available.
If you are migrating an existing PIN-based wallet to a passkey, look up useMigrateWalletToPasskey in your framework’s hook docs.

Pay for a 402-protected request

fetch is a drop-in replacement for the global fetch. If the seller returns 200, it passes through. If they return 402 Payment Required, the client signs the payment locally and retries:
const response = await client.fetch("https://api.example.com/premium-data");

if (response.status === 200) {
  const data = await response.json();
  // …use the paid response
} else {
  // 402 still after retry, 4xx/5xx, etc.
}
The client adds the signed X-PAYMENT header to the retry. No paymaster call from your side — the facilitator (the seller’s side) settles by forwarding the signed calldata to chipi-back’s /transactions/execute-sponsored-raw.

What gets signed

  1. Build a USDC.transfer(payTo, amount) call.
  2. Build a SHHH V8.4 execute_from_outside_v2 outside-execution wrapping that call, with caller = ANY_CALLER (paymaster sponsorship).
  3. Compute the V8.4 SNIP-12 hash against the wallet’s address + chain id.
  4. Decrypt the STARK key client-side, sign the hash, wrap into a V2_SNIP12 envelope.
  5. Serialize the full execute_from_outside_v2 calldata into payload.shhh.oeCalldata.
  6. Ship that as the X-PAYMENT header.
The cleartext STARK key never crosses the wire. Chipi-back receives only the pre-signed calldata span; the wallet’s owner is the only party that could have produced it.

Signer kind support

signerKindStatus
"STARK"Shipped — used by 100% of SHHH wallets created today
"ED25519"Coming — Phantom (Solana) buyers paying x402 sellers
WEBAUTHN_P256, EIP191_SECP256K1, etc.Not in v14.5.0 — the SHHH client throws a clear error for non-STARK kinds so silent on-chain reverts are impossible
For browser-rooted kinds (WEBAUTHN_P256, EIP191_SECP256K1), the right pattern is to call your wallet adapter’s signMessage directly and build the envelope via buildWebAuthnEnvelopeFromAssertion / buildEip191EnvelopeFromSignature from @chipi-stack/backend, then submit through the paymaster yourself. The drop-in fetch(url) flow is STARK-only today.

Safety: caps + allowlists

Both the original X402Client and X402ShhhClient enforce the same two safety nets at sign time:
  • maxPaymentAmount — hard cap per request in human USDC (“1.00” = 1 USDC). Throws before signing if a 402 asks for more.
  • allowedRecipients — whitelist of seller addresses. Throws before signing if a 402’s payTo isn’t on the list.
Both errors surface before any signature is produced, so the user is never asked to sign a payment that would have been rejected anyway.

Facilitator side (sellers)

You don’t need a different facilitator for SHHH buyers — X402Facilitator from PR #298 onward auto-detects payload.shhh on the inbound payment and routes through the SHHH dispatch path. See x402 server — monetizing APIs for the seller-side setup; that page works as-is for SHHH buyers.