package mrktplaats import ( "context" "encoding/json" "fmt" "net/url" "strings" ) // ListingService handles viewing individual listing details (VIP). type ListingService struct { t *transport } // ListingDetail is the full detail view of a single listing. type ListingDetail struct { AdCore AdCore `json:"adCore"` SellerInformation SellerInformation `json:"sellerInformation"` Bids []Bid `json:"bids,omitempty"` CurrentMinimumBid int `json:"currentMinimumBid,omitempty"` ShowBanner bool `json:"showBanner,omitempty"` Traits json.RawMessage `json:"traits,omitempty"` BuyersProtectionAllowed bool `json:"buyersProtectionAllowed,omitempty"` IsBuyerProtectionApplicableForDefaultOn bool `json:"isBuyerProtectionApplicableForDefaultOn,omitempty"` LargeItemShippingLogicalAllowed bool `json:"largeItemShippingLogicalAllowed,omitempty"` } // DefaultCTATypes is the standard set of CTA types the client declares support for. var DefaultCTATypes = []string{"bid", "asq", "website", "phone", "buyNow"} type viewItemRequest struct { SupportedCTATypes []string `json:"supportedCTATypes"` SupportsReservedFlag bool `json:"supportsReservedFlag"` } // Get retrieves the full details of a listing by its URN. // An optional correlationID (from a prior search) can be passed for analytics. func (s *ListingService) Get(ctx context.Context, urn string, correlationID ...string) (*ListingDetail, error) { path := fmt.Sprintf("/app/vip/v4/item/%s", urn) var params url.Values if len(correlationID) > 0 && correlationID[0] != "" { params = url.Values{"correlation_id": {correlationID[0]}} } body := viewItemRequest{ SupportedCTATypes: DefaultCTATypes, SupportsReservedFlag: true, } var resp ListingDetail if err := s.t.postJSON(ctx, path, params, nil, body, &resp); err != nil { return nil, err } return &resp, nil } // VIPDisplayTargetingRequest defines parameters for item page ad targeting. // Positions is serialized as a comma-separated string; Postcode and SellerID // are sent as JSON null when empty. type VIPDisplayTargetingRequest struct { AdURN string Attr json.RawMessage Positions []string Postcode string SellerID string } // MarshalJSON serializes in the format the marktplaats API expects. func (r VIPDisplayTargetingRequest) MarshalJSON() ([]byte, error) { attr := r.Attr if len(attr) == 0 { attr = json.RawMessage(`{}`) } type wire struct { AdURN string `json:"adUrn"` Attr json.RawMessage `json:"attr"` Positions string `json:"positions"` Postcode *string `json:"postcode"` SellerID *string `json:"sellerId"` } w := wire{ AdURN: r.AdURN, Attr: attr, Positions: strings.Join(r.Positions, ", "), } if r.Postcode != "" { w.Postcode = &r.Postcode } if r.SellerID != "" { w.SellerID = &r.SellerID } return json.Marshal(w) } // DefaultVIPPositions are the standard ad positions for an item detail page. var DefaultVIPPositions = []string{ "VIP_LEADERBOARD_MID1", "vip_native", "vip_native_2", "VIP_GALLERY_BANNER", "VIP_DESCRIPTION_BANNER", } // DisplayTargeting retrieves ad targeting configuration for a listing detail page. func (s *ListingService) DisplayTargeting(ctx context.Context, req *VIPDisplayTargetingRequest) ([]DisplayTargetingResult, error) { var resp []DisplayTargetingResult if err := s.t.postJSON(ctx, "/app/vip/v4/display-targeting", nil, nil, req, &resp); err != nil { return nil, err } return resp, nil }