Skip to content

POST /v3/bidder/favorite/:itemId

POST
/v3/bidder/favorite/{itemId}
curl --request POST \
--url https://api-ha-prod-p8.handbid.dev/v3/bidder/favorite/example \
--header 'Authorization: Bearer <token>'

NEW (HAN-1864, 2026-05-21). Add the item to the authenticated user’s favorites. Companion to the existing GET /v3/bidder/favorites (HAN-1586) read endpoint.

Auth: required.

Response (204 No Content): empty body. Idempotent — re-favoriting an already-favorited item also returns 204 with no side-effect.

Errors:

  • 404 not_found — itemId doesn’t exist (or is soft-deleted).
  • 403 forbidden — item is in an auction the user can’t see (private auction without direct AUR, etc.). Mirrors the visibility precedence used by GET /v3/bidder/favorites.
  • 429 rate_limited — per-user bidderFavoriteToggle throttle.
  • 400 validation_error — non-positive itemId.

Side-effects: writes to user_favorite_item_relation. The existing HbUserFavoriteItems AR model fires:

  • EVENT_AFTER_INSERTHbNodeUserFavoriteItemsBehavior queues event.favorite to room:{userGuid} with {action: "add", itemId}. Async via RabbitMQ → Go node_event consumer → Socket.io. Lets the user’s other connected devices flip local favorited state without re-polling.
  • afterSave → drops V3CacheTags::userFavorites($userId) so the next GET re-reads.

Performance: 3-roundtrip worst case (item exists-check + visibility-check + INSERT), 2-roundtrip on idempotent re-favorite (skip INSERT). All lookups index-covered (PRIMARY on items, idx_aur_auction_user_deleted on auction_user_relation, idx_ufir_user_item_deleted on user_favorite_item_relation). Target p99 < 150ms.

Design rationale: soft-delete pattern (writing isDeleted=1) was considered but rejected — the table has no UNIQUE constraint on (userId, itemId), so INSERT ... ON DUPLICATE KEY UPDATE would never trigger. Hard insert + delete also matches V1 ItemController::actionFavorite semantics, keeping V1/V3 in sync.

itemId
required
string

Successful response

Media type application/json