Packages Reference - WalletConnect Pay Docs
Documentation Index
Fetch the complete documentation index at: /llms.txt
Use this file to discover all available pages before exploring further.
The runtime is split into layered packages. Each is independently consumable, and lower layers never depend on higher ones — so you can take only what you need.
| Package | Role | Depends on |
|---|---|---|
@walletconnect/pay-core |
Engine API client — contract types, CAIP utilities, the browser Transport seam (createHttpTransport), and the server-side createEngineClient that holds your API key. The foundation. |
— |
@walletconnect/pay-state |
The headless runtime — the payment state machine, orchestration, the injectable seam contracts, the session factory, and the public PaymentSnapshot view-model. No React, no HTTP client, no wallet SDK. |
pay-core |
@walletconnect/pay-react |
Thin React binding — usePaymentSession returns the snapshot plus domain actions. Zero state-machine leak. |
pay-state |
@walletconnect/pay-appkit |
Reown AppKit adapter — implements the WalletProvider seam over a Reown AppKit instance (plus the Solana web3 loader). A /react subpath ships the wallet-connection hook. |
pay-state |
@walletconnect/pay-core
The foundation: Engine contract types, CAIP utilities, and the Transport seam. Zero runtime dependencies. Two entry points — a browser-safe main entry and a server-only /server entry that holds the key.
Browser entry — @walletconnect/pay-core
import { createHttpTransport, type Transport, type HttpTransportConfig } from '@walletconnect/pay-core'
interface HttpTransportConfig {
baseUrl?: string // default '/api/wcp'
fetch?: typeof fetch
timeoutMs?: number // default 30_000
}
function createHttpTransport(config?: HttpTransportConfig): Transport
The Transport contract (the seam the runtime depends on) — five methods, each resolving to an EngineResponse<T> envelope (never throwing):
interface Transport {
getPayment(paymentId): Promise<EngineResponse<GetPaymentResponse>>
getPaymentOptions(paymentId, request): Promise<EngineResponse<GetPaymentOptionsResponseExtended>>
fetchOptionActions(paymentId, request): Promise<EngineResponse<EngineBuildData>>
confirmPayment(paymentId, request): Promise<EngineResponse<unknown>>
getPaymentStatus(paymentId): Promise<EngineResponse<GetPaymentStatusResponse>>
}
Also exported: all Engine contract types (GetPaymentResponse, PaymentOptionExtended, Amount, CollectData, PaymentStatus, …), CAIP utilities (parseCaip2, parseCaip10, …), and transport error helpers (TRANSPORT_ERROR_CODES, isAbortError, DEFAULT_TIMEOUT_MS).
Server entry — @walletconnect/pay-core/server
import { createEngineClient, type EngineClient, type EngineClientConfig, DEFAULT_VERSION } from '@walletconnect/pay-core/server'
interface EngineClientConfig {
apiUrl: string // e.g. https://staging.api.pay.walletconnect.org (no trailing slash)
apiKey: string // your Gateway Api-Key — keep secret, server-side only
version?: string // WCP API version; defaults to DEFAULT_VERSION
fetch?: typeof fetch
timeoutMs?: number // default 30_000
}
function createEngineClient(config: EngineClientConfig): EngineClient
EngineClient exposes the same five methods as Transport, but attaches the secret Api-Key and Wcp-Version headers and calls the Engine directly. Use it only on the server.
@walletconnect/pay-state
The headless runtime: the payment state machine, the injectable seam contracts, the framework-agnostic PaymentController, the signing strategies, and the public PaymentSnapshot view-model.
createPaymentController
The framework-agnostic binding (the React hook wraps this). Use it directly in a non-React host.
import { createPaymentController, type PaymentController, type PaymentControllerOptions } from '@walletconnect/pay-state'
interface PaymentControllerOptions {
paymentId: string
seams: PaymentSessionSeams // { transport, clock, signer?, telemetry? }
wallet: WalletProvider
initialPayment?: GetPaymentResponse
signingTimeoutMs?: number
onMachineEvent?: MachineEventObserver // read-only analytics observer
}
function createPaymentController(options: PaymentControllerOptions): PaymentController
interface PaymentController {
getSnapshot(): PaymentSnapshot
subscribe(listener: () => void): () => void
start(): void
destroy(): void
// domain actions (see the React hook below for the full list)
connectWallet(wallet, namespace?, options?): void
// …
}
Seams
The runtime reaches the outside world only through these contracts:
interface PaymentSessionSeams {
transport: Transport // Engine calls (from pay-core)
clock: Clock // intervals + page visibility (for status polling)
signer?: Signer // signing capability — required for an end-to-end payment
telemetry?: Telemetry // optional analytics breadcrumbs
}
interface WalletProvider {
getAccounts(): Partial<Record<Namespace, NamespaceAccount | undefined>>
getProvider<T extends Namespace>(network: Caip2 & { namespace: T }): ProviderForNamespace<T> | null
connect(wallet: WalletRef, namespace: Namespace, options?: WalletConnectOptions): Promise<void>
disconnect(namespace?: Namespace): Promise<void>
switchNetwork(caipNetworkId: string): Promise<void>
subscribe(listener: () => void): () => void
}
interface Signer {
signActions(option: PaymentOptionExtended, range?: ActionRange): Promise<SignPaymentResult[]>
}
Browser defaults are provided so you only have to inject transport, wallet, and signer:
import { browserClock, noopTelemetry, browserDefaults } from '@walletconnect/pay-state'
Signing strategies
AppKit hosts don’t need these directly — @walletconnect/pay-appkit exports a zero-config createAppKitSigner(wallet) that wraps them with the bundled Solana codec. These are the low-level primitives, for a custom wallet integration.
import { EvmSigningStrategy, SolanaSigningStrategy, signOptionActions } from '@walletconnect/pay-state'
// Dispatch each of an option's actions to the matching strategy:
signOptionActions(option: PaymentOptionExtended, strategies: SigningStrategy[], range?: ActionRange): Promise<SignPaymentResult[]>
PaymentSnapshot
The public, serializable view-model. state is one of:
| Group | States |
|---|---|
| Loading | Initializing |
| Wallet | ReadyForWallet, ConnectingWallet |
| Options | LoadingOptions, OptionsReady, NoOptions, OptionSelected |
| Compliance | InformationCapture |
| Approval | RequiresApproval, AwaitingWalletApproval, WaitingForConfirmation |
| Terminal | Succeeded, Failed, PaymentExpired, PaymentCancelled, InvalidPayment, SanctionedUser |
interface PaymentSnapshot {
state: PaymentState
payment?: GetPaymentResponse
options: PaymentOptionExtended[]
selectedOption?: PaymentOptionExtended
collectData?: CollectData | null
wallet: { isConnected: boolean; accounts: string[] }
requiresApproval: boolean
signingError?: { code: string; message?: string }
isQuoteExpired: boolean
profileId?: string
profileNotFound: boolean
// …diagnostic fields
}
@walletconnect/pay-react
A single hook — usePaymentSession — a useSyncExternalStore-based binding over the controller. SSR-safe, tear-free, zero XState leak.
import { usePaymentSession, type UsePaymentSessionOptions, type PaymentSessionApi } from '@walletconnect/pay-react'
function usePaymentSession(options: UsePaymentSessionOptions): PaymentSessionApi
UsePaymentSessionOptions matches PaymentControllerOptions (paymentId, seams, wallet, initialPayment?, signingTimeoutMs?, onMachineEvent?). The return is { snapshot } plus the named actions:
| Action | Drives |
|---|---|
connectWallet(wallet, namespace?, options?) |
Begin connecting a wallet |
disconnectWallet(namespace?) |
Disconnect one namespace, or all |
selectOption(option, rank) |
Pick a payment option |
confirmSelection() |
Confirm and move toward signing |
unselectOption() |
Return to the option list |
submitInfoCapture(data) |
Submit collected KYC/contact data |
navigateBack() |
Step back |
Plus a host-orchestration channel for signals the runtime can’t observe itself — refreshOptions, notifyQuoteExpired, acknowledgeQuoteExpiry, markUserSanctioned, setProfileLookup, notifyPaymentExpired, failWalletConnection. Most gateways won’t need these to start.
@walletconnect/pay-appkit
The Reown AppKit adapter — it owns the entire AppKit setup so a host stays @reown/*-free. It constructs the instance, implements the WalletProvider seam over it, provides a zero-config Signer, and ships a headless wallet-picker controller. The main entry is framework-neutral; the React provider + hooks live on /react.
Main entry — @walletconnect/pay-appkit
import {
createPayAppKit, // ({ projectId, metadata, themeVariables? }) => PayAppKit (one-call setup)
createAppKitSigner, // (wallet) => Signer (zero-config, bundles the Solana codec)
createAppKitWalletList, // (appKit, options?) => AppKitWalletList (framework-neutral picker)
createAppKitWalletProvider, // (appKit, options?) => WalletProvider
SUPPORTED_NETWORKS, EVM_NETWORKS, // the WC-owned network set (baked in, not host config)
loadSolanaWeb3, // lazy @solana/web3.js codec loader for the Solana signing strategy
applyPlacements, resolvePlacements, // wallet-ordering helpers
type AppKit, // re-exported AppKit instance type — don't import @reown/appkit directly
type PayAppKit, type CreatePayAppKitOptions, type PayAppKitMetadata,
type WalletListItem, type ConnectedWallet, type WalletListState, type WalletListOptions
} from '@walletconnect/pay-appkit'
createPayAppKit builds the instance with the WC-owned networks + adapters in headless mode. It’s client-only and async — await payAppKit.whenReady(), then read getInstance() / getWagmiConfig() / getHooks() / getError() / isInitialized().createAppKitWalletList returns a controller — wallet (the seam), getState(), subscribe(), fetchWallets(), search(), loadMore(), getWcUri() — for non-React hosts.
React entry — @walletconnect/pay-appkit/react
The zero-config provider that owns AppKit’s construction + the Wagmi/Query tree + an SSR-safe context, plus the state hook and the imperative instance accessor:
import {
PayAppKitProvider, // <PayAppKitProvider projectId metadata themeVariables? queryClient?>
usePayAppKit, // SSR-safe hook: isReady / account / network / walletConnection / connect / disconnect / …
getPayAppKitInstance, // module-level accessor to the same AppKit instance (for non-hook consumers)
useAppKitWalletProvider,
type AppKitWalletProviderHandle,
type UseAppKitWalletProviderOptions
} from '@walletconnect/pay-appkit/react'
function useAppKitWalletProvider(appKit: AppKit | undefined, options?: UseAppKitWalletProviderOptions): AppKitWalletProviderHandle
useAppKitWalletProvider’s handle extends WalletListState and adds wallet (the seam to hand usePaymentSession), searchQuery/setSearchQuery (debounced), fetchWallets, loadMore, and getWcUri for the pairing QR.