package mrktplaats import ( "encoding/json" "fmt" "time" ) // Price represents a listing price. All amounts are in euro cents. type Price struct { PriceType string `json:"priceType"` PriceTypeLabel string `json:"priceTypeLabel"` PriceAmount int `json:"priceAmount"` } // Picture represents an image with CDN URLs at various sizes. type Picture struct { ID int `json:"id"` ExtraSmall string `json:"extraSmall"` Medium string `json:"medium"` Large string `json:"large"` ExtraExtraLarge string `json:"extraExtraLarge,omitempty"` AspectRatio interface{} `json:"aspectRatio,omitempty"` Width int `json:"width,omitempty"` Height int `json:"height,omitempty"` } // AdAddress represents the geographic location of a listing. type AdAddress struct { City string `json:"city"` Country string `json:"country"` CountryAbbreviation string `json:"countryAbbreviation"` ZipCode string `json:"zipCode,omitempty"` Latitude float64 `json:"latitude"` Longitude float64 `json:"longitude"` } // Attribute represents a listing attribute (e.g. condition, brand). type Attribute struct { ID int `json:"id"` Key string `json:"key"` Name string `json:"name"` Values []AttributeValue `json:"values"` } // AttributeValue represents a single value of an attribute. type AttributeValue struct { ID int `json:"id"` Name string `json:"name"` } // AdCore contains the core fields shared across search results and item detail views. type AdCore struct { URN string `json:"urn"` Title string `json:"title"` Description string `json:"description,omitempty"` CategoryID int `json:"categoryId"` Price Price `json:"price"` Picture *Picture `json:"picture,omitempty"` Pictures []Picture `json:"pictures,omitempty"` AdAddress AdAddress `json:"adAddress"` Attributes []Attribute `json:"attributes,omitempty"` Link string `json:"link,omitempty"` } // SellerInformation identifies the seller of a listing. type SellerInformation struct { ID int `json:"id"` Name string `json:"name"` Type string `json:"type,omitempty"` Phone string `json:"phone,omitempty"` PhoneHidden bool `json:"phoneNumberHidden,omitempty"` AllowASQ bool `json:"allowAsq,omitempty"` ActiveSince json.RawMessage `json:"activeSince,omitempty"` SavedForUser bool `json:"savedForUser,omitempty"` KYCState json.RawMessage `json:"kycState,omitempty"` MerchantState string `json:"merchantState,omitempty"` DealerPackage string `json:"dealerPackage,omitempty"` } // User represents an authenticated user account. type User struct { ID int `json:"id"` EncryptedID string `json:"encryptedId"` Name string `json:"name"` Email string `json:"email"` Phone string `json:"phone"` ZipCode string `json:"zipCode"` ActivationDate string `json:"activationDate"` RegistrationDate string `json:"registrationDate"` OneClickOptedIn bool `json:"oneClickOptedIn"` OneClickBlocked bool `json:"oneClickBlocked"` ProfilePicture string `json:"profilePicture"` ShowMapOnVipEnabled bool `json:"showMapOnVipEnabled"` NdfcDeclarationStatus string `json:"ndfcDeclarationStatus"` } // DiscoveryPrice is the snake_case price used by older API3 endpoints. type DiscoveryPrice struct { PriceType string `json:"price_type"` PriceTypeLabel string `json:"price_type_label"` PriceAmount int `json:"price_amount"` } // DiscoveryPicture is the snake_case picture used by older API3 endpoints. type DiscoveryPicture struct { ID int `json:"id"` ExtraSmall string `json:"extra_small"` Medium string `json:"medium"` Large string `json:"large"` } // FlexTime is a time.Time that accepts dates without a timezone suffix // (e.g. "2025-10-18T14:50:53") in addition to standard RFC3339. type FlexTime struct{ time.Time } // UnmarshalJSON parses RFC3339 dates, falling back to local (UTC) parsing // when the timezone suffix is absent. func (ft *FlexTime) UnmarshalJSON(data []byte) error { if len(data) < 2 || data[0] != '"' { return nil } s := string(data[1 : len(data)-1]) t, err := time.Parse(time.RFC3339, s) if err != nil { t, err = time.ParseInLocation("2006-01-02T15:04:05", s, time.UTC) if err != nil { return fmt.Errorf("FlexTime: cannot parse %q", s) } } ft.Time = t return nil } // Review represents a user review. type Review struct { ID int `json:"id"` Reviewer ReviewUser `json:"reviewer"` Reviewee ReviewUser `json:"reviewee"` Direction string `json:"direction"` CreationDate FlexTime `json:"creationDate"` Score int `json:"score"` ItemID string `json:"itemId"` Advertisement ReviewAd `json:"advertisement"` Details []ReviewDetail `json:"details"` Content ReviewContent `json:"content"` ReviewSubject string `json:"reviewSubject"` } // ReviewUser is a participant in a review. type ReviewUser struct { ID int `json:"id"` Nickname string `json:"nickname"` } // ReviewAd is the listing associated with a review. type ReviewAd struct { ID string `json:"id"` Title string `json:"title"` CategoryName string `json:"categoryName"` } // ReviewDetail contains category-level review scoring. type ReviewDetail struct { Category string `json:"category"` Score int `json:"score"` Characteristics []ReviewCharacteristic `json:"characteristics"` } // ReviewCharacteristic is an individual review trait. type ReviewCharacteristic struct { ID int `json:"id"` Text string `json:"text"` IsPositive bool `json:"isPositive"` } // ReviewContent holds the textual content of a review. type ReviewContent struct { Subject string `json:"subject"` } // ReviewSummary provides aggregate review statistics. type ReviewSummary struct { NumberOfReviews int `json:"numberOfReviews"` AverageScore float64 `json:"averageScore"` }