useCapxulPay
Mutation hook for sending money to a validated recipient — instant by default, or a scheduled/streaming Commitment.
Sends money from the signed-in user's Account to a recipient — a handle,
email, Organization, or saved payee.
Read results back with useCapxulPayments.
Import
import { useCapxulPay } from "@capxul/sdk-react";Usage
"use client";
import { useCapxulPay } from "@capxul/sdk-react";
function PayButton({ email }: { email: string }) {
const pay = useCapxulPay();
return (
<div>
<button
disabled={pay.isPending}
onClick={() =>
pay.mutate({
to: { kind: "email", email },
amount: { currency: "USD", value: "25.00", decimals: 6 },
})
}
>
{pay.isPending ? "Sending…" : "Send $25"}
</button>
{pay.error ? <p>{pay.error.message}</p> : null}
{pay.data ? (
<p>
Payment {pay.data.id} is {pay.data.status}.
</p>
) : null}
</div>
);
}Parameters
The hook itself takes no parameters. The mutation takes a PaymentsPayInput:
Prop
Type
Pass the payment intent only. The hook creates and stores the request key. A retry after a page reload uses the same key. The hook retains the key while an attempt is unresolved. It removes the key after all attempts succeed. The hook fails before the backend request when persistent storage or Web Locks are unavailable.
to — the recipient. Recipients are typed references, never raw
addresses. The accepted forms are:
{ kind: "handle", handle }— a handle you have reserved for one of your payees (a leading@is tolerated and stripped).{ kind: "email", email }— an email address.{ kind: "organization", handle }— an organization by its handle.{ kind: "payee", id }— a saved payee by id.
A bare EVM address (0x + 40 hex characters) is rejected by design with an
INVALID_INPUT error. The SDK and the backend both enforce this rule. The
TargetReference union has a destination variant, but pay rejects it with
NOT_IMPLEMENTED.
actor. Only the personal actor can pay in the current alpha. Passing an
organization actor fails with NOT_IMPLEMENTED (payments.pay.organizationActor).
See Capability status.
timing. Omitted means instant — the direct-send path. A
{ kind: "scheduled", at } or { kind: "stream", startsAt, endsAt, cliffAt? }
clause turns the payment into a Commitment: an escrowed, cancellable,
redirectable payment that the recipient claims as it vests. Timestamps are
epoch milliseconds. Commitment payments enter the ledger as scheduled,
streaming, or pending_claim instead of pending.
The instant-send guardrail
An instant, irreversible payment is only permitted to a validated recipient. Paying anyone not yet validated always goes through a recoverable Commitment (escrowed, cancellable, redirectable). The SDK enforces this; it is not a bug to work around. See Capability status.
document and lineItems. An attached document (for example an invoice)
is hashed, stored, and committed with the payment; the returned Payment
carries only a document reference. The backend enforces the bindings: an
attached invoice's amount due must equal the amount being paid, paymentType
(when given) must match the document kind, and lineItems are accepted only
with an invoice document whose committed line-items hash and total they
reproduce exactly.
Return type
import { type UseCapxulPayReturn } from "@capxul/sdk-react";
// UseMutationResult<Payment, CapxulError, PaymentsPayInput>On success, data is the recorded Payment: its id, status, amount, the
actor-relative direction, counterpartyLabel, nullable settled receipt,
recipient, attached document references, timing, and commitment amounts.
The hook returns TanStack Query's UseMutationResult. The most-used fields:
| Field | Description |
|---|---|
mutate | Fire the mutation (fire-and-forget; pair with onSuccess/onError callbacks). |
mutateAsync | Fire the mutation and get a Promise of the result. Rejects with a CapxulError on failure. |
data | The mutation result (typed per hook, shown above). undefined until the first success. |
error | A CapxulError when the last attempt failed, otherwise null. |
isPending | true while the mutation is in flight. Use it to disable submit buttons. |
reset | Clear the mutation state (data, error) back to idle. |
Mutations do not retry by default. The full field list is in the
TanStack Query useMutation reference;
see also the TanStack Query integration guide.
Client-backed mutation hooks are safe to render while CapxulProvider
bootstraps. If one is fired before bootstrap finishes, mutateAsync rejects
with a CapxulError whose code is WRONG_STATE; applications do not need to
hide their route tree behind useCapxul(). Every shipped mutation hook is
client-backed — alpha.23 removed the one client-free hook
(useCapxulSwitchActingEntity, a documented no-op).
Cache behavior
On success this mutation refreshes the personal money state: the payments list (and payment detail queries under it), the personal account balance, the personal activity projection, and the personal address book. Paying someone new records them as a counterparty.
Errors
Failures surface as a CapxulError on error /
thrown from mutateAsync. Notable modes: INVALID_INPUT for a raw 0x
address, an empty or unresolvable recipient (unknown handle, payee, or org
handle), or an invoice document that disagrees with the amount or line items;
NOT_IMPLEMENTED for an organization actor or a destination target.
Client method
This hook wraps client.payments.pay(input) on the core SDK.