Skip to main content
The ClaimModal returns a failed or rejected EVM deposit to the user, on the chain it came from. The user pastes the deposit’s transaction hash; the modal looks it up and asks your app to authorize the refund. No wallet is involved, and there is no source chain to pick — the hash is looked up across every chain, so a deposit that landed on a chain your deposit flow doesn’t offer is still claimable.
New in v0.9.0, on the ./claim subpath. Applies to deposits in failed or rejected status; see troubleshooting for the dashboard equivalent.

Why your app authorizes it

Deposit accounts are service-managed, so no user wallet can sign for a refund, and an exchange-funded deposit has no signable sender either. Only your app knows which of its users a deposit belongs to, so refundEndpoint points at something you control. Two shapes, depending on where that endpoint lives:
The browser’s session cookie travels with the request, so your route authenticates the user the way it always does. No token needed — omit getUserToken.

Implementing the endpoint

@rhinestone/deposit-modal/server exports createRefundHandler, which does everything except decide who the caller is. It verifies the deposit belongs to the recipient you name before spending your API key.
It returns a (Request) => Promise<Response>, so it mounts in any fetch-based runtime — Next.js route handlers, Hono, Bun.serve, Cloudflare Workers.
Import from @rhinestone/deposit-modal/server only. It holds your API key and must never reach the browser.

authorize

Return the deposit recipient the caller owns, or null to reject with 401. depositRecipient does not decide where money goes. The handler lists deposits settling to it and rejects a txHash that isn’t among them — that’s the whole job. One value covers every deposit account the user has, since the account salt includes the target chain and token. Set refundDestination whenever you already know where the user’s money should go. Without it the page picks, and it could pick anything.
Never refund to an exchange deposit address. Exchanges don’t credit arbitrary incoming transfers, so the funds may be lost. This is why the modal never defaults the destination to the deposit’s sender.

Request body

The modal POSTs a RefundRequest. It comes from the page, so treat it as untrusted.

Props reference

Required

Authorization

Prefills

Backend

Display

Callbacks

Lifecycle events

ClaimLifecycleEvent shares no variants with the deposit or withdraw unions, so don’t reuse a handler across them.