Capxul Docs
HooksPayments

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:

FieldDescription
mutateFire the mutation (fire-and-forget; pair with onSuccess/onError callbacks).
mutateAsyncFire the mutation and get a Promise of the result. Rejects with a CapxulError on failure.
dataThe mutation result (typed per hook, shown above). undefined until the first success.
errorA CapxulError when the last attempt failed, otherwise null.
isPendingtrue while the mutation is in flight. Use it to disable submit buttons.
resetClear 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.

On this page