GET /v3/item/:id — item detail
const url = 'https://api-ha-prod-p8.handbid.dev/v3/item/example';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url https://api-ha-prod-p8.handbid.dev/v3/item/example \ --header 'Authorization: Bearer <token>'NEW (HAN-1686, 2026-05-07; expanded by HAN-1907 2026-05-27). Item-detail screen payload — full content for the card-tap → detail flow on iOS. Strict superset of the items-list card shape plus full description / image carousel / per-caller bidding state.
Auth: OPTIONAL. Bearer token flips the per-user fields isCurrentUserWinning, userAutoBidMax, isFavorite, and hasCurrentUserBid. Missing/invalid token degrades silently to anonymous (same opportunistic pattern as /v3/auction/:id/items).
Wire shape — identity + core:
id,auctionId,auctionGuid,name,itemTypestatusId+status(string label)itemCode,categoryId,categoryNamecurrency(3-letter ISO code; defaults toUSDwhen the auction has no configured currency)
Money + bid state:
currentPrice,startingPrice,bidIncrement,minimumBidAmount,buyNowPrice(nullable),marketValue,reservePrice(nullable),showValue(bool — whether the auction is configured to exposemarketValueon the card)bidCount,bidderCount— both hook-maintained fromitem_stats(validBidQuantity + validBidderCount); zero allocations during the read.closingTime(epoch, nullable — cascades item → category → auction timer)
Inventory + tickets:
hasInventory(bool),inventoryTotal,quantitySold— all fromitem_stats.quantitySold.inventoryRemainingis null whenhasInventory=0.admits(ticket items only — admission count),ticketInstructions(string; null for non-ticket items)
Long-form content (the reason this endpoint exists vs the list shape):
description— full text (legacy WYSIWYG may emit HTML).finePrint— sourced fromitems.notables(legacy column name).videoEmbedCode,redemptionInstructions,donor— all nullable.images[]— full carousel as[{ url, isPrimary }]. Sorted: primary first, then byord, then byitemImageId.
Auction context (so the client can detect staleness without a separate auction-state poll):
auctionStatusId,auctionEndTime,auctionTimerStartTime,auctionTimerEndTime,auctionShowName(whether to display real bidder names vs paddle numbers).
Winner + per-caller state:
winnerId(nullable; fromitem_stats.highestBidId→bids.userId).winningBidderLabel(nullable) — composed perauctionShowNamerules:"Full Name (#paddleId)"when showName=true and a name is available, elsealias, else"Paddle#paddleId".isCurrentUserWinning(bool) — true iffwinnerId == currentUserId(alwaysfalseon anonymous reads).userAutoBidMax(decimal, nullable) — caller’s activemax_bids.amountfor this item if any.isFavorite(bool, always present) —user_favorite_item_relationEXISTS for caller (alwaysfalseon anonymous).isFeatured(bool) — auction-scoped featured flag.controlMode— string enum; same derivation + 9-value range as the items-list endpoint (purchase/donate/bid-with-buy-now/bid/sealed-bid/competitive-bid/bidbox/puzzle/view-only).hasCurrentUserBid(bool, always present) — NEW (HAN-1907) — true iff the caller has at least one bid row on this item withstatus IN ('winning', 'losing', 'purchase')(the V3 active-bid allowlist —MY_ACTIVITY_BID_STATUSES). Excludes lifecycle/terminal states (failed,removed,replaced,incomplete,sold_out,winning_changed,transferred) because those bids no longer “matter now” for the outbid-banner state. Drives the iOS “you’ve been outbid” banner — distinguishes “you bid and got outbid” from “you never bid.” Alwaysfalseon anonymous reads.
Errors:
- 400 when
:idis non-positive. - 404 not_found for missing, soft-deleted, deleted-events-org, test-auction, item-status-outside-visible-set, or privacy-blocked items. Privacy gate is identical to
/v3/auction/:id/itemsso an item visible in the list is always reachable via the detail endpoint.
Cache: per-user key v3:item:{id}:detail:{userId|anon}, 30s TTL, tagged on V3CacheTags::auction($auctionId) + V3CacheTags::userFavorites($userId) when authed. Bid placement/removal/replacement from any origin (V3 POST, manager, V1, purchase) invalidates the auction tag via HbBid::afterSave() / afterDelete(), so hasCurrentUserBid and isCurrentUserWinning flip on the next read without a TTL wait.
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters ”Responses
Section titled “ Responses ”Successful response