UX.SOL

Hook

usePrivatePayment

Typed React hook for the MagicBlock Private Payments API with auth-aware requests, transaction builders, balance readers, and mint initialization checks.

Installation

terminal
$npx shadcn@latest add https://uxdotsol.xyz/r/use-private-payment.json

Usage

use-private-payment.tsx
"use client";
 
import { useState } from "react";
import {
usePrivatePayment,
type PrivatePaymentTxResponse,
} from "@/hooks/use-private-payment";
 
const USDC_MINT = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU";
 
export function SendPrivateUsdc({
owner,
recipient,
amountAtomics,
signAndSend,
}: {
owner: string;
recipient: string;
amountAtomics: number;
signAndSend: (tx: PrivatePaymentTxResponse) => Promise<string>;
}) {
const payments = usePrivatePayment({ cluster: "devnet" });
const [signature, setSignature] = useState<string | null>(null);
 
async function sendPrivateUsdc() {
setSignature(null);
 
const mintStatus = await payments.isMintInitialized({ mint: USDC_MINT });
 
if (!mintStatus.initialized) {
const setupTx = await payments.initializeMint({
payer: owner,
mint: USDC_MINT,
});
await signAndSend(setupTx);
}
 
const transferTx = await payments.transfer({
from: owner,
to: recipient,
mint: USDC_MINT,
amount: amountAtomics,
visibility: "private",
fromBalance: "base",
toBalance: "base",
initIfMissing: false,
initAtasIfMissing: false,
initVaultIfMissing: false,
});
 
setSignature(await signAndSend(transferTx));
}
 
return (
<div className="grid gap-2">
<button disabled={payments.isLoading} onClick={sendPrivateUsdc}>
{payments.isLoading ? "Sending..." : "Send private USDC"}
</button>
{signature ? <p>Confirmed: {signature}</p> : null}
{payments.error ? <p>{payments.error.message}</p> : null}
</div>
);
}

Options

NameTypeDefaultDescription
endpointstring'https://payments.magicblock.app'Private Payments API base URL.
cluster'mainnet' | 'devnet' | http(s) URLundefinedDefault cluster sent to payment API requests.
validatorstringundefinedDefault MagicBlock validator sent to supported requests.
authTokenstringundefinedDefault bearer token for private balance reads and authenticated transfers.
headers / fetcherHeadersInit / typeof fetchundefined / fetchOptional default headers and custom fetch implementation. Per-request headers are merged on top.

Functions

NameTypeDefaultDescription
request<T>(path, init?) => Promise<T>-Low-level typed request helper. It trims endpoint slashes, merges auth/custom headers, records timing, and parses JSON/text errors.
health() => Promise<{ status: 'ok' }>-Checks Private Payments API availability.
deposit / transfer / withdraw / initializeMint(params) => Promise<PrivatePaymentTxResponse>-Builds unsigned SPL transactions for wallet signing. transfer can pass a per-request authToken.
balance / privateBalance(params) => Promise<PrivatePaymentBalance>-Reads public base-chain or private ephemeral token balance.
challenge / login(params) => Promise<{ challenge: string } | { token: string }>-Runs the wallet challenge flow used to authorize private data access.
isMintInitialized(params) => Promise<PrivatePaymentMintInitialization>-Checks whether the private-payment transfer queue is initialized for a mint before calling initializeMint.
reset / clearError() => void-Clears hook state completely or only clears the current error.

Types

NameTypeDefaultDescription
PrivatePaymentState{ status; isLoading; error; lastResponse; lastRequest }-Request lifecycle state exposed by the hook.
PrivatePaymentErrorError & { status?; payload?; path? }-Readable API error with response status, parsed payload, and endpoint path.
PrivatePaymentTxResponse{ kind; version; transactionBase64; sendTo; recentBlockhash; lastValidBlockHeight; instructionCount; requiredSigners; validator; transferQueue?; rentPda? }-Unsigned transaction payload returned by write endpoints.
PrivatePaymentCluster / BalanceLocation / Visibility'mainnet' | 'devnet' | URL / 'base' | 'ephemeral' / 'public' | 'private'-Shared string unions used across request configuration and transfer payloads.
PrivatePaymentDepositParams / WithdrawParams{ owner; mint?; amount; cluster?; validator?; initIfMissing?; initAtasIfMissing?; idempotent?; ... }-Deposit and withdraw request payloads. Amount is always integer token base units.
PrivatePaymentTransferParams{ from; to; mint; amount; visibility; fromBalance; toBalance; authToken?; ... }-Transfer request payload.
PrivatePaymentInitializeMintParams / IsMintInitializedParams{ payer; mint; cluster?; validator? } / { mint; cluster?; validator? }-Mint setup and setup-check request payloads.
PrivatePaymentChallengeParams / LoginParams{ pubkey; cluster?; mock? } / { pubkey; challenge; signature; cluster?; mock? }-Wallet-auth request payloads for private balance reads and authenticated transfers.
PrivatePaymentBalance{ address; mint; ata; location; balance }-Balance response shape.

Returns

NameTypeDefaultDescription
status / isLoadingPrivatePaymentStatus / boolean'idle' / falseCurrent request lifecycle state.
errorPrivatePaymentError | nullnullLast request error.
lastResponse / lastRequestunknown | null / PrivatePaymentRequestMeta | nullnull / nullLatest successful response and request timing metadata.
endpointstring'https://payments.magicblock.app'Normalized endpoint with trailing slashes removed.