> ## Documentation Index
> Fetch the complete documentation index at: https://docs.endstate.io/llms.txt
> Use this file to discover all available pages before exploring further.

# useTransfer

> Prepare a transfer of an owned item to a new owner. Endstate authorizes the move; the current owner broadcasts the returned transaction with their own signer.

```ts theme={null}
function useTransfer(): {
  transfer: (args: {
    to: string;
    idempotencyKey?: string;
    wait?: boolean;
  }) => Promise<Transfer>;
  status: TransferStatus;
  data: Transfer | null;
  error: Error | null;
  reset: () => void;
};

type TransferStatus =
  | "idle"
  | "preparing"
  | "settling"
  | "confirmed"
  | "expired"
  | "failed"
  | "error";
```

A transfer moves an item between existing owners. Unlike a [claim](/sdks/web/reference/react/useClaim), the item already has an owner, so only that current owner can complete it: Endstate authorizes the move and hands back a transaction, but never moves an item on an owner's behalf. That is why `transfer()` takes no `execution` option - there is no Endstate-submitted mode.

`transfer()` prepares the move against the active session [`useSession`](/sdks/web/reference/react/useSession) holds and returns a [`Transfer`](/sdks/core/reference/session-transfers/create) whose `transaction` field is the authorized payload. **The current owner broadcasts that transaction with their own signer, outside this hook** - so preparing and broadcasting are separate steps, and `transfer()` does not wait for settlement by default.

## Example

```tsx theme={null}
"use client";
import { useTransfer } from "@endstate-sdk/web/react";

function TransferButton() {
  const { transfer, status, data, error } = useTransfer();
  const to = "0x..."; // where the item is going

  return (
    <div>
      <button
        onClick={() => transfer({ to })}
        disabled={status === "preparing"}
      >
        Prepare transfer
      </button>

      {/* Endstate authorized the move. The current owner now broadcasts
          data.transaction with their own signer - see the core reference. */}
      {data?.transaction && <p>Ready to broadcast to {to}.</p>}
      {status === "error" && <p>Could not prepare: {error?.message}</p>}
    </div>
  );
}
```

Once the owner broadcasts the returned transaction, poll the **original** transfer for settlement - `session.transfers.waitUntilSettled(data.id)` with the [`session`](/sdks/web/reference/react/useSession) from `useSession()`. Calling `transfer()` again would create a second transfer, not observe the first (each call uses a fresh idempotency key). Broadcast well within about 30 minutes: the signed authorization expires after that and the transfer settles `expired`.

## The transfer call

<ParamField body="to" type="string" required>
  The recipient's EVM wallet address (`0x` followed by 40 hex characters) - the
  account that will receive the item. Required: a transfer always names its
  recipient.
</ParamField>

<ParamField body="idempotencyKey" type="string">
  Makes the transfer safe to retry. Replaying the same key with the same body
  returns the original transfer; omit it and core generates one.
</ParamField>

<ParamField body="wait" type="boolean" default="false">
  Waiting is opt-in because the owner broadcasts the transaction externally.
  Leave it unset to resolve as soon as the transfer is prepared; set it to
  `true` to poll to a terminal status after the owner has broadcast.
</ParamField>

## Returns

<ResponseField name="transfer" type="(args) => Promise<Transfer>">
  Prepares the transfer and returns it with an authorized `transaction`. Rejects
  with a typed error; throws if there is no active session yet. It never
  broadcasts - the current owner does that with their own signer.
</ResponseField>

<ResponseField name="status" type="TransferStatus">
  `"idle"` before a transfer, `"preparing"` while the request is in flight,
  `"settling"` once prepared and awaiting the owner's broadcast, then terminal
  `"confirmed"`, `"expired"`, or `"failed"`; `"error"` when the call throws. On
  `"expired"` or `"failed"`, prepare a new transfer.
</ResponseField>

<ResponseField name="data" type="Transfer | null">
  The latest transfer resource, including the authorized `transaction` to
  broadcast, or `null` before the first call.
</ResponseField>

<ResponseField name="error" type="Error | null">
  The failure that moved `status` to `"error"`, or `null`. Branch on the error
  `code`; see [Errors and retries](/sdks/core/errors-and-retries).
</ResponseField>

<ResponseField name="reset" type="() => void">
  Clears `status`, `data`, and `error` back to idle and aborts an in-flight
  settlement poll.
</ResponseField>

<Note>
  Broadcasting the returned transaction with the current owner's signer is a
  core concern, not part of this hook. See
  [`session.transfers.create`](/sdks/core/reference/session-transfers/create)
  for the transaction shape and who must send it.
</Note>

## See also

<CardGroup cols={2}>
  <Card title="Transfer ownership" icon="repeat" href="/sdks/web/transfer">
    The transfer flow, who broadcasts, and settlement in prose.
  </Card>

  <Card title="useClaim" icon="hand" href="/sdks/web/reference/react/useClaim">
    Assign first ownership out of a tap - the sibling action.
  </Card>

  <Card title="session.transfers.create" icon="arrow-right-left" href="/sdks/core/reference/session-transfers/create">
    The request body, the returned transaction, and every error code.
  </Card>

  <Card title="useSession" icon="badge-check" href="/sdks/web/reference/react/useSession">
    The session a transfer is prepared against.
  </Card>
</CardGroup>
