Skip to content

React SDK

Terminal window
npm install @tallypay/react @tallypay/core react react-dom

Wraps your app (or a subtree) with TallyPay context. All hooks require this provider as an ancestor.

import { TallyPayProvider } from "@tallypay/react";
function App() {
return (
<TallyPayProvider
network="eip155:8453"
walletClient={walletClient}
apiKey="tp_live_..."
collectorUrl="http://127.0.0.1:8787"
>
{children}
</TallyPayProvider>
);
}

Props (TallyPayProviderProps)

PropTypeRequiredDescription
networkstringYesCAIP-2 network identifier (e.g. "eip155:8453").
walletClientunknownYesA viem WalletClient or similar signing interface. Currently stored in context for your signing logic.
apiKeystringNoTallyPay API key. Enables client-side beacons to the trace collector.
collectorUrlstringNoOverride the collector URL for local dev.
childrenReactNodeYes

Read the provider context. Throws if used outside <TallyPayProvider>.

import { useTallyPay } from "@tallypay/react";
const { network, walletClient, apiKey } = useTallyPay();

Returns TallyPayContext

PropertyTypeDescription
networkstringNetwork from provider.
walletClientunknownWallet client from provider.
apiKeystring | undefinedAPI key from provider.
collectorUrlstring | undefinedCollector URL from provider.

Declarative hook for a single payment flow. Manages the full lifecycle: idlependingsigningsettlingcomplete / error.

import { usePayment } from "@tallypay/react";
function PremiumContent() {
const { pay, status, receipt, error, traceId } = usePayment(
"http://localhost:3000/api/premium",
);
return (
<div>
<button onClick={pay} disabled={status === "pending" || status === "signing"}>
{status === "complete" ? "Paid" : "Pay $0.01"}
</button>
{error && <p>{error.message}</p>}
{receipt?.txHash && <p>TX: {receipt.txHash}</p>}
</div>
);
}

Parameters

ParamTypeDescription
urlstringThe paywalled endpoint URL.
optionsRequestInitOptional fetch init (headers, method, body).

Returns UsePaymentResult

PropertyTypeDescription
pay() => Promise<void>Trigger the payment flow.
statusPaymentStatus"idle" | "pending" | "signing" | "settling" | "complete" | "error"
receipt{ txHash?: string; traceId?: string } | nullSettlement receipt after success.
errorError | nullError from the most recent attempt.
traceIdstring | nullTrace ID from the server’s 402 response.

Beacons: If apiKey is set in the provider, the hook emits 402_RECEIVED and PAYMENT_ERROR beacons to the collector via navigator.sendBeacon.


Returns a fetch wrapper (built on wrapFetch from @tallypay/core) that automatically handles 402 responses.

import { usePaymentFetch } from "@tallypay/react";
const payFetch = usePaymentFetch();
const res = await payFetch("/api/premium");

Requires a signing implementation wired to the walletClient from the provider.


Pre-built button with status feedback. Wraps usePayment.

import { PaymentButton } from "@tallypay/react";
<PaymentButton
url="http://localhost:3000/api/premium"
label="Unlock content"
className="btn btn-primary"
onComplete={(receipt) => console.log("Paid!", receipt.txHash)}
onError={(err) => console.error(err)}
/>

Props (PaymentButtonProps)

PropTypeRequiredDescription
urlstringYesPaywalled endpoint URL.
labelstringNoOverride the button text. Default labels based on status: “Pay”, “Processing…”, “Sign payment…”, “Settling…”, “Paid”, “Failed — Retry”.
classNamestringNoCSS class for the <button>.
requestInitRequestInitNoFetch options for the request.
onComplete(receipt) => voidNoCalled after successful payment.
onError(error) => voidNoCalled on failure.

The button sets data-tallypay-status on the <button> element (the current PaymentStatus value), so you can style states with CSS attribute selectors:

[data-tallypay-status="complete"] { background: green; }
[data-tallypay-status="error"] { background: red; }

When apiKey is set in the provider, hooks emit lightweight beacons via navigator.sendBeacon to the TallyPay collector at each client-side lifecycle step:

EventWhen
402_RECEIVEDClient received a 402 from the server
PAYMENT_SIGNEDClient signed the authorization
PAYMENT_SUBMITTEDClient retried with payment-signature
PAYMENT_COMPLETEFinal response was 2xx
PAYMENT_ERRORAny client-side step failed

This is the unique data. Facilitators only see verify + settle. Only TallyPay sees the full client funnel: how many 402s go unpaid, how long signing takes, whether the final response was received.