Skip to content

GET /v3/item/:id/purchases — purchase history

GET
/v3/item/{itemId}/purchases
curl --request GET \
--url 'https://api-ha-prod-p8.handbid.dev/v3/item/example/purchases?limit=20' \
--header 'Authorization: Bearer <token>'

NEW (HAN-1915). Paginated purchase history for an item, read from the canonical purchases table (not bids). Companion to /v3/item/:id/bids: for direct-purchase itemTypes (forSale, ticket, appeal, customDonation, dafDonation) this is the right rail — the bid-shaped /bids endpoint omits quantity/total.

Auth: OPTIONAL Bearer. isCurrentUser is decorated per-request (the cache entry is shared, no userId in the key). isAnonymous=1 rows mask the bidder identity uniformly for every viewer (“Anonymous Supporter”, paddleNumber null).

Query: limit (1-100, default 20), offset (default 0).

Response:

{
  "purchases": [
    { "id": 998877, "quantity": 2, "pricePerItem": 75.0, "grandTotal": 150.0,
      "premium": null, "tax": null, "time": 1781518101,
      "paddleNumber": 173, "bidderName": "Paddle#173", "isAnonymous": false,
      "isPaid": true, "isRefunded": false, "isPayLater": false,
      "fundraiserId": null, "recurringDonationId": null, "isCurrentUser": true }
  ],
  "totalCount": 1
}

Money fields (pricePerItem, grandTotal, premium, tax) are floats in the auction’s currency. isPaid is the per-purchase flag (purchases.isPaid, HAN-2050), not the receipt-level flag.

Errors: 400 when :id ≤ 0; 404 not_found (same privacy gate as item detail).

Cache: shared key (no userId), 10s TTL, tag V3CacheTags::auction($auctionId). Note: console raw-delete maintenance paths (HbCompetitiveBidController, HbBidboxController) bypass the AR hook, so up to the TTL of staleness is accepted there.

itemId
required
string
limit
integer

1-100, default 20

Example
20

Successful response

Media type application/json