Skip to main content
Claiming is the payoff of a tap. A customer taps your product, you confirm it is genuine, and you hand them the item. This is the first assignment of ownership out of a tap: the item has no prior owner, so no one has to authorize the hand-off. You supply only the recipient’s wallet address, and the session token the tap opened authorizes the write. That first-ownership shape is what sets a claim apart from a transfer, which moves an item between existing owners. Because a claim has no prior owner to sign, Endstate signs and submits it for you - so claiming is a single call. In React, that call is the useClaim() hook. The rest of this page leads with the hook and shows the Vanilla primitive alongside it.

The flow

In React, wrap the claim page in EndstateProvider and drive the claim from useClaim. With autoVerify on (the default) the provider captures and verifies the landing tap on mount, so useSession().item is the item the customer tapped and useWallet() provisions their address in the background. useClaim().claim() with no arguments claims into that wallet address, and because wait defaults to true it auto-settles before it resolves. status is a ClaimStatus you render the UI from. The Vanilla path picks up from a session you captured and verified yourself - the browser quickstart golden path and Tap capture cover how you get one, and Tap sessions covers what it is - then calls session.claims.create({ to }) and settles with waitUntilSettled.
The claim takes a single field:
string
The recipient’s EVM wallet address (0x followed by 40 hex characters). In React, omit it and claim() claims into the provisioned wallet address from useWallet(); pass one to target a specific address. Vanilla’s session.claims.create requires it - for a customer who brings no address of their own, this is (await wallet.ready()).address.
A claim reads unit_id from the session’s scope, so you never pass it. A session freshly opened by verify() (including the provider’s autoVerify) already carries that scope; one you adopted from a bare token does not, and the call throws EndstateSessionScopeError until you await session.refreshScope().
Endstate signs and submits the claim for you (execution defaults to endstate_relay), so a single claim() is the whole write; to broadcast it yourself from your own funded account or relayer instead, pass execution: "client_broadcast" and send the returned payload - see session.claims.create.

Settlement

A claim starts idle, and once claim() runs it moves through claiming (signed and submitted) and settling (awaiting confirmation) to one of three terminal statuses:
  • claimed - done. Ownership has transferred and settled.
  • expired - the signed authorization’s window (about 30 minutes) passed before the claim settled. Create a new claim.
  • failed - the submission did not settle. Create a new claim.
A thrown failure lands status on error and puts the Error on useClaim().error. In React you drive the whole progression off status; because wait defaults to true, claim() resolves only once the status is terminal, so you never write a poll loop. In Vanilla, session.claims.waitUntilSettled does that waiting for you:
It reads the claim on a backoff - starting at 1s, doubling to a 5s ceiling, and giving up at 120s by default - all overridable through its options. To poll yourself instead, call session.claims.get(claimId), or endstate.claims.get(unitId, claimId) from a secret-key client on your backend. Pass wait: false to opt out of auto-settlement and drive it yourself. On expired or failed, create a new claim.

Idempotency

Creating a claim is a mutation, so it is safe to retry with an idempotency key. Pass idempotencyKey; omit it and one is generated for you. Replaying the same key with the same body returns the original claim rather than opening a second one; the same key with a different body is rejected as a conflict.

Errors

Every failure carries a branchable code. In React it surfaces on useClaim().error with status set to error; in Vanilla session.claims.create throws it. For how those errors behave and what retries automatically, see Errors and retries; for the full claim code list - unit.not_minted, claim.in_progress, claim.already_to_recipient, session_token.wrong_chip, and the rest - see session.claims.create and the Claim a unit guide.

Next steps

session.claims.create

The claim request body, execution modes, and every error code.

Transfer ownership

Move an item between existing owners - the sibling action to a claim.

Wallet

Provision the recipient address the claim sends the item to.

Claim a unit

The credential-neutral walkthrough and the full error matrix.