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. For cash-out to a saved destination use useCapxulPayout; for an external wallet use useCapxulWithdraw. 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: 2 },
          })
        }
      >
        {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

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 it. The one lane that accepts a raw address is useCapxulWithdraw. The TargetReference union also has a destination variant, but pay rejects it with NOT_IMPLEMENTED — use useCapxulPayout for saved destinations.

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 recipient's kind and label, attached document references, the timing clause, and the released / availableToClaim amounts for commitments.

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.

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 insights summary and history, 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