Hooks
Hooks are built on top of the providers and the core Manager API. Make sure your component tree is wrapped with ManagerProvider or CocoCashuProvider.
Operation Hook Contract
The operation hooks intentionally mirror manager.ops.* instead of inventing a separate React-only workflow model. One hook instance owns one active operation.
currentOperationis the authoritative operation record to render from.executeResultis only for execute-specific returned data, such as the token returned byuseSendOperation().execute().- Creation methods such as
prepare(...)andimportQuote(...)bind the hook to the operation they create. - Follow-up methods such as
execute(),checkPayment(),finalize(),cancel(),reclaim(), andrefresh()operate on the currently bound operation, so app code should not pass anoperationIdto those methods. - The optional hook argument is initial-only. Use it to seed a resume screen from an operation object or load one persisted operation by id on mount.
- The hooks subscribe to lifecycle events and update the bound operation when the manager emits a newer state for that operation id.
refresh()is for stale persisted operations, recovery screens, or explicit user refresh actions. It is not needed as happy-path polling.reset()clears the hook's local binding,executeResult,status, anderror. It does not roll back or delete the persisted operation.status,error,isLoading, andisErrordescribe the hook's current local async action. If a second stateful action is started while one is already running, the second call rejects and does not replace the loading/error state from the first action.
For state-machine details, see Send Operations, Receive Operations, Mint Operations, and Melt Operations.
useSendOperation
Use this for the full send lifecycle, including resume, reclaim, and finalize flows.
import { useSendOperation } from '@cashu/coco-react';
const {
prepare,
execute,
currentOperation,
executeResult,
refresh,
cancel,
reclaim,
finalize,
listPrepared,
listInFlight,
status,
error,
reset,
isLoading,
isError,
} = useSendOperation();
await prepare({ mintUrl, amount: 100 });
// after the user reviews the prepared operation:
const { operation, token } = await execute();currentOperation is the persisted operation state you render from. Once the hook is bound, methods such as execute(), refresh(), cancel(), reclaim(), and finalize() operate on that bound operation. You can also start from persisted work with useSendOperation(initialOperationOrId).
The initialOperationOrId argument is initial-only. If a component stays mounted and you need to switch the hook to a different persisted operation, remount the hook or component with a new React key. Changing the hook argument on a later render does not rebind the hook.
useReceiveOperation
Use this to decode, prepare, execute, resume, and cancel receives via manager.ops.receive.*.
import { useReceiveOperation } from '@cashu/coco-react';
const { prepare, execute, currentOperation, refresh, cancel } = useReceiveOperation();
const preparedReceive = await prepare({ token });
if (preparedReceive.state === 'prepared') {
await execute();
}useMintOperation
Use this for quote-backed mint lifecycles, including imported quotes and remote payment checks.
import { useMintOperation } from '@cashu/coco-react';
const {
prepare,
importQuote,
execute,
checkPayment,
finalize,
currentOperation,
executeResult,
listPending,
listInFlight,
} = useMintOperation();
const pendingMint = await prepare({ mintUrl, amount: 100, method: 'bolt11' });
if (pendingMint.state === 'pending') {
await checkPayment();
}prepare() and importQuote() both create a pending mint operation.
useMeltOperation
Use this for outbound payment flows such as bolt11 melts.
import { useMeltOperation } from '@cashu/coco-react';
const { prepare, execute, refresh, finalize, reclaim, currentOperation } = useMeltOperation();
const preparedMelt = await prepare({
mintUrl,
method: 'bolt11',
methodData: { invoice },
});
if (preparedMelt.state === 'prepared') {
await execute();
}Derived-data Hooks
The existing derived-data hooks remain available for balance and history views.
import { useBalances, usePaginatedHistory, useTrustedBalance } from '@cashu/coco-react';
const { balances, refresh: refreshBalances } = useBalances();
const {
history,
loadMore,
goToPage,
refresh: refreshHistory,
hasMore,
isFetching,
} = usePaginatedHistory(50);
const { balances: trustedBalances } = useTrustedBalance();useBalances() returns the full wallet snapshot:
balances.byMint[mintUrl].spendablebalances.byMint[mintUrl].reservedbalances.byMint[mintUrl].totalbalances.total
useTrustedBalance() applies the same structured shape, filtered to trusted mints only.