July 2026
Transfer a unit between owners
A unit can now move from its current owner to a new owner — tap-authorized like a claim, but executed by the current owner:POST /v1/units/{unit_id}/transfers(session token required) creates the transfer and returns atransactionpayload. Only the unit’s current owner can submit it — Endstate authorizes the transfer but never relays it, and the authorization is valid for 30 minutes.GET /v1/units/{unit_id}/transfers/{transfer_id}(API key or session token) polls status:prepared→confirmed;expiredandfailedare terminal.- New error codes:
transfer.in_progress,transfer.already_to_recipient,transfer.owner_unknown,transfer.not_found.
Replace a unit’s chip
Until a unit is claimed, its chip can now be replaced — for example when a chip is damaged or fails QA after pairing but before the item reaches its owner:POST /v1/units/{unit_id}/chip-replacementspairs an existing, unpaired chip to the unit and retires the current one. Endstate performs the swap; replacement is asynchronous.GET /v1/units/{unit_id}/chip-replacements/{replacement_id}polls status (prepared→submitted→confirmed;failedis terminal).- New error codes:
chip_replacement.locked(unit already claimed — the chip is permanently locked),chip_replacement.in_progress, andchip_replacement.not_found.
chain_id is now optional on collection create
Collections are created on your organization’s default network when chain_id is omitted — configured by Endstate at onboarding, so most integrations never need to send a network identifier. An explicit chain_id is still accepted as an override, but must be one of the networks enabled for your organization.GET /v1/settings now returns your network configuration alongside default_redirect_url: default_chain_id (the default network, or null if none is configured) and allowed_chain_ids (the networks an explicit chain_id may use). Both are read-only.No migration needed — requests that send chain_id keep working unchanged.Single-resource responses are now top-level (breaking)
POST, GET, and PATCH responses for collections and units previously wrapped the resource in an envelope — { "collection": {...} } / { "unit": {...} }. They now return the resource’s fields at the top level, making every single-resource response uniform (chips, verify, session tokens, claims, and settings were already top-level).Migration: if your integration reads response.collection.id or response.unit.id from these endpoints, read the same fields at the top level instead (response.id, response.collection.token, …). List responses are unchanged — they still wrap under a plural key alongside pagination. See Response shape.Empty request bodies accepted on all-optional POSTs
APOST with a JSON content-type and an empty body previously failed JSON parsing. An empty or whitespace-only body is now treated as {}, so requests like POST /v1/chips/{chip_id}/tap work without a body. Endpoints with required body fields still validate as before.June 2026
Tap redirects
Control where a user lands after tapping a chip, at three levels — the most specific one wins:redirect_urlis a new (nullable, always-present) field on the unit and collection resources, accepted on create and editable via newPATCH /v1/units/{unit_id}andPATCH /v1/collections/{collection_id}endpoints.- New
GET/PATCH /v1/settingsendpoints manage the org-widedefault_redirect_url. - Redirected taps carry
endstate_chip_idandendstate_equery parameters so your page can verify the tap.
Claims
Transfer on-chain ownership of a unit to a recipient wallet, authorized by the session token from a recent tap of that unit’s chip:POST /v1/units/{unit_id}/claimscreates a claim (endstate_relayorclient_broadcastexecution).GET /v1/units/{unit_id}/claims/{claim_id}polls status (claiming→claimed/expired/failed).

