Connectors: Bonhams, Christie's, Sotheby's, Catawiki auction results + shared category mapper (agent I)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
22 changed files +8,303 −28
added
connectors/api/_auction-lib/categories.test.ts
+36 −0
@@ -0,0 +1,36 @@ | ||
| 1 | +import { describe, expect, it } from 'vitest'; | |
| 2 | +import { hintFromLabel, isBundleTitle, slugFromTitle, watchBrand, watchReference } from './categories.js'; | |
| 3 | + | |
| 4 | +describe('auction category mapping', () => { | |
| 5 | + it('watch departments', () => { | |
| 6 | + expect(slugFromTitle('ROLEX. A STAINLESS STEEL WRISTWATCH REF. 16610 SUBMARINER', 'watches')).toBe('rolex'); | |
| 7 | + expect(slugFromTitle('Patek Philippe Nautilus 5711/1A-010', 'watches')).toBe('patek_philippe'); | |
| 8 | + expect(slugFromTitle('Audemars Piguet Royal Oak 15202ST', 'watches')).toBe('audemars_piguet'); | |
| 9 | + expect(slugFromTitle('Omega Speedmaster Professional 145.022', 'watches')).toBe('omega'); | |
| 10 | + expect(slugFromTitle('Hermès Birkin 35 Togo', 'watches')).toBe('luxury_handbags'); | |
| 11 | + expect(slugFromTitle('A diamond and platinum ring, 2.01 carats', 'watches')).toBe('jewelry'); | |
| 12 | + expect(slugFromTitle('Montblanc Meisterstück fountain pen 149', 'watches')).toBe('pens'); | |
| 13 | + expect(watchBrand('CARTIER TANK LOUIS').brand).toBe('Cartier'); | |
| 14 | + expect(watchReference('Ref. 5711/1A-010')).toBe('5711/1A-010'); | |
| 15 | + }); | |
| 16 | + it('labels → hints', () => { | |
| 17 | + expect(hintFromLabel('Wines & Spirits')).toBe('wine'); | |
| 18 | + expect(hintFromLabel('Coins, Medals and Banknotes')).toBe('coins'); | |
| 19 | + expect(hintFromLabel('Designer Handbags & Fashion')).toBe('handbags'); | |
| 20 | + expect(hintFromLabel('Popular Culture')).toBe('popular_culture'); | |
| 21 | + expect(hintFromLabel('Science and Natural History')).toBe('natural_history'); | |
| 22 | + expect(hintFromLabel('Sneakers, Streetwear & Modern Collectables')).toBe('fashion'); | |
| 23 | + expect(hintFromLabel('Random Department')).toBe('unknown'); | |
| 24 | + }); | |
| 25 | + it('keyword sweeps and honesty', () => { | |
| 26 | + expect(slugFromTitle('LEGO 10179 Millennium Falcon UCS sealed', 'toys')).toBe('lego_sets'); | |
| 27 | + expect(slugFromTitle('Funko Pop! Marvel #01', 'toys')).toBe('funko'); | |
| 28 | + expect(slugFromTitle('Nike Air Jordan 1 Chicago 1985', 'fashion')).toBe('sneakers'); | |
| 29 | + expect(slugFromTitle('1999 Pokémon Base Set Charizard PSA 10', 'popular_culture')).toBe('pokemon'); | |
| 30 | + expect(slugFromTitle('Amazing Spider-Man #300 CGC 9.8', 'popular_culture')).toBe('marvel_comics'); | |
| 31 | + expect(slugFromTitle('Apollo 11 flown mission patch', 'popular_culture')).toBe('space'); | |
| 32 | + expect(slugFromTitle('Untitled abstract composition', 'unknown')).toBeNull(); | |
| 33 | + expect(isBundleTitle('A collection of 45 coins')).toBe(true); | |
| 34 | + expect(isBundleTitle('1 sovereign 1912')).toBe(false); | |
| 35 | + }); | |
| 36 | +}); | |
added
connectors/api/_auction-lib/categories.ts
+344 −0
@@ -0,0 +1,344 @@ | ||
| 1 | +/** | |
| 2 | + * Shared taxonomy mapping for auction-house connectors (Bonhams, Christie's, Sotheby's, Catawiki). | |
| 3 | + * Houses describe lots by department/category labels; we map label + title keywords to RareIndex | |
| 4 | + * taxonomy slugs (data/taxonomy/categories.json). When nothing matches we return null and the | |
| 5 | + * connector decides whether to keep the lot under a family slug or skip it — never invent attributes. | |
| 6 | + */ | |
| 7 | + | |
| 8 | +const WATCH_BRANDS: Array<[RegExp, string, string]> = [ | |
| 9 | + [/\brolex\b/i, 'rolex', 'Rolex'], | |
| 10 | + [/\bpatek\b/i, 'patek_philippe', 'Patek Philippe'], | |
| 11 | + [/\baudemars\b|\bap royal oak\b/i, 'audemars_piguet', 'Audemars Piguet'], | |
| 12 | + [/\bomega\b/i, 'omega', 'Omega'], | |
| 13 | + [/\brichard mille\b/i, 'other_watches', 'Richard Mille'], | |
| 14 | + [/\bvacheron\b/i, 'other_watches', 'Vacheron Constantin'], | |
| 15 | + [/\bcartier\b/i, 'other_watches', 'Cartier'], | |
| 16 | + [/\btudor\b/i, 'other_watches', 'Tudor'], | |
| 17 | + [/\bbreitling\b/i, 'other_watches', 'Breitling'], | |
| 18 | + [/\biwc\b/i, 'other_watches', 'IWC'], | |
| 19 | + [/\bjaeger[- ]lecoultre\b|\bjlc\b/i, 'other_watches', 'Jaeger-LeCoultre'], | |
| 20 | + [/\blange\b/i, 'other_watches', 'A. Lange & Söhne'], | |
| 21 | + [/\bbreguet\b/i, 'other_watches', 'Breguet'], | |
| 22 | + [/\bblancpain\b/i, 'other_watches', 'Blancpain'], | |
| 23 | + [/\bzenith\b/i, 'other_watches', 'Zenith'], | |
| 24 | + [/\bgrand seiko\b/i, 'other_watches', 'Grand Seiko'], | |
| 25 | + [/\bseiko\b/i, 'other_watches', 'Seiko'], | |
| 26 | + [/\btag heuer\b|\bheuer\b/i, 'other_watches', 'TAG Heuer'], | |
| 27 | + [/\bpanerai\b/i, 'other_watches', 'Panerai'], | |
| 28 | + [/\bhublot\b/i, 'other_watches', 'Hublot'], | |
| 29 | + [/\bf\.?\s?p\.?\s?journe\b/i, 'other_watches', 'F.P. Journe'], | |
| 30 | + [/\bmb&f\b/i, 'other_watches', 'MB&F'], | |
| 31 | + [/\bde bethune\b/i, 'other_watches', 'De Bethune'], | |
| 32 | + [/\bgreubel\b/i, 'other_watches', 'Greubel Forsey'], | |
| 33 | + [/\burwerk\b/i, 'other_watches', 'Urwerk'], | |
| 34 | + [/\blongines\b/i, 'other_watches', 'Longines'], | |
| 35 | + [/\bpiaget\b/i, 'other_watches', 'Piaget'], | |
| 36 | + [/\bchopard\b/i, 'other_watches', 'Chopard'], | |
| 37 | + [/\bvan cleef\b/i, 'other_watches', 'Van Cleef & Arpels'], | |
| 38 | + [/\bbulgari\b|\bbvlgari\b/i, 'other_watches', 'Bulgari'], | |
| 39 | + [/\bgirard[- ]perregaux\b/i, 'other_watches', 'Girard-Perregaux'], | |
| 40 | + [/\bulysse nardin\b/i, 'other_watches', 'Ulysse Nardin'], | |
| 41 | + [/\bfranck muller\b/i, 'other_watches', 'Franck Muller'], | |
| 42 | + [/\bbaume\b/i, 'other_watches', 'Baume & Mercier'], | |
| 43 | +]; | |
| 44 | + | |
| 45 | +export function watchBrand(title: string): { slug: string; brand: string | null } { | |
| 46 | + for (const [re, slug, brand] of WATCH_BRANDS) if (re.test(title)) return { slug, brand }; | |
| 47 | + return { slug: 'other_watches', brand: null }; | |
| 48 | +} | |
| 49 | + | |
| 50 | +/** Rolex-style reference numbers ("Ref. 116500LN", "REF 5711/1A-010", "126610LN"). */ | |
| 51 | +export function watchReference(title: string): string | null { | |
| 52 | + const m = title.match(/\b(?:ref(?:erence)?\.?\s*)([0-9]{3,6}[A-Z]{0,4}(?:[\/-][0-9A-Z]{1,6}){0,3})\b/i) ?? title.match(/\b([0-9]{5,6}(?:[A-Z]{1,3}|\/[0-9A-Z]{1,6}))\b/); | |
| 53 | + return m ? m[1]!.toUpperCase() : null; | |
| 54 | +} | |
| 55 | + | |
| 56 | +const HANDBAG = /\b(birkin|kelly|constance|hermès|hermes|chanel|louis vuitton|goyard|handbag|clutch|tote|mini bag|shoulder bag|pochette)\b/i; | |
| 57 | +const SNEAKER = /\b(sneaker|air jordan|nike|yeezy|dunk|adidas|new balance|air max|off-white x)\b/i; | |
| 58 | +const CARD = /\b(trading card|pokémon|pokemon|charizard|psa \d|bgs \d|cgc \d|topps|panini|upper deck|rookie card|magic: the gathering|yu-gi-oh)/i; | |
| 59 | +const COMIC = /\b(comic|#\d+\s*\(|amazing spider-man|detective comics|action comics|x-men|batman #|superman #|cgc|cbcs)\b/i; | |
| 60 | +const COMIC_STRONG = /\b(comic|amazing spider-man|detective comics|action comics|x-men #|batman #|superman #|incredible hulk #|fantastic four #|avengers #|spawn #)/i; | |
| 61 | +const LEGO = /\blego\b/i; | |
| 62 | +const FUNKO = /\bfunko\b|\bpop!\b/i; | |
| 63 | +const VINYL = /\b(vinyl|lp record|acetate|test pressing|78 rpm|shellac)\b/i; | |
| 64 | +const POSTER = /\b(poster|one[- ]sheet|lobby card|affiche)\b/i; | |
| 65 | +const GUITAR = /\b(guitar|stratocaster|telecaster|les paul|gibson|fender|bass guitar|synthesizer|moog)\b/i; | |
| 66 | +const PROP = /\b(screen[- ]used|prop|costume|worn by|production[- ]used|film-used|movie-used)\b/i; | |
| 67 | +const AUTOGRAPH = /\b(signed|autograph|inscribed|hand-signed)\b/i; | |
| 68 | +const JERSEY = /\b(jersey|game[- ]worn|match[- ]worn|match[- ]issued|game[- ]used|championship ring|olympic (?:gold|silver|bronze) medal|boxing gloves|signed ball|cricket bat|football boots)\b/i; | |
| 69 | +const COIN = /\b(coin|sovereign|guinea|denarius|aureus|stater|tetradrachm|solidus|ducat|thaler|dollar 18|morgan|double eagle|mint state|pcgs|ngc|ms6\d|ms7\d|au5\d|proof)\b/i; | |
| 70 | +const BANKNOTE = /\b(banknote|bank note|treasury note|currency note|specimen note|\bnote\b.*\bbank\b)/i; | |
| 71 | +const MEDAL = /\b(medal|order of|decoration|campaign group|dso|mc group|victoria cross)\b/i; | |
| 72 | +const STAMP = /\b(stamp|postal|cover|philatel|penny black|inverted)\b/i; | |
| 73 | +const WHISKY = /\b(whisky|whiskey|bourbon|macallan|springbank|bowmore|ardbeg|yamazaki|hibiki|karuizawa|glenfiddich|dalmore|laphroaig|brora|port ellen)\b/i; | |
| 74 | +const COGNAC = /\b(cognac|armagnac|calvados)\b/i; | |
| 75 | +const RUM = /\b(rum|rhum)\b/i; | |
| 76 | +const WINE = /\b(bottle|bottles|magnum|jeroboam|imperial|bordeaux|burgundy|champagne|château|chateau|domaine|romanée|romanee|petrus|lafite|latour|margaux|mouton|krug|dom pérignon|dom perignon|barolo|brunello|napa|screaming eagle|rhône|rhone|sauternes|port\b|vintage 19|vintage 20|cases? of \d|\d+\s*bts?\b|\bowc\b|\boc\b)/i; | |
| 77 | +const FOSSIL = /\b(fossil|ammonite|trilobite|dinosaur|tooth|skull|megalodon|mammoth|skeleton)\b/i; | |
| 78 | +const METEORITE = /\b(meteorite|pallasite|chondrite|lunar|martian)\b/i; | |
| 79 | +const MINERAL = /\b(mineral|specimen|quartz|amethyst|tourmaline|fluorite|azurite|malachite|geode|crystal cluster|agate)\b/i; | |
| 80 | +const MAP = /\b(map|atlas|globe|chart of|plan of)\b/i; | |
| 81 | +const MANUSCRIPT = /\b(manuscript|letter signed|autograph letter|document signed|typed letter|archive of)\b/i; | |
| 82 | +const CAMERA = /\b(leica|hasselblad|rolleiflex|camera|lens|nikon f|contax)\b/i; | |
| 83 | +const CAR = /\b(coupe|coupé|roadster|cabriolet|convertible|saloon|sedan|spyder|spider|berlinetta|gt\b|chassis no|vin\b|ferrari|porsche|lamborghini|bentley|aston martin|jaguar|mercedes-benz|bugatti|maserati|alfa romeo|mclaren)\b/i; | |
| 84 | +const MOTORCYCLE = /\b(motorcycle|motorbike|ducati|harley|triumph|norton|vincent|brough superior|bsa|moto guzzi|frame no)\b/i; | |
| 85 | +const AUTOMOBILIA = /\b(mascot|badge|enamel sign|petrol pump|steering wheel|racing helmet|race suit|programme|dashboard|hood ornament)\b/i; | |
| 86 | +const TOY = /\b(tin toy|tinplate|dinky|corgi|matchbox|hot wheels|teddy|steiff|barbie|action figure|star wars figure|transformers|he-man|g\.i\. joe|playmobil|doll\b)\b/i; | |
| 87 | +const MODEL_CAR = /\b(1:18|1:43|1:64|1:24|diecast|die-cast|autoart|cmc|minichamps|kyosho)\b/i; | |
| 88 | +const MODEL_TRAIN = /\b(märklin|marklin|hornby|lionel|bachmann|locomotive|gauge)\b/i; | |
| 89 | +const VIDEO_GAME = /\b(nintendo|sega|playstation|xbox|game boy|gameboy|atari|sealed game|wata|vga \d|nes\b|snes\b|n64\b|famicom)\b/i; | |
| 90 | +const JEWEL = /\b(ring|necklace|bracelet|brooch|earrings|pendant|diamond|sapphire|ruby|emerald|carat|cts?\b|tiara|van cleef|graff|harry winston|tiffany)\b/i; | |
| 91 | +const GEMSTONE = /\b(unmounted|loose diamond|loose stone|gia certified|gia report|rough diamond|natural pearl)\b/i; | |
| 92 | +const PEN = /\b(fountain pen|montblanc|namiki|pelikan|ballpoint|rollerball)\b/i; | |
| 93 | +const LIGHTER = /\b(lighter|dunhill|zippo|s\.t\. dupont)\b/i; | |
| 94 | +const PERFUME = /\b(perfume|parfum|fragrance|eau de)\b/i; | |
| 95 | +const CLOCK = /\b(clock|chronometer|regulator|longcase|bracket clock|carriage clock)\b/i; | |
| 96 | +const SILVER = /\b(silver|sterling|silver-gilt|vermeil|tea service|flatware|salver|tankard)\b/i; | |
| 97 | +const GLASS = /\b(glass|lalique|baccarat|murano|daum|gallé|galle|crystal vase|paperweight)\b/i; | |
| 98 | +const PORCELAIN = /\b(porcelain|meissen|sèvres|sevres|wedgwood|royal copenhagen|worcester|ceramic|earthenware|stoneware|faience|majolica|delft)\b/i; | |
| 99 | +const SCI = /\b(microscope|telescope|sextant|astrolabe|orrery|barometer|slide rule|calculating|theodolite|octant)\b/i; | |
| 100 | +const TYPEWRITER = /\btypewriter\b/i; | |
| 101 | +const MILITARIA = /\b(helmet|uniform|bayonet|sword|dagger|insignia|regiment|militaria|flintlock|musket|cannon|armour|armor|epaulette)\b/i; | |
| 102 | +const SPACE = /\b(apollo|nasa|space shuttle|flown|astronaut|cosmonaut|soyuz|gemini mission|mercury mission|lunar module)\b/i; | |
| 103 | +const AVIATION = /\b(aircraft|aviation|propeller|cockpit|spitfire|concorde|airline)\b/i; | |
| 104 | +const PHOTO = /\b(gelatin silver|photograph|silver print|c-print|chromogenic|platinum print|daguerreotype|albumen)\b/i; | |
| 105 | +const CONTEMPORARY = /\b(banksy|kaws|murakami|hirst|koons|kusama|basquiat|haring|warhol|richter|hockney|kapoor|kiefer|condo|nara|stik|invader)\b/i; | |
| 106 | +const ART = /\b(oil on canvas|oil on panel|acrylic on canvas|watercolour|watercolor|gouache|lithograph|screenprint|etching|engraving|woodcut|sculpture|bronze|drawing|pastel|ink on paper|mixed media|print\b|edition of)\b/i; | |
| 107 | +const BOOK = /\b(first edition|first printing|edition|volumes|vols?\.|folio|octavo|quarto|bound|binding|signed copy|incunabula|hardback|hardcover|dust[- ]?jacket)\b/i; | |
| 108 | +const ANIMATION = /\b(animation cel|production cel|celluloid|disney studio|storyboard|concept art)\b/i; | |
| 109 | +const CHESS = /\b(chess set|chessmen|chess board)\b/i; | |
| 110 | +const ANTIQUE_FURNITURE = /\b(commode|chair|table|cabinet|bureau|chest of drawers|armchair|mirror|console|settee|sofa|desk|bookcase|sideboard|screen|tapestry|carpet|rug)\b/i; | |
| 111 | +const DESIGN = /\b(eames|prouvé|prouve|perriand|jeanneret|nakashima|noguchi|wegner|jacobsen|panton|memphis|sottsass|knoll|cassina|vitra|mid-century|scandinavian design)\b/i; | |
| 112 | + | |
| 113 | +/** Map a title to a slug given a loose department hint. Returns null when no confident match. */ | |
| 114 | +export function slugFromTitle(title: string, hint: DeptHint = 'unknown'): string | null { | |
| 115 | + const t = title; | |
| 116 | + // Highly specific signals first (independent of hint) | |
| 117 | + if (LEGO.test(t)) return 'lego_sets'; | |
| 118 | + if (FUNKO.test(t)) return 'funko'; | |
| 119 | + if (SNEAKER.test(t) && !/\bposter\b/i.test(t)) return 'sneakers'; | |
| 120 | + if (METEORITE.test(t)) return 'meteorites'; | |
| 121 | + if (hint === 'watches' || (/\b(wristwatch|watch|chronograph|pocket watch|tourbillon)\b/i.test(t) && hint !== 'jewelry')) { | |
| 122 | + if (HANDBAG.test(t) && !/\bwatch|chronograph|wristwatch\b/i.test(t)) return 'luxury_handbags'; | |
| 123 | + if (PEN.test(t) && !/\bwatch\b/i.test(t)) return 'pens'; | |
| 124 | + if (LIGHTER.test(t) && !/\bwatch\b/i.test(t)) return 'lighters'; | |
| 125 | + if (CLOCK.test(t) && !/\bwatch\b/i.test(t)) return 'clocks'; | |
| 126 | + if (JEWEL.test(t) && !/\bwatch|chronograph|wristwatch\b/i.test(t)) return 'jewelry'; | |
| 127 | + return watchBrand(t).slug; | |
| 128 | + } | |
| 129 | + if (hint === 'handbags' || HANDBAG.test(t)) return 'luxury_handbags'; | |
| 130 | + if (hint === 'jewelry') return GEMSTONE.test(t) ? 'gemstones' : 'jewelry'; | |
| 131 | + if (hint === 'wine') { | |
| 132 | + if (WHISKY.test(t)) return 'whisky'; | |
| 133 | + if (COGNAC.test(t)) return 'cognac'; | |
| 134 | + if (RUM.test(t)) return 'rum'; | |
| 135 | + return 'wine'; | |
| 136 | + } | |
| 137 | + if (WHISKY.test(t)) return 'whisky'; | |
| 138 | + if (COGNAC.test(t)) return 'cognac'; | |
| 139 | + if (hint === 'coins') { | |
| 140 | + if (BANKNOTE.test(t)) return 'banknotes'; | |
| 141 | + if (MEDAL.test(t) && !COIN.test(t)) return 'medals'; | |
| 142 | + return 'coins'; | |
| 143 | + } | |
| 144 | + if (hint === 'stamps' || STAMP.test(t) && hint === 'books') return 'stamps'; | |
| 145 | + if (hint === 'cars') return MOTORCYCLE.test(t) ? 'motorcycles' : AUTOMOBILIA.test(t) && !CAR.test(t) ? 'automotive_memorabilia' : 'automobiles'; | |
| 146 | + if (hint === 'motorcycles') return 'motorcycles'; | |
| 147 | + if (hint === 'automobilia') return 'automotive_memorabilia'; | |
| 148 | + if (hint === 'comics' || COMIC_STRONG.test(t)) { | |
| 149 | + if (ANIMATION.test(t)) return 'animation_art'; | |
| 150 | + if (/\b(marvel|spider-man|x-men|avengers|hulk|fantastic four|iron man|captain america|thor|wolverine|daredevil)\b/i.test(t)) return 'marvel_comics'; | |
| 151 | + if (/\b(dc comics|batman|superman|detective comics|action comics|wonder woman|flash|green lantern)\b/i.test(t)) return 'dc_comics'; | |
| 152 | + if (/\b(manga|tankobon|shonen jump)\b/i.test(t)) return 'manga'; | |
| 153 | + return 'independent_comics'; | |
| 154 | + } | |
| 155 | + if (hint === 'cards' || CARD.test(t)) { | |
| 156 | + if (/pok[eé]mon/i.test(t)) return 'pokemon'; | |
| 157 | + if (/magic: the gathering|\bmtg\b/i.test(t)) return 'magic_the_gathering'; | |
| 158 | + if (/yu-gi-oh/i.test(t)) return 'yugioh'; | |
| 159 | + if (/one piece/i.test(t)) return 'one_piece_card_game'; | |
| 160 | + if (/lorcana/i.test(t)) return 'disney_lorcana'; | |
| 161 | + if (/\b(basketball|nba|jordan|lebron|kobe)\b/i.test(t)) return 'basketball_cards'; | |
| 162 | + if (/\b(baseball|mlb|mantle|ruth|topps 195|bowman 195)\b/i.test(t)) return 'baseball_cards'; | |
| 163 | + if (/\b(football|nfl|brady|mahomes)\b/i.test(t)) return 'football_cards'; | |
| 164 | + if (/\b(hockey|nhl|gretzky|mcdavid)\b/i.test(t)) return 'hockey_cards'; | |
| 165 | + if (/\b(soccer|messi|ronaldo|mbapp|prizm world cup|panini fifa)\b/i.test(t)) return 'soccer_cards'; | |
| 166 | + if (/\b(f1|formula 1|verstappen|hamilton)\b/i.test(t)) return 'f1_cards'; | |
| 167 | + return hint === 'cards' ? 'other_tcg' : 'non_sport_cards'; | |
| 168 | + } | |
| 169 | + if (COMIC.test(t) && !CARD.test(t)) return /\b(marvel|spider-man|x-men|avengers|hulk)\b/i.test(t) ? 'marvel_comics' : /\b(batman|superman|dc comics)\b/i.test(t) ? 'dc_comics' : 'independent_comics'; | |
| 170 | + if (hint === 'popular_culture' || hint === 'entertainment') { | |
| 171 | + if (GUITAR.test(t)) return 'musical_instruments'; | |
| 172 | + if (VINYL.test(t)) return 'music'; | |
| 173 | + if (POSTER.test(t)) return 'movie_posters'; | |
| 174 | + if (ANIMATION.test(t)) return 'animation_art'; | |
| 175 | + if (PROP.test(t)) return 'movie_memorabilia'; | |
| 176 | + if (VIDEO_GAME.test(t)) return 'video_games'; | |
| 177 | + if (TOY.test(t)) return 'vintage_toys'; | |
| 178 | + if (SPACE.test(t)) return 'space'; | |
| 179 | + if (JERSEY.test(t)) return 'sports_memorabilia'; | |
| 180 | + if (/\b(beatles|rolling stones|bowie|elvis|hendrix|queen|pink floyd|led zeppelin|tour|concert|gold disc|platinum disc|setlist|lyrics)\b/i.test(t)) return 'music_memorabilia'; | |
| 181 | + if (/\b(star wars|harry potter|james bond|007|marvel|disney|lord of the rings|batman|indiana jones|jurassic|back to the future)\b/i.test(t)) return 'movie_memorabilia'; | |
| 182 | + if (AUTOGRAPH.test(t)) return 'autographs'; | |
| 183 | + return 'movie_memorabilia'; | |
| 184 | + } | |
| 185 | + if (hint === 'sports' || JERSEY.test(t)) return 'sports_memorabilia'; | |
| 186 | + if (hint === 'toys') { | |
| 187 | + if (MODEL_TRAIN.test(t)) return 'model_trains'; | |
| 188 | + if (MODEL_CAR.test(t)) return 'model_cars'; | |
| 189 | + if (VIDEO_GAME.test(t)) return 'video_games'; | |
| 190 | + if (/\b(action figure|hot toys|sideshow|figuarts|nendoroid|mafex)\b/i.test(t)) return 'action_figures'; | |
| 191 | + if (/\b(doll|barbie|blythe|bisque)\b/i.test(t)) return 'dolls'; | |
| 192 | + if (/\b(plush|teddy|steiff|jellycat)\b/i.test(t)) return 'plush'; | |
| 193 | + if (/\b(bearbrick|kaws|medicom|labubu|pop mart|kidrobot)\b/i.test(t)) return 'designer_toys'; | |
| 194 | + return 'vintage_toys'; | |
| 195 | + } | |
| 196 | + if (hint === 'natural_history') { | |
| 197 | + if (FOSSIL.test(t)) return 'fossils'; | |
| 198 | + if (MINERAL.test(t)) return 'minerals'; | |
| 199 | + return 'fossils'; | |
| 200 | + } | |
| 201 | + if (hint === 'science') return SCI.test(t) ? 'scientific_instruments' : TYPEWRITER.test(t) ? 'typewriters' : FOSSIL.test(t) ? 'fossils' : MINERAL.test(t) ? 'minerals' : 'scientific_instruments'; | |
| 202 | + if (hint === 'books') { | |
| 203 | + if (MAP.test(t)) return 'maps'; | |
| 204 | + if (MANUSCRIPT.test(t)) return 'historical_documents'; | |
| 205 | + if (PHOTO.test(t)) return 'photography'; | |
| 206 | + return 'books'; | |
| 207 | + } | |
| 208 | + if (hint === 'photographs') return PHOTO.test(t) || !ART.test(t) ? 'photography' : 'art'; | |
| 209 | + if (hint === 'prints') return CONTEMPORARY.test(t) ? 'contemporary_art' : 'art'; | |
| 210 | + if (hint === 'contemporary') return 'contemporary_art'; | |
| 211 | + if (hint === 'art') return CONTEMPORARY.test(t) ? 'contemporary_art' : PHOTO.test(t) ? 'photography' : 'art'; | |
| 212 | + if (hint === 'clocks') return 'clocks'; | |
| 213 | + if (hint === 'silver') return 'silver'; | |
| 214 | + if (hint === 'glass') return 'glass_crystal'; | |
| 215 | + if (hint === 'ceramics') return 'porcelain'; | |
| 216 | + if (hint === 'militaria') return MEDAL.test(t) ? 'medals' : 'militaria'; | |
| 217 | + if (hint === 'design') return 'design_furniture'; | |
| 218 | + if (hint === 'furniture' || hint === 'decorative') { | |
| 219 | + if (CLOCK.test(t)) return 'clocks'; | |
| 220 | + if (SILVER.test(t)) return 'silver'; | |
| 221 | + if (GLASS.test(t)) return 'glass_crystal'; | |
| 222 | + if (PORCELAIN.test(t)) return 'porcelain'; | |
| 223 | + if (DESIGN.test(t)) return 'design_furniture'; | |
| 224 | + if (CHESS.test(t)) return 'chess'; | |
| 225 | + return 'antiques'; | |
| 226 | + } | |
| 227 | + if (hint === 'cameras' || CAMERA.test(t)) return 'cameras'; | |
| 228 | + if (hint === 'music') return GUITAR.test(t) ? 'musical_instruments' : VINYL.test(t) ? 'music' : 'music_memorabilia'; | |
| 229 | + if (hint === 'movies') return POSTER.test(t) ? 'movie_posters' : PROP.test(t) ? 'movie_memorabilia' : ANIMATION.test(t) ? 'animation_art' : 'movie_memorabilia'; | |
| 230 | + if (hint === 'space') return 'space'; | |
| 231 | + if (hint === 'aviation') return AVIATION.test(t) ? 'aviation' : 'space'; | |
| 232 | + if (hint === 'perfume') return 'perfume'; | |
| 233 | + if (hint === 'pens') return PEN.test(t) ? 'pens' : LIGHTER.test(t) ? 'lighters' : 'pens'; | |
| 234 | + if (hint === 'fashion') return HANDBAG.test(t) ? 'luxury_handbags' : SNEAKER.test(t) ? 'sneakers' : 'fashion_streetwear'; | |
| 235 | + if (hint === 'video_games') return 'video_games'; | |
| 236 | + if (hint === 'asian' || hint === 'tribal' || hint === 'antiquities') return 'antiques'; | |
| 237 | + // No hint: broad keyword sweep | |
| 238 | + if (WINE.test(t) && /\b(19|20)\d{2}\b/.test(t)) return 'wine'; | |
| 239 | + if (COIN.test(t)) return 'coins'; | |
| 240 | + if (STAMP.test(t)) return 'stamps'; | |
| 241 | + if (JEWEL.test(t)) return 'jewelry'; | |
| 242 | + if (CAR.test(t) && /\b(19|20)\d{2}\b/.test(t)) return 'automobiles'; | |
| 243 | + if (VINYL.test(t)) return 'music'; | |
| 244 | + if (POSTER.test(t)) return 'movie_posters'; | |
| 245 | + if (GUITAR.test(t)) return 'musical_instruments'; | |
| 246 | + if (VIDEO_GAME.test(t)) return 'video_games'; | |
| 247 | + if (FOSSIL.test(t)) return 'fossils'; | |
| 248 | + if (MINERAL.test(t)) return 'minerals'; | |
| 249 | + if (MAP.test(t)) return 'maps'; | |
| 250 | + if (BOOK.test(t)) return 'books'; | |
| 251 | + if (PHOTO.test(t)) return 'photography'; | |
| 252 | + if (CONTEMPORARY.test(t)) return 'contemporary_art'; | |
| 253 | + if (ART.test(t)) return 'art'; | |
| 254 | + if (CLOCK.test(t)) return 'clocks'; | |
| 255 | + if (SILVER.test(t)) return 'silver'; | |
| 256 | + if (PORCELAIN.test(t)) return 'porcelain'; | |
| 257 | + if (GLASS.test(t)) return 'glass_crystal'; | |
| 258 | + if (SCI.test(t)) return 'scientific_instruments'; | |
| 259 | + if (MILITARIA.test(t)) return 'militaria'; | |
| 260 | + if (ANTIQUE_FURNITURE.test(t)) return 'antiques'; | |
| 261 | + return null; | |
| 262 | +} | |
| 263 | + | |
| 264 | +export type DeptHint = | |
| 265 | + | 'unknown' | 'watches' | 'handbags' | 'jewelry' | 'wine' | 'coins' | 'stamps' | 'cars' | 'motorcycles' | 'automobilia' | 'cards' | 'comics' | |
| 266 | + | 'popular_culture' | 'entertainment' | 'sports' | 'toys' | 'natural_history' | 'science' | 'books' | 'photographs' | 'prints' | 'contemporary' | 'art' | |
| 267 | + | 'clocks' | 'silver' | 'glass' | 'ceramics' | 'militaria' | 'design' | 'furniture' | 'decorative' | 'cameras' | 'music' | 'movies' | 'space' | 'aviation' | |
| 268 | + | 'perfume' | 'pens' | 'fashion' | 'video_games' | 'asian' | 'tribal' | 'antiquities'; | |
| 269 | + | |
| 270 | +/** Map a free-text department / category label from any house to a DeptHint. */ | |
| 271 | +export function hintFromLabel(label: string | null | undefined): DeptHint { | |
| 272 | + if (!label) return 'unknown'; | |
| 273 | + const l = label.toLowerCase(); | |
| 274 | + if (/watch|horolog/.test(l)) return 'watches'; | |
| 275 | + if (/handbag|luggage/.test(l)) return 'handbags'; | |
| 276 | + if (/jewel|gem/.test(l)) return 'jewelry'; | |
| 277 | + if (/wine|whisky|spirit|champagne/.test(l)) return 'wine'; | |
| 278 | + if (/coin|numismat|banknote|medal/.test(l)) return 'coins'; | |
| 279 | + if (/stamp|philatel|postal/.test(l)) return 'stamps'; | |
| 280 | + if (/motor ?car|\bcars\b|automobile|motoring/.test(l)) return 'cars'; | |
| 281 | + if (/motorcycle/.test(l)) return 'motorcycles'; | |
| 282 | + if (/automobilia/.test(l)) return 'automobilia'; | |
| 283 | + if (/trading card|sports card|pokémon|pokemon|tcg/.test(l)) return 'cards'; | |
| 284 | + if (/comic|animation/.test(l)) return 'comics'; | |
| 285 | + if (/popular culture|entertainment|rock|pop memorabilia|film memorabilia|music memorabilia/.test(l)) return 'popular_culture'; | |
| 286 | + if (/sport/.test(l)) return 'sports'; | |
| 287 | + if (/toy|model|doll|teddy/.test(l)) return 'toys'; | |
| 288 | + if (/natural history|fossil|mineral|meteorite/.test(l)) return 'natural_history'; | |
| 289 | + if (/scien|instrument|technology/.test(l)) return 'science'; | |
| 290 | + if (/book|manuscript|map|atlas|travel|exploration|library/.test(l)) return 'books'; | |
| 291 | + if (/photograph/.test(l)) return 'photographs'; | |
| 292 | + if (/print|multiple|edition/.test(l)) return 'prints'; | |
| 293 | + if (/contemporary|post-war|modern british|20th|21st|street art|urban art/.test(l)) return 'contemporary'; | |
| 294 | + if (/impressionist|old master|painting|fine art|\bart\b|drawing|sculpture|picture/.test(l)) return 'art'; | |
| 295 | + if (/clock|barometer/.test(l)) return 'clocks'; | |
| 296 | + if (/silver|vertu|objects of vertu/.test(l)) return 'silver'; | |
| 297 | + if (/glass|paperweight/.test(l)) return 'glass'; | |
| 298 | + if (/ceramic|porcelain|pottery/.test(l)) return 'ceramics'; | |
| 299 | + if (/arms|armour|armor|militar|medal/.test(l)) return 'militaria'; | |
| 300 | + if (/design/.test(l)) return 'design'; | |
| 301 | + if (/furniture|interiors|decorative|works of art|house sale|carpet|rug|tapestr/.test(l)) return 'furniture'; | |
| 302 | + if (/camera/.test(l)) return 'cameras'; | |
| 303 | + if (/music|instrument|guitar/.test(l)) return 'music'; | |
| 304 | + if (/movie|film|cinema|poster/.test(l)) return 'movies'; | |
| 305 | + if (/space|nasa/.test(l)) return 'space'; | |
| 306 | + if (/aviation|aeronautic/.test(l)) return 'aviation'; | |
| 307 | + if (/perfume|fragrance/.test(l)) return 'perfume'; | |
| 308 | + if (/pen|writing instrument|lighter/.test(l)) return 'pens'; | |
| 309 | + if (/fashion|sneaker|streetwear|couture|accessor/.test(l)) return 'fashion'; | |
| 310 | + if (/video ?game/.test(l)) return 'video_games'; | |
| 311 | + if (/asian|chinese|japanese|islamic|indian|himalayan|korean/.test(l)) return 'asian'; | |
| 312 | + if (/tribal|african|oceanic|native american|pre-columbian/.test(l)) return 'tribal'; | |
| 313 | + if (/antiquit|ancient/.test(l)) return 'antiquities'; | |
| 314 | + return 'unknown'; | |
| 315 | +} | |
| 316 | + | |
| 317 | +export function brandFromSlug(slug: string, title: string): string | null { | |
| 318 | + if (['rolex', 'patek_philippe', 'audemars_piguet', 'omega', 'other_watches'].includes(slug)) return watchBrand(title).brand; | |
| 319 | + if (slug === 'luxury_handbags') { | |
| 320 | + const m = title.match(/\b(herm[èe]s|chanel|louis vuitton|dior|gucci|goyard|fendi|bottega veneta|prada|celine|loewe|saint laurent)\b/i); | |
| 321 | + return m ? m[1]!.replace(/^herm[èe]s$/i, 'Hermès') : null; | |
| 322 | + } | |
| 323 | + if (slug === 'lego_sets') return 'LEGO'; | |
| 324 | + if (slug === 'funko') return 'Funko'; | |
| 325 | + return null; | |
| 326 | +} | |
| 327 | + | |
| 328 | +/** "PSA 10", "CGC 9.8" etc. are handled by @rareindex/taxonomy; this extracts a LEGO set number. */ | |
| 329 | +export function legoSetNumber(title: string): string | null { | |
| 330 | + const m = title.match(/\b(\d{4,5})(?:-1)?\b/); | |
| 331 | + return m ? m[1]! : null; | |
| 332 | +} | |
| 333 | + | |
| 334 | +export function isBundleTitle(title: string): boolean { | |
| 335 | + return /\b(collection of|group of|lot of|assorted|quantity of|\(\d{2,}\)|\d{2,}\s*(?:items|pieces|cards|bottles|coins)|set of \d{2,}|mixed lot|various)\b/i.test(title); | |
| 336 | +} | |
| 337 | + | |
| 338 | +export function safeYear(title: string): number | null { | |
| 339 | + const now = new Date().getUTCFullYear(); | |
| 340 | + const m = title.match(/\b(1[5-9]\d{2}|20\d{2})\b/); | |
| 341 | + if (!m) return null; | |
| 342 | + const y = Number(m[1]); | |
| 343 | + return y <= now ? y : null; | |
| 344 | +} | |
added
connectors/api/_auction-lib/smoke.ts
+57 −0
@@ -0,0 +1,57 @@ | ||
| 1 | +/** | |
| 2 | + * Live smoke + fixture capture for the auction-house connectors. | |
| 3 | + * Usage: pnpm tsx connectors/api/_auction-lib/smoke.ts <connectorId> [--limit N] [--seed URL]... [--category slug]... [--capture name] | |
| 4 | + * Requires FIRECRAWL_API_KEY / SCRAPFLY_API_KEY in the environment for the engines the connector uses. | |
| 5 | + */ | |
| 6 | +import { createCrawlContext, createRouter, getConnectorMeta, loadConnector } from '@rareindex/connectors'; | |
| 7 | +import { saveFixture } from '@rareindex/connectors/testing'; | |
| 8 | +import { childLogger } from '@rareindex/shared'; | |
| 9 | + | |
| 10 | +const [id, ...rest] = process.argv.slice(2); | |
| 11 | +if (!id) throw new Error('usage: smoke.ts <connectorId> [--limit N] [--seed URL] [--category slug] [--capture name]'); | |
| 12 | +const opt = { limit: 12, seeds: [] as string[], categories: [] as string[], capture: null as string | null }; | |
| 13 | +for (let i = 0; i < rest.length; i++) { | |
| 14 | + const a = rest[i]!; | |
| 15 | + if (a === '--limit') opt.limit = Number(rest[++i]); | |
| 16 | + else if (a === '--seed') opt.seeds.push(rest[++i]!); | |
| 17 | + else if (a === '--category') opt.categories.push(rest[++i]!); | |
| 18 | + else if (a === '--capture') opt.capture = rest[++i]!; | |
| 19 | +} | |
| 20 | + | |
| 21 | +const meta = getConnectorMeta(id); | |
| 22 | +const connector = await loadConnector(id); | |
| 23 | +const router = createRouter({ firecrawlApiKey: process.env.FIRECRAWL_API_KEY, scrapflyApiKey: process.env.SCRAPFLY_API_KEY }); | |
| 24 | +const ctx = createCrawlContext({ | |
| 25 | + router, | |
| 26 | + meta, | |
| 27 | + options: { mode: 'probe', limit: opt.limit, ...(opt.seeds.length ? { seeds: opt.seeds } : {}), ...(opt.categories.length ? { categories: opt.categories } : {}) }, | |
| 28 | + log: childLogger({ connector: id, smoke: true }), | |
| 29 | +}); | |
| 30 | + | |
| 31 | +let rawCount = 0; | |
| 32 | +let total = 0; | |
| 33 | +const kinds: Record<string, number> = {}; | |
| 34 | +let captured = 0; | |
| 35 | +for await (const raw of connector.crawl(ctx)) { | |
| 36 | + rawCount++; | |
| 37 | + const rawLike = { ...raw, externalId: raw.externalId ?? null, fetchedAt: raw.fetchedAt ?? new Date() }; | |
| 38 | + const records = await connector.normalize(rawLike); | |
| 39 | + total += records.length; | |
| 40 | + for (const r of records) kinds[r.kind] = (kinds[r.kind] ?? 0) + 1; | |
| 41 | + const p = raw.payload as { lots?: unknown[]; kind?: string }; | |
| 42 | + console.log(`raw#${rawCount} ${raw.kind} ${raw.url} → payload.${p.kind} lots=${p.lots?.length ?? '-'} → ${records.length} records`); | |
| 43 | + for (const r of records.slice(0, 2)) console.log(JSON.stringify(r, null, 1).slice(0, 1800)); | |
| 44 | + if (opt.capture && captured < 3 && records.length) { | |
| 45 | + const name = `${opt.capture}-${captured + 1}`; | |
| 46 | + const first = records[0]!; | |
| 47 | + saveFixture(id, name, { | |
| 48 | + raw: { ...rawLike, payload: JSON.parse(JSON.stringify(rawLike.payload)) }, | |
| 49 | + expect: { minCount: 1, kinds: [...new Set(records.map((r) => r.kind))], first: { kind: first.kind, ...('auctionHouse' in first ? { auctionHouse: (first as { auctionHouse: string }).auctionHouse } : {}), ...('currency' in first && first.currency ? { currency: first.currency } : {}) } }, | |
| 50 | + note: `Captured live by connectors/api/_auction-lib/smoke.ts on ${new Date().toISOString().slice(0, 10)} (${records.length} records from this raw page).`, | |
| 51 | + }); | |
| 52 | + captured++; | |
| 53 | + console.log(` saved fixture data/fixtures/${id}/${name}.json`); | |
| 54 | + } | |
| 55 | + if (rawCount >= 6) break; | |
| 56 | +} | |
| 57 | +console.log(JSON.stringify({ rawCount, totalNormalized: total, kinds, engineStats: ctx.engineStats, anomalies: ctx.anomalies }, null, 1)); | |
added
connectors/api/bonhams/index.test.ts
+84 −0
@@ -0,0 +1,84 @@ | ||
| 1 | +import { describe, expect, it } from 'vitest'; | |
| 2 | +import { getConnectorMeta } from '@rareindex/connectors'; | |
| 3 | +import { loadFixture, runFixtureSuite } from '@rareindex/connectors/testing'; | |
| 4 | +import createConnector, { auctionPageUrl, lotUrl, parseAuctionList, parseAuctionPage, type PagePayload } from './index.js'; | |
| 5 | +import { hintFromLabel, slugFromTitle, watchReference } from '../_auction-lib/categories.js'; | |
| 6 | + | |
| 7 | +const connector = createConnector(getConnectorMeta('bonhams')); | |
| 8 | + | |
| 9 | +describe('bonhams connector', () => { | |
| 10 | + runFixtureSuite(connector, it, expect); | |
| 11 | + | |
| 12 | + it('stores the premium-inclusive price and keeps the hammer', async () => { | |
| 13 | + const fx = loadFixture('bonhams', 'results-1'); | |
| 14 | + const payload = fx.raw.payload as PagePayload; | |
| 15 | + const out = await connector.normalize(fx.raw); | |
| 16 | + const sold = payload.lots.filter((l) => l.status === 'SOLD' && (l.hammerPremium ?? 0) > 0); | |
| 17 | + expect(out.length).toBe(sold.length); | |
| 18 | + const lot = sold[0]!; | |
| 19 | + const rec = out.find((r) => r.kind === 'sale' && r.externalId === `${payload.auction.id}-${lot.lotNo}`); | |
| 20 | + expect(rec && rec.kind === 'sale').toBe(true); | |
| 21 | + if (!rec || rec.kind !== 'sale') return; | |
| 22 | + expect(rec.price).toBe(lot.hammerPremium); | |
| 23 | + expect(rec.buyerPremiumIncluded).toBe(true); | |
| 24 | + expect(rec.attributes.metadata.hammer_price).toBe(lot.hammerPrice); | |
| 25 | + expect(rec.currency).toBe(lot.currency); | |
| 26 | + expect(rec.saleDate.toISOString()).toBe(new Date(lot.hammerTime!).toISOString()); | |
| 27 | + expect(rec.auctionHouse).toBe('Bonhams'); | |
| 28 | + expect(rec.lotNumber).toBe(lot.lotNo); | |
| 29 | + expect(rec.sourceUrl).toBe(lotUrl(payload.auction.id, lot.lotNo, lot.slug)); | |
| 30 | + expect(['rolex', 'patek_philippe', 'audemars_piguet', 'omega', 'other_watches']).toContain(rec.attributes.categorySlug); | |
| 31 | + }); | |
| 32 | + | |
| 33 | + it('emits auction_lot records for lots that have not ended', async () => { | |
| 34 | + const fx = loadFixture('bonhams', 'results-1'); | |
| 35 | + const payload = structuredClone(fx.raw.payload) as PagePayload; | |
| 36 | + const future = new Date(Date.now() + 5 * 86_400_000).toISOString(); | |
| 37 | + payload.auction = { ...payload.auction, isEnded: false, end: future, start: new Date(Date.now() - 86_400_000).toISOString() }; | |
| 38 | + payload.lots = payload.lots.slice(0, 3).map((l) => ({ ...l, status: 'READY', hammerPrice: null, hammerPremium: null, isEnded: false, hammerTime: future, endDate: future })); | |
| 39 | + const out = await connector.normalize({ ...fx.raw, payload }); | |
| 40 | + expect(out.length).toBe(3); | |
| 41 | + for (const r of out) { | |
| 42 | + expect(r.kind).toBe('auction_lot'); | |
| 43 | + if (r.kind !== 'auction_lot') continue; | |
| 44 | + expect(r.status).toBe('live'); | |
| 45 | + expect(r.estimateLow).not.toBeNull(); | |
| 46 | + expect(r.endsAt?.toISOString()).toBe(new Date(future).toISOString()); | |
| 47 | + } | |
| 48 | + }); | |
| 49 | + | |
| 50 | + it('skips unsold, withdrawn and unmapped-department lots', async () => { | |
| 51 | + const fx = loadFixture('bonhams', 'results-1'); | |
| 52 | + const payload = structuredClone(fx.raw.payload) as PagePayload; | |
| 53 | + payload.lots = [ | |
| 54 | + { ...payload.lots[0]!, status: 'UNSOLD', hammerPrice: null, hammerPremium: null }, | |
| 55 | + { ...payload.lots[1]!, status: 'WITHDRAWN' }, | |
| 56 | + { ...payload.lots[2]!, department: 'Carpets, Rugs & Tapestries', title: 'A Persian rug' }, | |
| 57 | + payload.lots[3]!, | |
| 58 | + ]; | |
| 59 | + payload.auction = { ...payload.auction, departments: ['Watches'] }; | |
| 60 | + const out = await connector.normalize({ ...fx.raw, payload }); | |
| 61 | + expect(out.map((r) => ('externalId' in r ? r.externalId : null))).toEqual([`${payload.auction.id}-${payload.lots[3]!.lotNo}`]); | |
| 62 | + }); | |
| 63 | + | |
| 64 | + it('parses listing and auction pages defensively', () => { | |
| 65 | + expect(parseAuctionList('<html></html>')).toEqual({ auctions: [], nbHits: null }); | |
| 66 | + expect(parseAuctionPage('<html></html>')).toBeNull(); | |
| 67 | + expect(auctionPageUrl({ id: '31992', slug: 'weekly-watches' }, 2)).toBe('https://www.bonhams.com/auction/31992/weekly-watches/?page=2'); | |
| 68 | + }); | |
| 69 | + | |
| 70 | + it('maps departments and titles to taxonomy slugs', () => { | |
| 71 | + expect(slugFromTitle('ROLEX. A STAINLESS STEEL AUTOMATIC CHRONOGRAPH WRISTWATCH REF 116500LN DAYTONA', hintFromLabel('Watches'))).toBe('rolex'); | |
| 72 | + expect(watchReference('REF 116500LN DAYTONA')).toBe('116500LN'); | |
| 73 | + expect(slugFromTitle('Château Lafite Rothschild 1982 (12 bottles)', hintFromLabel('Wine'))).toBe('wine'); | |
| 74 | + expect(slugFromTitle('The Macallan 25 Year Old Sherry Oak', hintFromLabel('Whisky'))).toBe('whisky'); | |
| 75 | + expect(slugFromTitle('1965 Ferrari 275 GTB Berlinetta Chassis no. 07589', hintFromLabel('Cars'))).toBe('automobiles'); | |
| 76 | + expect(slugFromTitle('Hermès Birkin 30 Togo leather 2019', hintFromLabel('Designer Handbags & Fashion'))).toBe('luxury_handbags'); | |
| 77 | + expect(slugFromTitle('A Gibson Les Paul Standard owned by ...', hintFromLabel('Popular Culture'))).toBe('musical_instruments'); | |
| 78 | + expect(slugFromTitle('Star Wars 1977 original one-sheet poster', hintFromLabel('Popular Culture'))).toBe('movie_posters'); | |
| 79 | + expect(slugFromTitle('Elizabeth II gold sovereign 1958', hintFromLabel('Coins, Medals and Banknotes'))).toBe('coins'); | |
| 80 | + expect(slugFromTitle('Bank of England £5 banknote 1935', hintFromLabel('Coins, Medals and Banknotes'))).toBe('banknotes'); | |
| 81 | + expect(slugFromTitle('A large ammonite fossil, Madagascar', hintFromLabel('Natural History'))).toBe('fossils'); | |
| 82 | + expect(slugFromTitle('Untitled, acrylic on canvas', hintFromLabel('Post-War and Contemporary Art'))).toBe('contemporary_art'); | |
| 83 | + }); | |
| 84 | +}); | |
added
connectors/api/bonhams/index.ts
+418 −0
@@ -0,0 +1,418 @@ | ||
| 1 | +import { z } from 'zod'; | |
| 2 | +import { BaseConnector, type ConnectorMeta, type CrawlContext, type RawRecordInput, type RawRecordLike } from '@rareindex/connectors'; | |
| 3 | +import { NormalizedAuctionLotSchema, NormalizedSaleSchema, type NormalizedRecord, type CurrencyCode, SUPPORTED_CURRENCIES } from '@rareindex/shared'; | |
| 4 | +import { parseGradeFromTitle } from '@rareindex/taxonomy'; | |
| 5 | +import { brandFromSlug, hintFromLabel, isBundleTitle, legoSetNumber, safeYear, slugFromTitle, watchReference } from '../_auction-lib/categories.js'; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * Bonhams — realized prices + upcoming lots from the public, server-rendered Next.js pages. | |
| 9 | + * Engine: plain HTTPS (no credits). See meta.json accessNotes. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +const SITE = 'https://www.bonhams.com'; | |
| 13 | + | |
| 14 | +export const AuctionSummarySchema = z.object({ | |
| 15 | + id: z.string(), | |
| 16 | + title: z.string(), | |
| 17 | + slug: z.string(), | |
| 18 | + status: z.string().nullable(), | |
| 19 | + type: z.string().nullable(), | |
| 20 | + departments: z.array(z.string()), | |
| 21 | + categories: z.array(z.string()), | |
| 22 | + currency: z.string().nullable(), | |
| 23 | + country: z.string().nullable(), | |
| 24 | + venue: z.string().nullable(), | |
| 25 | + start: z.string().nullable(), | |
| 26 | + end: z.string().nullable(), | |
| 27 | + isEnded: z.boolean(), | |
| 28 | + numberOfLots: z.number().nullable(), | |
| 29 | +}); | |
| 30 | +export type AuctionSummary = z.infer<typeof AuctionSummarySchema>; | |
| 31 | + | |
| 32 | +export const LotSchema = z.object({ | |
| 33 | + lotId: z.string(), | |
| 34 | + lotUniqueId: z.string().nullable(), | |
| 35 | + lotNo: z.string(), | |
| 36 | + title: z.string(), | |
| 37 | + heading: z.string().nullable(), | |
| 38 | + slug: z.string().nullable(), | |
| 39 | + imageUrl: z.string().nullable(), | |
| 40 | + estimateLow: z.number().nullable(), | |
| 41 | + estimateHigh: z.number().nullable(), | |
| 42 | + hammerPrice: z.number().nullable(), | |
| 43 | + hammerPremium: z.number().nullable(), | |
| 44 | + startingBid: z.number().nullable(), | |
| 45 | + currency: z.string().nullable(), | |
| 46 | + status: z.string().nullable(), | |
| 47 | + hammerTime: z.string().nullable(), | |
| 48 | + endDate: z.string().nullable(), | |
| 49 | + department: z.string().nullable(), | |
| 50 | + categories: z.array(z.string()), | |
| 51 | + isEnded: z.boolean(), | |
| 52 | + isWithoutReserve: z.boolean().nullable(), | |
| 53 | +}); | |
| 54 | +export type Lot = z.infer<typeof LotSchema>; | |
| 55 | + | |
| 56 | +export const PagePayloadSchema = z.object({ | |
| 57 | + kind: z.literal('auction_lots'), | |
| 58 | + auction: AuctionSummarySchema, | |
| 59 | + page: z.number().int(), | |
| 60 | + nbHits: z.number().nullable(), | |
| 61 | + lots: z.array(LotSchema), | |
| 62 | +}); | |
| 63 | +export type PagePayload = z.infer<typeof PagePayloadSchema>; | |
| 64 | + | |
| 65 | +const ConfigSchema = z.object({ | |
| 66 | + departments: z.array(z.string()).default([]), | |
| 67 | + maxResultsPages: z.number().int().min(1).default(20), | |
| 68 | + maxAuctionsPerRun: z.number().int().min(1).default(40), | |
| 69 | + upcomingAuctionsPerRun: z.number().int().min(0).default(12), | |
| 70 | + lotsPerPage: z.number().int().default(48), | |
| 71 | +}); | |
| 72 | + | |
| 73 | +type NextData = { props?: { pageProps?: Record<string, unknown> } }; | |
| 74 | + | |
| 75 | +export function extractNextData(html: string): NextData | null { | |
| 76 | + const m = html.match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/); | |
| 77 | + if (!m) return null; | |
| 78 | + try { | |
| 79 | + return JSON.parse(m[1]!) as NextData; | |
| 80 | + } catch { | |
| 81 | + return null; | |
| 82 | + } | |
| 83 | +} | |
| 84 | + | |
| 85 | +function str(v: unknown): string | null { | |
| 86 | + return typeof v === 'string' && v.length ? v : v === null || v === undefined ? null : typeof v === 'number' ? String(v) : null; | |
| 87 | +} | |
| 88 | +function numOrNull(v: unknown): number | null { | |
| 89 | + return typeof v === 'number' && Number.isFinite(v) ? v : null; | |
| 90 | +} | |
| 91 | + | |
| 92 | +/** Summaries from a results/upcoming listing page (pagesOfAuctions) or from an auction page (auction + lots). */ | |
| 93 | +export function parseAuctionList(html: string): { auctions: AuctionSummary[]; nbHits: number | null } { | |
| 94 | + const nd = extractNextData(html); | |
| 95 | + const pp = nd?.props?.pageProps ?? {}; | |
| 96 | + const pages = (pp.pagesOfAuctions as unknown[][] | undefined) ?? []; | |
| 97 | + const auctions: AuctionSummary[] = []; | |
| 98 | + for (const page of pages) { | |
| 99 | + for (const a of page as Array<Record<string, any>>) { | |
| 100 | + const dates = a.dates ?? {}; | |
| 101 | + auctions.push( | |
| 102 | + AuctionSummarySchema.parse({ | |
| 103 | + id: String(a.id), | |
| 104 | + title: a.auctionTitle ?? a.auctionHeading ?? '', | |
| 105 | + slug: a.slug ?? '', | |
| 106 | + status: str(a.auctionStatus), | |
| 107 | + type: str(a.auctionType), | |
| 108 | + departments: ((a.departments as Array<{ name?: string }> | undefined) ?? []).map((d) => d.name ?? '').filter(Boolean), | |
| 109 | + categories: ((a.categories as Array<{ name?: string }> | undefined) ?? []).map((d) => d.name ?? '').filter(Boolean), | |
| 110 | + currency: str(a.currency?.iso_code), | |
| 111 | + country: str(a.country?.code), | |
| 112 | + venue: str(a.venue ?? a.location?.name), | |
| 113 | + start: str(dates.start?.datetime), | |
| 114 | + end: str(dates.end?.datetime ?? a.hammerTime?.datetime), | |
| 115 | + isEnded: Boolean(a.flags?.isAuctionEnded), | |
| 116 | + numberOfLots: numOrNull(a.numberOfLots ?? a.number_of_lots), | |
| 117 | + }), | |
| 118 | + ); | |
| 119 | + } | |
| 120 | + } | |
| 121 | + return { auctions, nbHits: numOrNull(pp.nbHits) }; | |
| 122 | +} | |
| 123 | + | |
| 124 | +/** Lots + auction metadata from an auction page (or its _next/data JSON pageProps). */ | |
| 125 | +export function parseAuctionPage(html: string, fallback?: Partial<AuctionSummary>): { auction: AuctionSummary; lots: Lot[]; nbHits: number | null } | null { | |
| 126 | + const nd = extractNextData(html); | |
| 127 | + const pp = nd?.props?.pageProps as Record<string, any> | undefined; | |
| 128 | + if (!pp?.lotData) return null; | |
| 129 | + const a = pp.auction ?? {}; | |
| 130 | + const rawLots = (pp.lotData.auctionLots as Array<Record<string, any>> | undefined) ?? []; | |
| 131 | + const first = rawLots[0]; | |
| 132 | + const auction = AuctionSummarySchema.parse({ | |
| 133 | + id: String(first?.auctionId ?? fallback?.id ?? a.iSaleNo ?? ''), | |
| 134 | + title: a.sSaleName ?? fallback?.title ?? '', | |
| 135 | + slug: a.slug ?? fallback?.slug ?? '', | |
| 136 | + status: str(first?.auctionStatus) ?? fallback?.status ?? null, | |
| 137 | + type: str(first?.auctionType) ?? str(a.sSaleType) ?? fallback?.type ?? null, | |
| 138 | + departments: ((a.departments as Array<{ sDepartmentName?: string }> | undefined) ?? []).map((d) => d.sDepartmentName ?? '').filter(Boolean), | |
| 139 | + categories: fallback?.categories ?? [], | |
| 140 | + currency: str(first?.currency?.iso_code) ?? fallback?.currency ?? null, | |
| 141 | + country: str(first?.country?.code) ?? fallback?.country ?? null, | |
| 142 | + venue: str(a.sVenue) ?? fallback?.venue ?? null, | |
| 143 | + start: str(a.dates?.start?.[0]?.date?.datetime) ?? fallback?.start ?? null, | |
| 144 | + end: str(a.dates?.end?.datetime) ?? str(first?.auctionEndDate?.datetime) ?? fallback?.end ?? null, | |
| 145 | + isEnded: Boolean(first?.flags?.isAuctionEnded ?? fallback?.isEnded ?? false), | |
| 146 | + numberOfLots: numOrNull(a.number_of_lots) ?? fallback?.numberOfLots ?? null, | |
| 147 | + }); | |
| 148 | + const lots: Lot[] = rawLots.map((l) => | |
| 149 | + LotSchema.parse({ | |
| 150 | + lotId: String(l.lotId ?? l.id ?? ''), | |
| 151 | + lotUniqueId: str(l.lotUniqueId), | |
| 152 | + lotNo: String(l.lotNo?.full ?? l.lotNo?.number ?? l.lotId ?? ''), | |
| 153 | + title: String(l.title ?? l.image?.caption ?? '').replace(/\s+/g, ' ').trim(), | |
| 154 | + heading: str(l.heading) || null, | |
| 155 | + slug: str(l.slug), | |
| 156 | + imageUrl: str(l.image?.url), | |
| 157 | + estimateLow: numOrNull(l.price?.estimateLow), | |
| 158 | + estimateHigh: numOrNull(l.price?.estimateHigh), | |
| 159 | + hammerPrice: numOrNull(l.price?.hammerPrice), | |
| 160 | + hammerPremium: numOrNull(l.price?.hammerPremium), | |
| 161 | + startingBid: numOrNull(l.price?.startingBidAmount), | |
| 162 | + currency: str(l.currency?.iso_code), | |
| 163 | + status: str(l.status), | |
| 164 | + hammerTime: str(l.hammerTime?.datetime), | |
| 165 | + endDate: str(l.auctionEndDate?.datetime), | |
| 166 | + department: str(l.department?.name), | |
| 167 | + categories: ((l.categories as Array<{ name?: string }> | undefined) ?? []).map((c) => c.name ?? '').filter(Boolean), | |
| 168 | + isEnded: Boolean(l.flags?.isAuctionEnded), | |
| 169 | + isWithoutReserve: typeof l.flags?.isWithoutReserve === 'boolean' ? l.flags.isWithoutReserve : null, | |
| 170 | + }), | |
| 171 | + ); | |
| 172 | + return { auction, lots, nbHits: numOrNull(pp.lotData.nbHits) }; | |
| 173 | +} | |
| 174 | + | |
| 175 | +export function lotUrl(auctionId: string, lotNo: string, slug: string | null): string { | |
| 176 | + return `${SITE}/auction/${auctionId}/lot/${lotNo}/${slug ? `${slug}/` : ''}`; | |
| 177 | +} | |
| 178 | +export function auctionPageUrl(a: { id: string; slug: string }, page: number): string { | |
| 179 | + return `${SITE}/auction/${a.id}/${a.slug}/${page > 1 ? `?page=${page}` : ''}`; | |
| 180 | +} | |
| 181 | + | |
| 182 | +function currency(code: string | null | undefined): CurrencyCode | null { | |
| 183 | + return code && (SUPPORTED_CURRENCIES as readonly string[]).includes(code) ? (code as CurrencyCode) : null; | |
| 184 | +} | |
| 185 | + | |
| 186 | +function parseDate(s: string | null | undefined): Date | null { | |
| 187 | + if (!s) return null; | |
| 188 | + const d = new Date(s); | |
| 189 | + return Number.isNaN(d.getTime()) ? null : d; | |
| 190 | +} | |
| 191 | + | |
| 192 | +export default function createConnector(meta: ConnectorMeta) { | |
| 193 | + return new BonhamsConnector(meta); | |
| 194 | +} | |
| 195 | + | |
| 196 | +export class BonhamsConnector extends BaseConnector { | |
| 197 | + readonly version = '1.0.0'; | |
| 198 | + readonly parserVersion = '1.0.0'; | |
| 199 | + override readonly urlPatterns = [/^https?:\/\/(www\.)?bonhams\.com\/auction\/\d+\//i]; | |
| 200 | + protected override minIntervalMs = 1500; | |
| 201 | + private readonly config = ConfigSchema.parse(this.meta.config ?? {}); | |
| 202 | + | |
| 203 | + private wanted(a: AuctionSummary): boolean { | |
| 204 | + if (!this.config.departments.length) return true; | |
| 205 | + return a.departments.some((d) => this.config.departments.includes(d)); | |
| 206 | + } | |
| 207 | + | |
| 208 | + private async page(ctx: CrawlContext, url: string): Promise<string | null> { | |
| 209 | + await this.throttle(); | |
| 210 | + const res = await ctx.fetch(url, { engines: ['api'], responseType: 'text', minQuality: 0, headers: { accept: 'text/html' } }); | |
| 211 | + if (!res.success || !res.html) { | |
| 212 | + ctx.anomaly('page_fetch_failed', `${url}: ${res.error ?? res.httpStatus}`); | |
| 213 | + return null; | |
| 214 | + } | |
| 215 | + return res.html; | |
| 216 | + } | |
| 217 | + | |
| 218 | + /** Iterate listing pages (results or upcoming) yielding whitelisted auctions until `stop` says so. */ | |
| 219 | + private async *listAuctions(ctx: CrawlContext, path: string, maxPages: number, stop: (a: AuctionSummary) => boolean): AsyncIterable<AuctionSummary> { | |
| 220 | + for (let page = 1; page <= maxPages; page++) { | |
| 221 | + const html = await this.page(ctx, `${SITE}${path}${page > 1 ? `?page=${page}` : ''}`); | |
| 222 | + if (!html) return; | |
| 223 | + const { auctions } = parseAuctionList(html); | |
| 224 | + if (!auctions.length) { | |
| 225 | + if (page === 1) ctx.anomaly('empty_page', `${path}: no auctions parsed (redesign?)`); | |
| 226 | + return; | |
| 227 | + } | |
| 228 | + for (const a of auctions) { | |
| 229 | + if (stop(a)) return; | |
| 230 | + if (this.wanted(a)) yield a; | |
| 231 | + } | |
| 232 | + } | |
| 233 | + } | |
| 234 | + | |
| 235 | + private async *crawlAuction(ctx: CrawlContext, a: AuctionSummary, kind: 'sale' | 'auction_lot', maxPages = 60): AsyncIterable<RawRecordInput> { | |
| 236 | + for (let page = 1; page <= maxPages; page++) { | |
| 237 | + const url = auctionPageUrl(a, page); | |
| 238 | + const html = await this.page(ctx, url); | |
| 239 | + if (!html) return; | |
| 240 | + const parsed = parseAuctionPage(html, a); | |
| 241 | + if (!parsed) { | |
| 242 | + ctx.anomaly('parse_failure', `${url}: no lotData in __NEXT_DATA__`); | |
| 243 | + return; | |
| 244 | + } | |
| 245 | + if (!parsed.lots.length) return; | |
| 246 | + const payload: PagePayload = { kind: 'auction_lots', auction: { ...parsed.auction, categories: a.categories }, page, nbHits: parsed.nbHits, lots: parsed.lots }; | |
| 247 | + yield { url, externalId: `${a.id}#${page}`, kind, engine: 'api', httpStatus: 200, payload, fetchedAt: new Date() }; | |
| 248 | + if (parsed.nbHits !== null && page * this.config.lotsPerPage >= parsed.nbHits) return; | |
| 249 | + if (ctx.signal?.aborted) return; | |
| 250 | + } | |
| 251 | + } | |
| 252 | + | |
| 253 | + async *crawl(ctx: CrawlContext): AsyncIterable<RawRecordInput> { | |
| 254 | + const cursor = { ...(ctx.options.cursor ?? {}) } as { lastEnd?: string; done?: string[] }; | |
| 255 | + const done = new Set(cursor.done ?? []); | |
| 256 | + const probe = ctx.options.mode === 'probe'; | |
| 257 | + const backfill = ctx.options.mode === 'backfill'; | |
| 258 | + const maxAuctions = probe ? 1 : this.config.maxAuctionsPerRun; | |
| 259 | + let yielded = 0; | |
| 260 | + let newestEnd: string | undefined = cursor.lastEnd; | |
| 261 | + let count = 0; | |
| 262 | + | |
| 263 | + // 1. Past results (sold) | |
| 264 | + const stop = (a: AuctionSummary) => !backfill && !!cursor.lastEnd && !!a.end && a.end < cursor.lastEnd && !probe; | |
| 265 | + for await (const a of this.listAuctions(ctx, '/auctions/results/', probe ? 1 : this.config.maxResultsPages, stop)) { | |
| 266 | + if (done.has(a.id)) continue; | |
| 267 | + if (count >= maxAuctions) break; | |
| 268 | + count++; | |
| 269 | + for await (const raw of this.crawlAuction(ctx, a, 'sale', probe ? 1 : 60)) { | |
| 270 | + yield raw; | |
| 271 | + yielded += (raw.payload as PagePayload).lots.length; | |
| 272 | + if (this.reached(ctx, yielded)) return; | |
| 273 | + } | |
| 274 | + done.add(a.id); | |
| 275 | + if (a.end && (!newestEnd || a.end > newestEnd)) newestEnd = a.end; | |
| 276 | + cursor.done = [...done].slice(-500); | |
| 277 | + if (!backfill) cursor.lastEnd = newestEnd; | |
| 278 | + await ctx.setCursor(cursor); | |
| 279 | + } | |
| 280 | + | |
| 281 | + // 2. Upcoming / live lots for the auction calendar (incremental runs only) | |
| 282 | + if (!probe && !backfill && this.config.upcomingAuctionsPerRun > 0) { | |
| 283 | + let up = 0; | |
| 284 | + for await (const a of this.listAuctions(ctx, '/auctions/upcoming/', 3, () => false)) { | |
| 285 | + if (a.type === 'EXHIBITION') continue; | |
| 286 | + if (up++ >= this.config.upcomingAuctionsPerRun) break; | |
| 287 | + for await (const raw of this.crawlAuction(ctx, a, 'auction_lot', 10)) yield raw; | |
| 288 | + } | |
| 289 | + } | |
| 290 | + } | |
| 291 | + | |
| 292 | + async lookup(url: string, ctx: CrawlContext): Promise<RawRecordInput[]> { | |
| 293 | + const m = url.match(/\/auction\/(\d+)\/(?:lot\/(\d+[A-Za-z]?)\/)?([^/?#]*)/); | |
| 294 | + if (!m) return []; | |
| 295 | + const auctionId = m[1]!; | |
| 296 | + const lotNo = m[2]; | |
| 297 | + // The auction page lists lots 48 at a time; find the page containing the lot number when given. | |
| 298 | + const first = await this.page(ctx, `${SITE}/auction/${auctionId}/`); | |
| 299 | + if (!first) return []; | |
| 300 | + const parsed = parseAuctionPage(first); | |
| 301 | + if (!parsed) return []; | |
| 302 | + let lots = parsed.lots; | |
| 303 | + if (lotNo && !lots.some((l) => l.lotNo === lotNo) && parsed.nbHits) { | |
| 304 | + const pages = Math.ceil(parsed.nbHits / this.config.lotsPerPage); | |
| 305 | + for (let p = 2; p <= pages; p++) { | |
| 306 | + const html = await this.page(ctx, auctionPageUrl({ id: auctionId, slug: parsed.auction.slug }, p)); | |
| 307 | + const pg = html ? parseAuctionPage(html, parsed.auction) : null; | |
| 308 | + if (pg?.lots.some((l) => l.lotNo === lotNo)) { | |
| 309 | + lots = pg.lots; | |
| 310 | + break; | |
| 311 | + } | |
| 312 | + } | |
| 313 | + } | |
| 314 | + if (lotNo) lots = lots.filter((l) => l.lotNo === lotNo); | |
| 315 | + const payload: PagePayload = { kind: 'auction_lots', auction: parsed.auction, page: 0, nbHits: parsed.nbHits, lots }; | |
| 316 | + return [{ url, externalId: lotNo ? `${auctionId}-${lotNo}` : auctionId, kind: parsed.auction.isEnded ? 'sale' : 'auction_lot', engine: 'api', httpStatus: 200, payload, fetchedAt: new Date() }]; | |
| 317 | + } | |
| 318 | + | |
| 319 | + async normalize(raw: RawRecordLike): Promise<NormalizedRecord[]> { | |
| 320 | + const page = PagePayloadSchema.parse(raw.payload); | |
| 321 | + const out: NormalizedRecord[] = []; | |
| 322 | + const a = page.auction; | |
| 323 | + const observedAt = raw.fetchedAt; | |
| 324 | + for (const lot of page.lots) { | |
| 325 | + const dept = lot.department ?? a.departments[0] ?? null; | |
| 326 | + // A lot's own department is authoritative; fall back to the sale's departments when the lot has none. | |
| 327 | + if (this.config.departments.length && (dept ? !this.config.departments.includes(dept) : !a.departments.some((d) => this.config.departments.includes(d)))) continue; | |
| 328 | + const hint = hintFromLabel(dept); | |
| 329 | + const categorySlug = slugFromTitle(lot.title, hint); | |
| 330 | + if (!categorySlug) continue; // unmapped department/title → skip rather than guess | |
| 331 | + const cur = currency(lot.currency ?? a.currency); | |
| 332 | + if (!cur) continue; | |
| 333 | + const grade = parseGradeFromTitle(lot.title); | |
| 334 | + const brand = brandFromSlug(categorySlug, lot.title); | |
| 335 | + const reference = categorySlug.endsWith('watches') || ['rolex', 'patek_philippe', 'audemars_piguet', 'omega'].includes(categorySlug) ? watchReference(lot.title) : null; | |
| 336 | + const identifiers: Record<string, string> = { bonhams_lot: `${a.id}-${lot.lotNo}` }; | |
| 337 | + if (lot.lotUniqueId) identifiers.bonhams_lot_unique_id = lot.lotUniqueId; | |
| 338 | + if (reference) identifiers.reference = reference; | |
| 339 | + if (categorySlug === 'lego_sets') { | |
| 340 | + const n = legoSetNumber(lot.title); | |
| 341 | + if (n) identifiers.lego_set_number = n; | |
| 342 | + } | |
| 343 | + const base = { | |
| 344 | + connectorId: this.meta.id, | |
| 345 | + sourceId: this.meta.sourceId, | |
| 346 | + sourceUrl: lotUrl(a.id, lot.lotNo, lot.slug), | |
| 347 | + externalId: `${a.id}-${lot.lotNo}`, | |
| 348 | + rawTitle: lot.title, | |
| 349 | + description: lot.heading, | |
| 350 | + imageUrls: lot.imageUrl ? [lot.imageUrl] : [], | |
| 351 | + attributes: { | |
| 352 | + categorySlug, | |
| 353 | + name: lot.title, | |
| 354 | + brand, | |
| 355 | + reference, | |
| 356 | + year: safeYear(lot.title), | |
| 357 | + country: a.country, | |
| 358 | + identifiers, | |
| 359 | + metadata: { department: dept, auction_id: a.id, auction_title: a.title, auction_type: a.type, venue: a.venue, estimate_low: lot.estimateLow, estimate_high: lot.estimateHigh, hammer_price: lot.hammerPrice, without_reserve: lot.isWithoutReserve }, | |
| 360 | + }, | |
| 361 | + grade: { grader: grade.grader, grade: grade.grade, qualifier: grade.qualifier, certificationNumber: null }, | |
| 362 | + condition: {}, | |
| 363 | + observedAt, | |
| 364 | + parserVersion: this.parserVersion, | |
| 365 | + }; | |
| 366 | + const saleDate = parseDate(lot.hammerTime ?? lot.endDate ?? a.end); | |
| 367 | + const sold = lot.status === 'SOLD' && (lot.hammerPremium ?? lot.hammerPrice ?? 0) > 0; | |
| 368 | + const endDate = parseDate(lot.endDate ?? a.end); | |
| 369 | + const ended = sold || lot.isEnded || a.isEnded || lot.status === 'UNSOLD' || lot.status === 'WITHDRAWN' || (endDate !== null && endDate.getTime() < Date.now()); | |
| 370 | + if (ended) { | |
| 371 | + // Only published results (status SOLD with a price) become sales; unsold/withdrawn lots are skipped. | |
| 372 | + if (!sold || !saleDate || saleDate.getTime() > Date.now() + 86_400_000) continue; | |
| 373 | + const price = lot.hammerPremium ?? lot.hammerPrice!; | |
| 374 | + out.push( | |
| 375 | + NormalizedSaleSchema.parse({ | |
| 376 | + ...base, | |
| 377 | + kind: 'sale', | |
| 378 | + confidence: 0.9, | |
| 379 | + saleType: 'auction', | |
| 380 | + saleDate, | |
| 381 | + price, | |
| 382 | + currency: cur, | |
| 383 | + buyerPremiumIncluded: lot.hammerPremium !== null, | |
| 384 | + quantity: 1, | |
| 385 | + isBundle: isBundleTitle(lot.title), | |
| 386 | + location: a.venue ?? a.country, | |
| 387 | + auctionHouse: 'Bonhams', | |
| 388 | + lotNumber: lot.lotNo, | |
| 389 | + }), | |
| 390 | + ); | |
| 391 | + } else { | |
| 392 | + const endsAt = parseDate(lot.endDate ?? a.end); | |
| 393 | + const startsAt = parseDate(a.start); | |
| 394 | + const now = Date.now(); | |
| 395 | + const status = startsAt && startsAt.getTime() <= now ? 'live' : 'upcoming'; | |
| 396 | + out.push( | |
| 397 | + NormalizedAuctionLotSchema.parse({ | |
| 398 | + ...base, | |
| 399 | + kind: 'auction_lot', | |
| 400 | + confidence: 0.85, | |
| 401 | + auctionHouse: 'Bonhams', | |
| 402 | + auctionName: a.title, | |
| 403 | + lotNumber: lot.lotNo, | |
| 404 | + startsAt, | |
| 405 | + endsAt, | |
| 406 | + estimateLow: lot.estimateLow, | |
| 407 | + estimateHigh: lot.estimateHigh, | |
| 408 | + currentBid: null, | |
| 409 | + currency: cur, | |
| 410 | + status, | |
| 411 | + location: a.venue ?? a.country, | |
| 412 | + }), | |
| 413 | + ); | |
| 414 | + } | |
| 415 | + } | |
| 416 | + return out; | |
| 417 | + } | |
| 418 | +} | |
added
connectors/api/bonhams/meta.json
+36 −0
@@ -0,0 +1,36 @@ | ||
| 1 | +{ | |
| 2 | + "id": "bonhams", | |
| 3 | + "displayName": "Bonhams (auction results & upcoming lots)", | |
| 4 | + "sourceId": "bonhams", | |
| 5 | + "sourceName": "Bonhams", | |
| 6 | + "sourceType": "auction_house", | |
| 7 | + "sourceUrl": "https://www.bonhams.com", | |
| 8 | + "module": "api/bonhams", | |
| 9 | + "enginePriority": ["api"], | |
| 10 | + "categories": ["rolex", "patek_philippe", "audemars_piguet", "omega", "other_watches", "wine", "whisky", "coins", "banknotes", "medals", "automobiles", "motorcycles", "automotive_memorabilia", "luxury_handbags", "fashion_streetwear", "jewelry", "movie_memorabilia", "music_memorabilia", "musical_instruments", "movie_posters", "vintage_toys", "sports_memorabilia", "books", "maps", "photography", "art", "contemporary_art", "clocks", "silver", "glass_crystal", "porcelain", "scientific_instruments", "stamps", "fossils", "minerals", "meteorites", "militaria", "design_furniture", "antiques"], | |
| 11 | + "regions": ["GB", "US", "HK", "FR", "AU"], | |
| 12 | + "languages": ["en"], | |
| 13 | + "currency": ["GBP", "USD", "HKD", "EUR", "AUD", "CHF"], | |
| 14 | + "supportsListings": false, | |
| 15 | + "supportsSold": true, | |
| 16 | + "supportsAuctions": true, | |
| 17 | + "supportsImages": true, | |
| 18 | + "supportsCatalog": false, | |
| 19 | + "supportsPopulation": false, | |
| 20 | + "supportsLookup": true, | |
| 21 | + "refreshFrequencyMinutes": 360, | |
| 22 | + "priority": "high", | |
| 23 | + "trustScore": 0.9, | |
| 24 | + "attributionRequired": true, | |
| 25 | + "termsUrl": "https://www.bonhams.com/legals/terms-of-use/", | |
| 26 | + "accessNotes": "Plain HTTPS (no rendering, no credits). Public results listing https://www.bonhams.com/auctions/results/?page=N and upcoming listing /auctions/upcoming/ are server-rendered Next.js pages whose __NEXT_DATA__ carries 24 auctions per page (11k+ past auctions); each auction page /auction/<id>/<slug>/?page=N carries 48 lots per page with estimates, hammer price, price including buyer's premium (hammerPremium), status, currency, department and end date. bonhams.com/robots.txt only disallows /ldc/, /vms-assets/, */aggregate$ and */head_image* — none used. Prices: we store hammerPremium (hammer + buyer's premium as published by Bonhams) as the sale price with buyerPremiumIncluded=true and keep the hammer price in metadata. Sale date = the lot's hammerTime / auction end date from the source. Departments outside the configured whitelist are skipped, not guessed.", | |
| 27 | + "enabled": true, | |
| 28 | + "schemaVersion": "1.0", | |
| 29 | + "config": { | |
| 30 | + "departments": ["Watches", "Wine", "Whisky", "Coins, Medals and Banknotes", "Cars", "Motorcycles", "Automobilia", "Designer Handbags & Fashion", "Jewellery", "Popular Culture", "Sporting Memorabilia", "Books & Manuscripts", "Photographs", "Prints & Multiples", "Post-War and Contemporary Art", "Clocks", "Silver", "Glass", "Scientific Instruments", "Stamps, Covers & Postal History", "Natural History", "Arms and Armour", "Modern Decorative Art & Design", "Impressionist and Modern Art", "Modern British & Irish Art", "European Ceramics", "British Ceramics", "Travel & Exploration", "Home and Interiors"], | |
| 31 | + "maxResultsPages": 20, | |
| 32 | + "maxAuctionsPerRun": 40, | |
| 33 | + "upcomingAuctionsPerRun": 12, | |
| 34 | + "lotsPerPage": 48 | |
| 35 | + } | |
| 36 | +} | |
added
connectors/api/christies/index.test.ts
+75 −0
@@ -0,0 +1,75 @@ | ||
| 1 | +import { describe, expect, it } from 'vitest'; | |
| 2 | +import { getConnectorMeta } from '@rareindex/connectors'; | |
| 3 | +import { loadFixture, runFixtureSuite } from '@rareindex/connectors/testing'; | |
| 4 | +import createConnector, { currencyFromText, hintForSale, lotSearchUrl, parseLotSearch, parseResultsMonth, resultsUrl, type PagePayload } from './index.js'; | |
| 5 | + | |
| 6 | +const connector = createConnector(getConnectorMeta('christies')); | |
| 7 | + | |
| 8 | +describe('christies connector', () => { | |
| 9 | + runFixtureSuite(connector, it, expect); | |
| 10 | + | |
| 11 | + it('emits one premium-inclusive sale per realised lot, with the source currency and date', async () => { | |
| 12 | + const fx = loadFixture('christies', 'results-1'); | |
| 13 | + const payload = fx.raw.payload as PagePayload; | |
| 14 | + const out = await connector.normalize(fx.raw); | |
| 15 | + const realised = payload.lots.filter((l) => !l.withdrawn && (l.priceRealised ?? 0) > 0); | |
| 16 | + expect(out.length).toBeGreaterThan(0); | |
| 17 | + expect(out.length).toBeLessThanOrEqual(realised.length); | |
| 18 | + for (const r of out) { | |
| 19 | + expect(r.kind).toBe('sale'); | |
| 20 | + if (r.kind !== 'sale') continue; | |
| 21 | + const lot = payload.lots.find((l) => l.objectId === r.externalId)!; | |
| 22 | + expect(r.price).toBe(lot.priceRealised); | |
| 23 | + expect(r.currency).toBe(currencyFromText(lot.priceRealisedText)); | |
| 24 | + expect(r.buyerPremiumIncluded).toBe(true); | |
| 25 | + expect(r.saleDate.toISOString()).toBe(new Date(lot.endDate ?? payload.sale.endDate!).toISOString()); | |
| 26 | + expect(r.auctionHouse).toBe("Christie's"); | |
| 27 | + expect(r.lotNumber).toBe(lot.lotNumber); | |
| 28 | + expect(r.attributes.identifiers.christies_sale_number).toBe(payload.sale.saleNumber); | |
| 29 | + expect(r.attributes.metadata.estimate_low).toBe(lot.estimateLow); | |
| 30 | + } | |
| 31 | + }); | |
| 32 | + | |
| 33 | + it('skips withdrawn and unsold lots', async () => { | |
| 34 | + const fx = loadFixture('christies', 'results-1'); | |
| 35 | + const payload = structuredClone(fx.raw.payload) as PagePayload; | |
| 36 | + const keep = payload.lots.find((l) => (l.priceRealised ?? 0) > 0)!; | |
| 37 | + payload.lots = [{ ...keep, objectId: 'w', withdrawn: true }, { ...keep, objectId: 'u', priceRealised: null, priceRealisedText: null }, { ...keep, objectId: 'z', priceRealised: 0 }, keep]; | |
| 38 | + const out = await connector.normalize({ ...fx.raw, payload }); | |
| 39 | + expect(out.map((r) => ('externalId' in r ? r.externalId : null))).toEqual([keep.objectId]); | |
| 40 | + }); | |
| 41 | + | |
| 42 | + it('parses month results and lot searches', () => { | |
| 43 | + const month = { | |
| 44 | + filters: { groups: [{ title_txt: 'Category', type: 'category', filters: [{ id: 'category_9', label_txt: 'Jewellery, Watches & Handbags' }] }] }, | |
| 45 | + events: [{ event_id: '31193', landing_url: 'https://www.christies.com/en/auction/x-31193/', title_txt: 'Important Watches', subtitle_txt: 'Live Auction 24546 | CLOSED', filter_ids: '|category_9|location_36|event_0||event_live|', location_txt: 'London', start_date: '2026-07-08T00:00:00', end_date: '2026-07-08T00:00:00', sale_total_value_txt: 'GBP 12,707,879' }], | |
| 46 | + }; | |
| 47 | + const sales = parseResultsMonth(month); | |
| 48 | + expect(sales).toHaveLength(1); | |
| 49 | + expect(sales[0]).toMatchObject({ saleId: '31193', saleNumber: '24546', eventType: 'Live', categoryLabels: ['Jewellery, Watches & Handbags'], location: 'London' }); | |
| 50 | + expect(hintForSale(sales[0]!, ['Jewellery, Watches & Handbags'])).toBe('watches'); | |
| 51 | + expect(lotSearchUrl(sales[0]!, 2, 84)).toContain('SaleNumber=24546&SaleId=31193&page=2&pageSize=84'); | |
| 52 | + expect(resultsUrl(7, 2026)).toBe('https://www.christies.com/api/discoverywebsite/auctioncalendar/auctionresults?language=en&month=7&year=2026'); | |
| 53 | + const ls = parseLotSearch({ lots: [{ object_id: '1', lot_id_txt: '5', title_primary_txt: 'ROLEX', title_secondary_txt: 'REF. 6239 DAYTONA', price_realised: '190500.0', price_realised_txt: 'GBP 190,500', estimate_low: '40000.0', estimate_high: '60000.0', end_date: '2026-07-07T23:00Z', url: 'https://www.christies.com/en/lot/lot-1' }], total_hits_filtered: 1 }); | |
| 54 | + expect(ls.total).toBe(1); | |
| 55 | + expect(ls.lots[0]).toMatchObject({ objectId: '1', lotNumber: '5', priceRealised: 190500, estimateLow: 40000 }); | |
| 56 | + expect(currencyFromText('HKD 1,250,000')).toBe('HKD'); | |
| 57 | + expect(currencyFromText(null)).toBeNull(); | |
| 58 | + }); | |
| 59 | + | |
| 60 | + it('maps a watch lot from a jewellery/watches sale to the brand slug with reference', async () => { | |
| 61 | + const fx = loadFixture('christies', 'results-1'); | |
| 62 | + const payload = structuredClone(fx.raw.payload) as PagePayload; | |
| 63 | + payload.sale = { ...payload.sale, categoryLabels: ['Jewellery, Watches & Handbags'], title: 'Important Watches' }; | |
| 64 | + const base = payload.lots.find((l) => (l.priceRealised ?? 0) > 0)!; | |
| 65 | + payload.lots = [{ ...base, objectId: 'rolex1', titlePrimary: 'ROLEX', titleSecondary: 'REF. 116500LN DAYTONA, A STAINLESS STEEL AUTOMATIC CHRONOGRAPH WRISTWATCH', titleTertiary: null, description: null, priceRealised: 30000, priceRealisedText: 'USD 30,000' }]; | |
| 66 | + const out = await connector.normalize({ ...fx.raw, payload }); | |
| 67 | + expect(out).toHaveLength(1); | |
| 68 | + const r = out[0]!; | |
| 69 | + if (r.kind !== 'sale') throw new Error('expected sale'); | |
| 70 | + expect(r.attributes.categorySlug).toBe('rolex'); | |
| 71 | + expect(r.attributes.identifiers.reference).toBe('116500LN'); | |
| 72 | + expect(r.attributes.brand).toBe('Rolex'); | |
| 73 | + expect(r.currency).toBe('USD'); | |
| 74 | + }); | |
| 75 | +}); | |
added
connectors/api/christies/index.ts
+307 −0
@@ -0,0 +1,307 @@ | ||
| 1 | +import { z } from 'zod'; | |
| 2 | +import { BaseConnector, type ConnectorMeta, type CrawlContext, type RawRecordInput, type RawRecordLike } from '@rareindex/connectors'; | |
| 3 | +import { NormalizedSaleSchema, SUPPORTED_CURRENCIES, type CurrencyCode, type NormalizedRecord } from '@rareindex/shared'; | |
| 4 | +import { parseGradeFromTitle } from '@rareindex/taxonomy'; | |
| 5 | +import { brandFromSlug, hintFromLabel, isBundleTitle, legoSetNumber, safeYear, slugFromTitle, watchReference, type DeptHint } from '../_auction-lib/categories.js'; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * Christie's — prices realised from the public discovery-website JSON endpoints (§110). | |
| 9 | + * Engine: plain HTTPS. See meta.json accessNotes. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +const SITE = 'https://www.christies.com'; | |
| 13 | +const RESULTS = `${SITE}/api/discoverywebsite/auctioncalendar/auctionresults`; | |
| 14 | +const LOTSEARCH = `${SITE}/api/discoverywebsite/auctionpages/lotsearch`; | |
| 15 | +/** christies.com's edge silently drops requests whose User-Agent contains a URL or '@'; we still identify ourselves honestly. */ | |
| 16 | +const UA = 'RareIndex/0.1 (market data research; contact data at rareindex.io)'; | |
| 17 | + | |
| 18 | +export const SaleSchema = z.object({ | |
| 19 | + saleId: z.string(), | |
| 20 | + saleNumber: z.string(), | |
| 21 | + title: z.string(), | |
| 22 | + subtitle: z.string().nullable(), | |
| 23 | + eventType: z.string().nullable(), // Live | Online | |
| 24 | + location: z.string().nullable(), | |
| 25 | + startDate: z.string().nullable(), | |
| 26 | + endDate: z.string().nullable(), | |
| 27 | + landingUrl: z.string().nullable(), | |
| 28 | + categoryLabels: z.array(z.string()), | |
| 29 | + saleTotalText: z.string().nullable(), | |
| 30 | +}); | |
| 31 | +export type Sale = z.infer<typeof SaleSchema>; | |
| 32 | + | |
| 33 | +export const LotSchema = z.object({ | |
| 34 | + objectId: z.string(), | |
| 35 | + lotNumber: z.string(), | |
| 36 | + titlePrimary: z.string(), | |
| 37 | + titleSecondary: z.string().nullable(), | |
| 38 | + titleTertiary: z.string().nullable(), | |
| 39 | + description: z.string().nullable(), | |
| 40 | + url: z.string().nullable(), | |
| 41 | + imageUrl: z.string().nullable(), | |
| 42 | + estimateLow: z.number().nullable(), | |
| 43 | + estimateHigh: z.number().nullable(), | |
| 44 | + estimateText: z.string().nullable(), | |
| 45 | + priceRealised: z.number().nullable(), | |
| 46 | + priceRealisedText: z.string().nullable(), | |
| 47 | + startDate: z.string().nullable(), | |
| 48 | + endDate: z.string().nullable(), | |
| 49 | + withdrawn: z.boolean(), | |
| 50 | + isOver: z.boolean(), | |
| 51 | +}); | |
| 52 | +export type Lot = z.infer<typeof LotSchema>; | |
| 53 | + | |
| 54 | +export const PagePayloadSchema = z.object({ | |
| 55 | + kind: z.literal('sale_lots'), | |
| 56 | + sale: SaleSchema, | |
| 57 | + page: z.number().int(), | |
| 58 | + totalHits: z.number().nullable(), | |
| 59 | + lots: z.array(LotSchema), | |
| 60 | +}); | |
| 61 | +export type PagePayload = z.infer<typeof PagePayloadSchema>; | |
| 62 | + | |
| 63 | +const ConfigSchema = z.object({ | |
| 64 | + categoryLabels: z.array(z.string()).default([]), | |
| 65 | + monthsPerRun: z.number().int().min(1).default(2), | |
| 66 | + backfillMonths: z.number().int().min(1).default(36), | |
| 67 | + maxSalesPerRun: z.number().int().min(1).default(30), | |
| 68 | + pageSize: z.number().int().min(10).max(200).default(84), | |
| 69 | +}); | |
| 70 | + | |
| 71 | +function numOrNull(v: unknown): number | null { | |
| 72 | + if (v === null || v === undefined || v === '') return null; | |
| 73 | + const n = typeof v === 'number' ? v : Number.parseFloat(String(v)); | |
| 74 | + return Number.isFinite(n) ? n : null; | |
| 75 | +} | |
| 76 | +const str = (v: unknown): string | null => (typeof v === 'string' && v.trim().length ? v.trim() : null); | |
| 77 | + | |
| 78 | +/** Parse an auctionresults month response into sales; `categoryNames` maps filter ids → labels. */ | |
| 79 | +export function parseResultsMonth(json: any): Sale[] { | |
| 80 | + const labels = new Map<string, string>(); | |
| 81 | + for (const g of json?.filters?.groups ?? []) { | |
| 82 | + for (const f of g.filters ?? []) if (f.id && f.label_txt) labels.set(String(f.id), String(f.label_txt)); | |
| 83 | + for (const fg of Object.values((g.filter_groups ?? {}) as Record<string, any>)) for (const f of fg?.filters ?? []) if (f.id && f.label_txt) labels.set(String(f.id), String(f.label_txt)); | |
| 84 | + } | |
| 85 | + const out: Sale[] = []; | |
| 86 | + for (const e of json?.events ?? []) { | |
| 87 | + const landing = str(e.landing_url); | |
| 88 | + const saleNumber = landing?.match(/SaleNumber=(\d+)/)?.[1] ?? String(e.subtitle_txt ?? '').match(/Auction\s+(\d{4,6})/)?.[1] ?? null; | |
| 89 | + if (!e.event_id || !saleNumber) continue; | |
| 90 | + const ids = String(e.filter_ids ?? '').split('|').filter(Boolean); | |
| 91 | + const categoryLabels = ids.filter((id) => id.startsWith('category_')).map((id) => labels.get(id) ?? id); | |
| 92 | + const locId = ids.find((id) => id.startsWith('location_')); | |
| 93 | + out.push( | |
| 94 | + SaleSchema.parse({ | |
| 95 | + saleId: String(e.event_id), | |
| 96 | + saleNumber, | |
| 97 | + title: String(e.title_txt ?? ''), | |
| 98 | + subtitle: str(e.subtitle_txt), | |
| 99 | + eventType: /online/i.test(String(e.subtitle_txt ?? '')) || ids.includes('event_115') ? 'Online' : ids.includes('event_live') ? 'Live' : null, | |
| 100 | + location: str(e.location_txt) ?? (locId ? labels.get(locId) ?? null : null), | |
| 101 | + startDate: str(e.start_date), | |
| 102 | + endDate: str(e.end_date), | |
| 103 | + landingUrl: landing, | |
| 104 | + categoryLabels, | |
| 105 | + saleTotalText: str(e.sale_total_value_txt), | |
| 106 | + }), | |
| 107 | + ); | |
| 108 | + } | |
| 109 | + return out; | |
| 110 | +} | |
| 111 | + | |
| 112 | +export function parseLotSearch(json: any): { lots: Lot[]; total: number | null } { | |
| 113 | + const lots: Lot[] = []; | |
| 114 | + for (const l of json?.lots ?? []) { | |
| 115 | + lots.push( | |
| 116 | + LotSchema.parse({ | |
| 117 | + objectId: String(l.object_id ?? ''), | |
| 118 | + lotNumber: String(l.lot_id_txt ?? ''), | |
| 119 | + titlePrimary: String(l.title_primary_txt ?? '').trim(), | |
| 120 | + titleSecondary: str(l.title_secondary_txt), | |
| 121 | + titleTertiary: str(l.title_tertiary_txt), | |
| 122 | + description: str(String(l.description_txt ?? '').replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ')), | |
| 123 | + url: str(l.url), | |
| 124 | + imageUrl: str(l.image?.image_src), | |
| 125 | + estimateLow: numOrNull(l.estimate_low), | |
| 126 | + estimateHigh: numOrNull(l.estimate_high), | |
| 127 | + estimateText: str(l.estimate_txt), | |
| 128 | + priceRealised: numOrNull(l.price_realised), | |
| 129 | + priceRealisedText: str(l.price_realised_txt), | |
| 130 | + startDate: str(l.start_date), | |
| 131 | + endDate: str(l.end_date), | |
| 132 | + withdrawn: Boolean(l.lot_withdrawn), | |
| 133 | + isOver: Boolean(l.is_auction_over), | |
| 134 | + }), | |
| 135 | + ); | |
| 136 | + } | |
| 137 | + return { lots, total: numOrNull(json?.total_hits_filtered) }; | |
| 138 | +} | |
| 139 | + | |
| 140 | +export function resultsUrl(month: number, year: number): string { | |
| 141 | + return `${RESULTS}?language=en&month=${month}&year=${year}`; | |
| 142 | +} | |
| 143 | +export function lotSearchUrl(sale: Pick<Sale, 'saleId' | 'saleNumber'>, page: number, pageSize: number): string { | |
| 144 | + return `${LOTSEARCH}?language=en&SaleNumber=${sale.saleNumber}&SaleId=${sale.saleId}&page=${page}&pageSize=${pageSize}&sortby=lotnumber`; | |
| 145 | +} | |
| 146 | + | |
| 147 | +/** "GBP 190,500" → { currency, amount } (amount taken from numeric price_realised when available). */ | |
| 148 | +export function currencyFromText(text: string | null): CurrencyCode | null { | |
| 149 | + const code = text?.match(/^([A-Z]{3})\b/)?.[1] ?? null; | |
| 150 | + return code && (SUPPORTED_CURRENCIES as readonly string[]).includes(code) ? (code as CurrencyCode) : null; | |
| 151 | +} | |
| 152 | + | |
| 153 | +export function hintForSale(sale: Sale, cfg: string[]): DeptHint { | |
| 154 | + const labels = sale.categoryLabels.length ? sale.categoryLabels : []; | |
| 155 | + const chosen = labels.find((l) => cfg.includes(l)) ?? labels[0] ?? null; | |
| 156 | + const fromLabel = hintFromLabel(chosen); | |
| 157 | + if (fromLabel !== 'unknown') return fromLabel; | |
| 158 | + if (chosen === 'Collectibles') return 'popular_culture'; | |
| 159 | + return hintFromLabel(sale.title); | |
| 160 | +} | |
| 161 | + | |
| 162 | +function monthsBack(from: Date, n: number): Array<{ month: number; year: number }> { | |
| 163 | + const out: Array<{ month: number; year: number }> = []; | |
| 164 | + const d = new Date(Date.UTC(from.getUTCFullYear(), from.getUTCMonth(), 1)); | |
| 165 | + for (let i = 0; i < n; i++) { | |
| 166 | + out.push({ month: d.getUTCMonth() + 1, year: d.getUTCFullYear() }); | |
| 167 | + d.setUTCMonth(d.getUTCMonth() - 1); | |
| 168 | + } | |
| 169 | + return out; | |
| 170 | +} | |
| 171 | + | |
| 172 | +export default function createConnector(meta: ConnectorMeta) { | |
| 173 | + return new ChristiesConnector(meta); | |
| 174 | +} | |
| 175 | + | |
| 176 | +export class ChristiesConnector extends BaseConnector { | |
| 177 | + readonly version = '1.0.0'; | |
| 178 | + readonly parserVersion = '1.0.0'; | |
| 179 | + protected override minIntervalMs = 1200; | |
| 180 | + private readonly config = ConfigSchema.parse(this.meta.config ?? {}); | |
| 181 | + | |
| 182 | + private async json(ctx: CrawlContext, url: string): Promise<unknown | null> { | |
| 183 | + await this.throttle(); | |
| 184 | + const res = await ctx.fetch(url, { engines: ['api'], responseType: 'json', minQuality: 0, headers: { accept: 'application/json', referer: `${SITE}/en/results`, 'user-agent': UA } }); | |
| 185 | + if (!res.success || res.json === null || res.json === undefined) { | |
| 186 | + ctx.anomaly('page_fetch_failed', `${url}: ${res.error ?? res.httpStatus}`); | |
| 187 | + return null; | |
| 188 | + } | |
| 189 | + return res.json; | |
| 190 | + } | |
| 191 | + | |
| 192 | + private wanted(sale: Sale): boolean { | |
| 193 | + if (!this.config.categoryLabels.length) return true; | |
| 194 | + return sale.categoryLabels.some((l) => this.config.categoryLabels.includes(l)); | |
| 195 | + } | |
| 196 | + | |
| 197 | + async *crawl(ctx: CrawlContext): AsyncIterable<RawRecordInput> { | |
| 198 | + const cursor = { ...(ctx.options.cursor ?? {}) } as { done?: string[]; backfillMonth?: string }; | |
| 199 | + const done = new Set(cursor.done ?? []); | |
| 200 | + const probe = ctx.options.mode === 'probe'; | |
| 201 | + const backfill = ctx.options.mode === 'backfill'; | |
| 202 | + const now = new Date(); | |
| 203 | + let months = monthsBack(now, probe ? 1 : backfill ? this.config.backfillMonths : this.config.monthsPerRun); | |
| 204 | + if (backfill && cursor.backfillMonth) { | |
| 205 | + const [y, m] = cursor.backfillMonth.split('-').map(Number); | |
| 206 | + months = months.filter((x) => x.year < y! || (x.year === y && x.month <= m!)); | |
| 207 | + } | |
| 208 | + let sales = 0; | |
| 209 | + let yielded = 0; | |
| 210 | + for (const { month, year } of months) { | |
| 211 | + const monthJson = await this.json(ctx, resultsUrl(month, year)); | |
| 212 | + if (!monthJson) continue; | |
| 213 | + const list = parseResultsMonth(monthJson).filter((s) => this.wanted(s)); | |
| 214 | + if (!list.length && !(monthJson as { events?: unknown[] }).events?.length) ctx.anomaly('empty_page', `results ${year}-${month}: no events`); | |
| 215 | + for (const sale of list) { | |
| 216 | + if (done.has(sale.saleId)) continue; | |
| 217 | + if (sales >= (probe ? 1 : this.config.maxSalesPerRun)) return; | |
| 218 | + sales++; | |
| 219 | + let page = 1; | |
| 220 | + let seen = 0; | |
| 221 | + for (; page <= 40; page++) { | |
| 222 | + const url = lotSearchUrl(sale, page, probe ? 20 : this.config.pageSize); | |
| 223 | + const lj = await this.json(ctx, url); | |
| 224 | + if (!lj) break; | |
| 225 | + const { lots, total } = parseLotSearch(lj); | |
| 226 | + if (!lots.length) break; | |
| 227 | + seen += lots.length; | |
| 228 | + const payload: PagePayload = { kind: 'sale_lots', sale, page, totalHits: total, lots }; | |
| 229 | + yield { url, externalId: `${sale.saleNumber}#${page}`, kind: 'sale', engine: 'api', httpStatus: 200, payload, fetchedAt: new Date() }; | |
| 230 | + yielded += lots.length; | |
| 231 | + if (this.reached(ctx, yielded)) return; | |
| 232 | + if (probe || (total !== null && seen >= total)) break; | |
| 233 | + } | |
| 234 | + done.add(sale.saleId); | |
| 235 | + cursor.done = [...done].slice(-800); | |
| 236 | + await ctx.setCursor(cursor); | |
| 237 | + } | |
| 238 | + if (backfill) { | |
| 239 | + cursor.backfillMonth = `${year}-${String(month).padStart(2, '0')}`; | |
| 240 | + await ctx.setCursor(cursor); | |
| 241 | + } | |
| 242 | + } | |
| 243 | + } | |
| 244 | + | |
| 245 | + async normalize(raw: RawRecordLike): Promise<NormalizedRecord[]> { | |
| 246 | + const page = PagePayloadSchema.parse(raw.payload); | |
| 247 | + const sale = page.sale; | |
| 248 | + const hint = hintForSale(sale, this.config.categoryLabels); | |
| 249 | + const out: NormalizedRecord[] = []; | |
| 250 | + for (const lot of page.lots) { | |
| 251 | + if (lot.withdrawn || lot.priceRealised === null || lot.priceRealised <= 0) continue; | |
| 252 | + const cur = currencyFromText(lot.priceRealisedText) ?? currencyFromText(lot.estimateText); | |
| 253 | + if (!cur) continue; | |
| 254 | + const title = [lot.titlePrimary, lot.titleSecondary, lot.titleTertiary].filter(Boolean).join(' — '); | |
| 255 | + const categorySlug = slugFromTitle(title, hint) ?? slugFromTitle(lot.description ?? '', hint); | |
| 256 | + if (!categorySlug) continue; | |
| 257 | + const saleDate = new Date(lot.endDate ?? sale.endDate ?? ''); | |
| 258 | + if (Number.isNaN(saleDate.getTime()) || saleDate.getTime() > Date.now() + 86_400_000) continue; | |
| 259 | + const grade = parseGradeFromTitle(title); | |
| 260 | + const isWatch = ['rolex', 'patek_philippe', 'audemars_piguet', 'omega', 'other_watches'].includes(categorySlug); | |
| 261 | + const reference = isWatch ? watchReference(`${title} ${lot.description ?? ''}`) : null; | |
| 262 | + const identifiers: Record<string, string> = { christies_object_id: lot.objectId, christies_sale_number: sale.saleNumber }; | |
| 263 | + if (reference) identifiers.reference = reference; | |
| 264 | + if (categorySlug === 'lego_sets') { | |
| 265 | + const n = legoSetNumber(title); | |
| 266 | + if (n) identifiers.lego_set_number = n; | |
| 267 | + } | |
| 268 | + out.push( | |
| 269 | + NormalizedSaleSchema.parse({ | |
| 270 | + kind: 'sale', | |
| 271 | + connectorId: this.meta.id, | |
| 272 | + sourceId: this.meta.sourceId, | |
| 273 | + sourceUrl: lot.url ?? `${SITE}/en/lot/lot-${lot.objectId}`, | |
| 274 | + externalId: lot.objectId, | |
| 275 | + rawTitle: title, | |
| 276 | + description: lot.description, | |
| 277 | + imageUrls: lot.imageUrl ? [lot.imageUrl] : [], | |
| 278 | + attributes: { | |
| 279 | + categorySlug, | |
| 280 | + name: lot.titleSecondary && isWatch ? `${lot.titlePrimary} ${lot.titleSecondary}` : title, | |
| 281 | + brand: brandFromSlug(categorySlug, title) ?? (isWatch ? lot.titlePrimary.replace(/\.$/, '') : null), | |
| 282 | + reference, | |
| 283 | + year: safeYear(title), | |
| 284 | + identifiers, | |
| 285 | + metadata: { sale_id: sale.saleId, sale_number: sale.saleNumber, sale_title: sale.title, sale_type: sale.eventType, sale_categories: sale.categoryLabels, estimate_low: lot.estimateLow, estimate_high: lot.estimateHigh, estimate_text: lot.estimateText }, | |
| 286 | + }, | |
| 287 | + grade: { grader: grade.grader, grade: grade.grade, qualifier: grade.qualifier, certificationNumber: null }, | |
| 288 | + condition: {}, | |
| 289 | + observedAt: raw.fetchedAt, | |
| 290 | + confidence: 0.9, | |
| 291 | + parserVersion: this.parserVersion, | |
| 292 | + saleType: 'auction', | |
| 293 | + saleDate, | |
| 294 | + price: lot.priceRealised, | |
| 295 | + currency: cur, | |
| 296 | + buyerPremiumIncluded: true, | |
| 297 | + quantity: 1, | |
| 298 | + isBundle: isBundleTitle(title), | |
| 299 | + location: sale.location, | |
| 300 | + auctionHouse: "Christie's", | |
| 301 | + lotNumber: lot.lotNumber, | |
| 302 | + }), | |
| 303 | + ); | |
| 304 | + } | |
| 305 | + return out; | |
| 306 | + } | |
| 307 | +} | |
added
connectors/api/christies/meta.json
+95 −0
@@ -0,0 +1,95 @@ | ||
| 1 | +{ | |
| 2 | + "id": "christies", | |
| 3 | + "displayName": "Christie's (auction results)", | |
| 4 | + "sourceId": "christies", | |
| 5 | + "sourceName": "Christie's", | |
| 6 | + "sourceType": "auction_house", | |
| 7 | + "sourceUrl": "https://www.christies.com", | |
| 8 | + "module": "api/christies", | |
| 9 | + "enginePriority": [ | |
| 10 | + "api" | |
| 11 | + ], | |
| 12 | + "categories": [ | |
| 13 | + "rolex", | |
| 14 | + "patek_philippe", | |
| 15 | + "audemars_piguet", | |
| 16 | + "omega", | |
| 17 | + "other_watches", | |
| 18 | + "luxury_handbags", | |
| 19 | + "jewelry", | |
| 20 | + "gemstones", | |
| 21 | + "wine", | |
| 22 | + "whisky", | |
| 23 | + "cognac", | |
| 24 | + "art", | |
| 25 | + "contemporary_art", | |
| 26 | + "photography", | |
| 27 | + "books", | |
| 28 | + "maps", | |
| 29 | + "historical_documents", | |
| 30 | + "antiques", | |
| 31 | + "design_furniture", | |
| 32 | + "scientific_instruments", | |
| 33 | + "fossils", | |
| 34 | + "minerals", | |
| 35 | + "meteorites", | |
| 36 | + "sports_memorabilia", | |
| 37 | + "movie_memorabilia", | |
| 38 | + "music_memorabilia", | |
| 39 | + "sneakers", | |
| 40 | + "vintage_toys", | |
| 41 | + "automobiles" | |
| 42 | + ], | |
| 43 | + "regions": [ | |
| 44 | + "US", | |
| 45 | + "GB", | |
| 46 | + "HK", | |
| 47 | + "FR", | |
| 48 | + "CH" | |
| 49 | + ], | |
| 50 | + "languages": [ | |
| 51 | + "en" | |
| 52 | + ], | |
| 53 | + "currency": [ | |
| 54 | + "USD", | |
| 55 | + "GBP", | |
| 56 | + "HKD", | |
| 57 | + "EUR", | |
| 58 | + "CHF" | |
| 59 | + ], | |
| 60 | + "supportsListings": false, | |
| 61 | + "supportsSold": true, | |
| 62 | + "supportsAuctions": false, | |
| 63 | + "supportsImages": true, | |
| 64 | + "supportsCatalog": false, | |
| 65 | + "supportsPopulation": false, | |
| 66 | + "supportsLookup": false, | |
| 67 | + "refreshFrequencyMinutes": 720, | |
| 68 | + "priority": "high", | |
| 69 | + "trustScore": 0.9, | |
| 70 | + "attributionRequired": true, | |
| 71 | + "termsUrl": "https://www.christies.com/en/help/terms-and-conditions", | |
| 72 | + "accessNotes": "Plain HTTPS JSON (no rendering, no credits) from the two endpoints the public christies.com pages themselves call: /api/discoverywebsite/auctioncalendar/auctionresults?language=en&month=M&year=Y (closed sales of a month with SaleID/SaleNumber, category/location filters and sale totals) and /api/discoverywebsite/auctionpages/lotsearch?language=en&SaleNumber=…&SaleId=…&page=N&pageSize=…&sortby=lotnumber (lots with estimate, price_realised, dates, image, lot url; max ~84 lots per page). christies.com/robots.txt (User-agent: *) disallows */search, */AjaxPages, */lotimages, */mychristies and similar — none of these paths are used. Prices realised are published by Christie's inclusive of buyer's premium → buyerPremiumIncluded=true; currency comes from price_realised_txt (e.g. 'GBP 190,500'); sale date = the lot's end_date. Categories come from the sale's category filter labels plus title keywords; unmapped lots keep the family suggested by the sale category. Upcoming lots are not exposed by these endpoints (calendar of future sales is a different client app), so supportsAuctions=false. Note: christies.com's edge drops requests whose User-Agent contains a URL or an e-mail address, so the connector identifies itself as 'RareIndex/0.1 (market data research; contact data at rareindex.io)' — no browser impersonation.", | |
| 73 | + "enabled": true, | |
| 74 | + "schemaVersion": "1.0", | |
| 75 | + "config": { | |
| 76 | + "categoryLabels": [ | |
| 77 | + "Jewellery, Watches & Handbags", | |
| 78 | + "Wines & Spirits", | |
| 79 | + "Collectibles", | |
| 80 | + "Books & Manuscripts", | |
| 81 | + "Science and Natural History", | |
| 82 | + "Photographs & Prints", | |
| 83 | + "Fine Art", | |
| 84 | + "Furniture & Decorative Art", | |
| 85 | + "Antiquities", | |
| 86 | + "Asian Art", | |
| 87 | + "Design", | |
| 88 | + "Cars" | |
| 89 | + ], | |
| 90 | + "monthsPerRun": 2, | |
| 91 | + "backfillMonths": 36, | |
| 92 | + "maxSalesPerRun": 30, | |
| 93 | + "pageSize": 84 | |
| 94 | + } | |
| 95 | +} | |
added
connectors/api/sothebys/index.test.ts
+68 −0
@@ -0,0 +1,68 @@ | ||
| 1 | +import { describe, expect, it } from 'vitest'; | |
| 2 | +import { getConnectorMeta } from '@rareindex/connectors'; | |
| 3 | +import { listFixtures, loadFixture, runFixtureSuite } from '@rareindex/connectors/testing'; | |
| 4 | +import createConnector, { auctionLinks, classifyTitle, hintsForAuction, lotUrl, parseAuctionPage, parseGraphqlLots, type PagePayload } from './index.js'; | |
| 5 | + | |
| 6 | +const connector = createConnector(getConnectorMeta('sothebys')); | |
| 7 | + | |
| 8 | +describe('sothebys connector', () => { | |
| 9 | + runFixtureSuite(connector, it, expect); | |
| 10 | + | |
| 11 | + it('closed sales: price includes premium, hammer kept in metadata, date from the lot closing time', async () => { | |
| 12 | + const closed = listFixtures('sothebys').filter((n) => n.startsWith('closed')); | |
| 13 | + expect(closed.length).toBeGreaterThan(0); | |
| 14 | + const fx = loadFixture('sothebys', closed[0]!); | |
| 15 | + const payload = fx.raw.payload as PagePayload; | |
| 16 | + expect(payload.auction.state).toBe('Closed'); | |
| 17 | + const out = await connector.normalize(fx.raw); | |
| 18 | + expect(out.length).toBeGreaterThan(0); | |
| 19 | + for (const r of out) { | |
| 20 | + expect(r.kind).toBe('sale'); | |
| 21 | + if (r.kind !== 'sale') continue; | |
| 22 | + const lot = payload.lots.find((l) => l.lotId === r.externalId)!; | |
| 23 | + expect(lot.isSold).toBe(true); | |
| 24 | + expect(r.price).toBe(lot.finalPrice); | |
| 25 | + expect(r.price).toBeGreaterThanOrEqual(lot.currentBid ?? 0); | |
| 26 | + expect(r.buyerPremiumIncluded).toBe(true); | |
| 27 | + expect(r.attributes.metadata.hammer_price).toBe(lot.currentBid); | |
| 28 | + expect(r.saleDate.toISOString()).toBe(new Date(lot.closingTime ?? payload.auction.closedAt!).toISOString()); | |
| 29 | + expect(r.auctionHouse).toBe("Sotheby's"); | |
| 30 | + expect(r.sourceUrl).toBe(lotUrl(payload.auction.url, lot.slug, lot.lotId)); | |
| 31 | + } | |
| 32 | + }); | |
| 33 | + | |
| 34 | + it('open sales: lots become auction_lot records with estimates', async () => { | |
| 35 | + const live = listFixtures('sothebys').filter((n) => n.startsWith('live')); | |
| 36 | + expect(live.length).toBeGreaterThan(0); | |
| 37 | + const fx = loadFixture('sothebys', live[0]!); | |
| 38 | + const payload = fx.raw.payload as PagePayload; | |
| 39 | + expect(payload.auction.state).not.toBe('Closed'); | |
| 40 | + const out = await connector.normalize(fx.raw); | |
| 41 | + expect(out.length).toBeGreaterThan(0); | |
| 42 | + for (const r of out) { | |
| 43 | + expect(r.kind).toBe('auction_lot'); | |
| 44 | + if (r.kind !== 'auction_lot') continue; | |
| 45 | + expect(['upcoming', 'live']).toContain(r.status); | |
| 46 | + expect(r.currency).toBe(payload.auction.currency); | |
| 47 | + expect(r.auctionName).toBe(payload.auction.title); | |
| 48 | + } | |
| 49 | + }); | |
| 50 | + | |
| 51 | + it('mixed multi-department sales only trust title keywords', () => { | |
| 52 | + const mixed = { auctionId: 'x', url: 'u', title: 'Arcade | New York', saleNumber: null, state: 'Closed', type: 'Timed', departments: ['American Furniture', 'Decorative Art', 'American Art', 'Books & Manuscripts', 'Contemporary Art'], currency: 'USD', location: 'New York', startsAt: null, endsAt: null, closedAt: null, totalLots: null }; | |
| 53 | + const hints = hintsForAuction(mixed); | |
| 54 | + expect(hints[0]).toBe('unknown'); | |
| 55 | + expect(classifyTitle('Tom Baril — Lilies', hints)).toBeNull(); | |
| 56 | + expect(classifyTitle('Andy Warhol — Marilyn, screenprint', hints)).toBe('contemporary_art'); | |
| 57 | + const watches = { ...mixed, title: 'Important Watches', departments: ['Watches'] }; | |
| 58 | + expect(classifyTitle('Patek Philippe — Nautilus Ref. 5711/1A', hintsForAuction(watches))).toBe('patek_philippe'); | |
| 59 | + }); | |
| 60 | + | |
| 61 | + it('parses GraphQL pages and discovery links defensively', () => { | |
| 62 | + expect(parseAuctionPage('<html></html>', 'u')).toBeNull(); | |
| 63 | + expect(parseGraphqlLots({ errors: [{ message: 'x' }] })).toBeNull(); | |
| 64 | + const gl = parseGraphqlLots({ data: { auction: { lotCards: { totalCount: 1, hasNextPage: false, lots: [{ lotId: 'l1', title: 'T', lotNumber: { lotDisplayNumber: '7' }, slug: { lotSlug: 't' }, estimateV2: { lowEstimate: { amount: '10' }, highEstimate: { amount: '20' } }, bidState: { isClosed: true, closingTime: '2026-08-26T16:01Z', numberOfBids: 3, currentBidV2: { amount: '900', currency: 'USD' }, sold: { __typename: 'ResultVisible', isSold: true, premiums: { finalPriceV2: { amount: '1152', currency: 'USD' } } } } }] } } } }); | |
| 65 | + expect(gl?.lots[0]).toMatchObject({ lotId: 'l1', lotNumber: '7', estimateLow: 10, currentBid: 900, finalPrice: 1152, finalCurrency: 'USD', isSold: true }); | |
| 66 | + expect(auctionLinks('<a href="https://www.sothebys.com/en/buy/auction/2026/arcade-new-york">x</a> https://www.sothebys.com/en/buy/auction/2026/arcade-new-york/lilies')).toEqual(['https://www.sothebys.com/en/buy/auction/2026/arcade-new-york']); | |
| 67 | + }); | |
| 68 | +}); | |
added
connectors/api/sothebys/index.ts
+419 −0
@@ -0,0 +1,419 @@ | ||
| 1 | +import { z } from 'zod'; | |
| 2 | +import { BaseConnector, type ConnectorMeta, type CrawlContext, type RawRecordInput, type RawRecordLike } from '@rareindex/connectors'; | |
| 3 | +import { NormalizedAuctionLotSchema, NormalizedSaleSchema, SUPPORTED_CURRENCIES, type CurrencyCode, type NormalizedRecord } from '@rareindex/shared'; | |
| 4 | +import { parseGradeFromTitle } from '@rareindex/taxonomy'; | |
| 5 | +import { brandFromSlug, hintFromLabel, isBundleTitle, legoSetNumber, safeYear, slugFromTitle, watchReference, type DeptHint } from '../_auction-lib/categories.js'; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * Sotheby's — results (price incl. premium) and upcoming lots from the public auction pages and the | |
| 9 | + * page's own GraphQL lot-card pagination. Engine: plain HTTPS (+ Firecrawl for link discovery). | |
| 10 | + */ | |
| 11 | + | |
| 12 | +const SITE = 'https://www.sothebys.com'; | |
| 13 | +const GRAPHQL = 'https://clientapi.prod.sothelabs.com/graphql'; | |
| 14 | + | |
| 15 | +export const AuctionSchema = z.object({ | |
| 16 | + auctionId: z.string(), | |
| 17 | + url: z.string(), | |
| 18 | + title: z.string(), | |
| 19 | + saleNumber: z.string().nullable(), | |
| 20 | + state: z.string().nullable(), // Opened | Closed | Published… | |
| 21 | + type: z.string().nullable(), // Timed | Live | |
| 22 | + departments: z.array(z.string()), | |
| 23 | + currency: z.string().nullable(), | |
| 24 | + location: z.string().nullable(), | |
| 25 | + startsAt: z.string().nullable(), | |
| 26 | + endsAt: z.string().nullable(), | |
| 27 | + closedAt: z.string().nullable(), | |
| 28 | + totalLots: z.number().nullable(), | |
| 29 | +}); | |
| 30 | +export type Auction = z.infer<typeof AuctionSchema>; | |
| 31 | + | |
| 32 | +export const LotSchema = z.object({ | |
| 33 | + lotId: z.string(), | |
| 34 | + lotNumber: z.string().nullable(), | |
| 35 | + title: z.string(), | |
| 36 | + creators: z.string().nullable(), | |
| 37 | + slug: z.string().nullable(), | |
| 38 | + estimateLow: z.number().nullable(), | |
| 39 | + estimateHigh: z.number().nullable(), | |
| 40 | + isClosed: z.boolean().nullable(), | |
| 41 | + closingTime: z.string().nullable(), | |
| 42 | + currentBid: z.number().nullable(), | |
| 43 | + bidCurrency: z.string().nullable(), | |
| 44 | + isSold: z.boolean().nullable(), | |
| 45 | + finalPrice: z.number().nullable(), | |
| 46 | + finalCurrency: z.string().nullable(), | |
| 47 | + numberOfBids: z.number().nullable(), | |
| 48 | + imageUrl: z.string().nullable(), | |
| 49 | + withdrawn: z.boolean(), | |
| 50 | +}); | |
| 51 | +export type Lot = z.infer<typeof LotSchema>; | |
| 52 | + | |
| 53 | +export const PagePayloadSchema = z.object({ | |
| 54 | + kind: z.literal('auction_page'), | |
| 55 | + auction: AuctionSchema, | |
| 56 | + offset: z.number().int(), | |
| 57 | + lots: z.array(LotSchema), | |
| 58 | +}); | |
| 59 | +export type PagePayload = z.infer<typeof PagePayloadSchema>; | |
| 60 | + | |
| 61 | +const ConfigSchema = z.object({ | |
| 62 | + seeds: z.array(z.string()).default([]), | |
| 63 | + discoveryPages: z.array(z.string()).default([]), | |
| 64 | + departments: z.array(z.string()).default([]), | |
| 65 | + maxAuctionsPerRun: z.number().int().default(25), | |
| 66 | + pageSize: z.number().int().min(1).max(48).default(48), | |
| 67 | +}); | |
| 68 | + | |
| 69 | +const LOT_QUERY = `query LotCardsFilterByPaginated($id: String!, $limit: Int, $offset: Int) { | |
| 70 | + auction(id: $id, language: ENGLISH) { | |
| 71 | + id | |
| 72 | + lotCards: lotCardsConnection(offset: $offset, limit: $limit, filter: ALL) { | |
| 73 | + totalCount | |
| 74 | + hasNextPage | |
| 75 | + lots { | |
| 76 | + lotId | |
| 77 | + title | |
| 78 | + creatorsDisplayTitle | |
| 79 | + lotNumber { ... on VisibleLotNumber { lotDisplayNumber } } | |
| 80 | + slug { lotSlug } | |
| 81 | + withdrawnState { state } | |
| 82 | + estimateV2 { ... on LowHighEstimateV2 { lowEstimate { amount } highEstimate { amount } } } | |
| 83 | + bidState { | |
| 84 | + isClosed | |
| 85 | + closingTime | |
| 86 | + numberOfBids | |
| 87 | + currentBidV2 { amount currency } | |
| 88 | + sold { __typename ... on ResultVisible { isSold premiums { finalPriceV2 { amount currency } } } } | |
| 89 | + } | |
| 90 | + media(imageSizes: [Small]) { images { renditions { url } } } | |
| 91 | + } | |
| 92 | + } | |
| 93 | + } | |
| 94 | +}`; | |
| 95 | + | |
| 96 | +function num(v: unknown): number | null { | |
| 97 | + if (v === null || v === undefined || v === '') return null; | |
| 98 | + const n = typeof v === 'number' ? v : Number.parseFloat(String(v)); | |
| 99 | + return Number.isFinite(n) ? n : null; | |
| 100 | +} | |
| 101 | + | |
| 102 | +/** Build a Lot from a GraphQL lot card or from the SSR Apollo cache (refs resolved by caller). */ | |
| 103 | +function lotFrom(card: Record<string, any>, bidState: Record<string, any> | null): Lot { | |
| 104 | + const est = card.estimateV2 ?? {}; | |
| 105 | + const sold = bidState?.sold ?? {}; | |
| 106 | + const fp = sold.premiums?.finalPriceV2 ?? null; | |
| 107 | + const cb = bidState?.currentBidV2 ?? null; | |
| 108 | + const mediaKey = Object.keys(card).find((k) => k.startsWith('media')); | |
| 109 | + const img = mediaKey ? card[mediaKey]?.images?.[0]?.renditions?.[0]?.url ?? null : null; | |
| 110 | + return LotSchema.parse({ | |
| 111 | + lotId: String(card.lotId), | |
| 112 | + lotNumber: card.lotNumber?.lotDisplayNumber ?? null, | |
| 113 | + title: String(card.title ?? ''), | |
| 114 | + creators: card.creatorsDisplayTitle ?? null, | |
| 115 | + slug: card.slug?.lotSlug ?? null, | |
| 116 | + estimateLow: num(est.lowEstimate?.amount), | |
| 117 | + estimateHigh: num(est.highEstimate?.amount), | |
| 118 | + isClosed: typeof bidState?.isClosed === 'boolean' ? bidState.isClosed : null, | |
| 119 | + closingTime: bidState?.closingTime ?? null, | |
| 120 | + currentBid: num(cb?.amount), | |
| 121 | + bidCurrency: cb?.currency ?? null, | |
| 122 | + isSold: typeof sold.isSold === 'boolean' ? sold.isSold : null, | |
| 123 | + finalPrice: num(fp?.amount), | |
| 124 | + finalCurrency: fp?.currency ?? null, | |
| 125 | + numberOfBids: num(bidState?.numberOfBids), | |
| 126 | + imageUrl: typeof img === 'string' ? img : null, | |
| 127 | + withdrawn: card.withdrawnState?.state ? card.withdrawnState.state !== 'NotAffected' : false, | |
| 128 | + }); | |
| 129 | +} | |
| 130 | + | |
| 131 | +/** Parse an SSR auction page: auction + first lot cards from the Apollo cache. */ | |
| 132 | +export function parseAuctionPage(html: string, url: string): { auction: Auction; lots: Lot[] } | null { | |
| 133 | + const m = html.match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/); | |
| 134 | + if (!m) return null; | |
| 135 | + let cache: Record<string, any>; | |
| 136 | + let pp: Record<string, any>; | |
| 137 | + try { | |
| 138 | + pp = (JSON.parse(m[1]!) as { props: { pageProps: Record<string, any> } }).props.pageProps; | |
| 139 | + cache = pp.apolloCache ?? {}; | |
| 140 | + } catch { | |
| 141 | + return null; | |
| 142 | + } | |
| 143 | + const aKey = Object.keys(cache).find((k) => k.startsWith('Auction:')); | |
| 144 | + if (!aKey) return null; | |
| 145 | + const a = cache[aKey]; | |
| 146 | + const dates = a.dates ?? {}; | |
| 147 | + const cards = Object.keys(cache) | |
| 148 | + .filter((k) => k.startsWith('LotCard:')) | |
| 149 | + .map((k) => cache[k]) | |
| 150 | + .filter((c) => !c.auction || c.auction.auctionId === a.auctionId || c.auction.sapSaleNumber === a.sapSaleNumber); | |
| 151 | + const lots = cards.map((c) => lotFrom(c, c.bidState?.__ref ? cache[c.bidState.__ref] ?? null : c.bidState ?? null)); | |
| 152 | + const currency = a.currencyV2 ?? a.currency ?? cards[0]?.auction?.currency ?? lots.find((l) => l.finalCurrency)?.finalCurrency ?? null; | |
| 153 | + const auction = AuctionSchema.parse({ | |
| 154 | + auctionId: String(a.auctionId), | |
| 155 | + url, | |
| 156 | + title: String(a.title ?? ''), | |
| 157 | + saleNumber: a.sapSaleNumber ?? null, | |
| 158 | + state: a.state ?? null, | |
| 159 | + type: a.type ?? null, | |
| 160 | + departments: Array.isArray(a.departmentNames) ? a.departmentNames.map((d: string) => d.trim()) : [], | |
| 161 | + currency, | |
| 162 | + location: a.locationV2?.name ?? null, | |
| 163 | + startsAt: dates.goesLive ?? dates.acceptsBids ?? null, | |
| 164 | + endsAt: dates.startsToClose ?? dates.goesLive ?? null, | |
| 165 | + closedAt: dates.closed ?? null, | |
| 166 | + totalLots: num(pp.totalLotCount), | |
| 167 | + }); | |
| 168 | + return { auction, lots }; | |
| 169 | +} | |
| 170 | + | |
| 171 | +export function parseGraphqlLots(json: any): { lots: Lot[]; hasNextPage: boolean; totalCount: number | null } | null { | |
| 172 | + const conn = json?.data?.auction?.lotCards; | |
| 173 | + if (!conn) return null; | |
| 174 | + return { lots: (conn.lots ?? []).map((c: Record<string, any>) => lotFrom(c, c.bidState ?? null)), hasNextPage: Boolean(conn.hasNextPage), totalCount: num(conn.totalCount) }; | |
| 175 | +} | |
| 176 | + | |
| 177 | +export function auctionLinks(html: string): string[] { | |
| 178 | + return [...new Set([...html.matchAll(/https?:\/\/www\.sothebys\.com\/en\/buy\/auction\/(20\d{2})\/([a-z0-9-]+)/g)].map((m) => `${SITE}/en/buy/auction/${m[1]}/${m[2]}`))]; | |
| 179 | +} | |
| 180 | + | |
| 181 | +export function lotUrl(auctionUrl: string, lotSlug: string | null, lotId: string): string { | |
| 182 | + return lotSlug ? `${auctionUrl}/${lotSlug}` : `${auctionUrl}?lotId=${lotId}`; | |
| 183 | +} | |
| 184 | + | |
| 185 | +function currency(code: string | null | undefined): CurrencyCode | null { | |
| 186 | + return code && (SUPPORTED_CURRENCIES as readonly string[]).includes(code) ? (code as CurrencyCode) : null; | |
| 187 | +} | |
| 188 | + | |
| 189 | +/** Ordered hints for an auction: a single-department sale is a strong hint; a mixed "Arcade"-style sale is not. */ | |
| 190 | +export function hintsForAuction(a: Auction): DeptHint[] { | |
| 191 | + const hints = a.departments.map((d) => hintFromLabel(d)).filter((h) => h !== 'unknown'); | |
| 192 | + const titleHint = hintFromLabel(a.title); | |
| 193 | + // Mixed multi-department sales (e.g. "Arcade"): only title keywords are trusted; no department guess. | |
| 194 | + if (a.departments.length > 3) return ['unknown', ...(titleHint !== 'unknown' ? [titleHint] : [])]; | |
| 195 | + return [...(hints.length ? hints : []), ...(titleHint !== 'unknown' ? [titleHint] : []), 'unknown']; | |
| 196 | +} | |
| 197 | + | |
| 198 | +export function classifyTitle(title: string, hints: DeptHint[]): string | null { | |
| 199 | + for (const h of hints) { | |
| 200 | + const slug = slugFromTitle(title, h); | |
| 201 | + if (slug) return slug; | |
| 202 | + } | |
| 203 | + return null; | |
| 204 | +} | |
| 205 | + | |
| 206 | +function iso(d: string | null | undefined): Date | null { | |
| 207 | + if (!d) return null; | |
| 208 | + const x = new Date(d); | |
| 209 | + return Number.isNaN(x.getTime()) ? null : x; | |
| 210 | +} | |
| 211 | + | |
| 212 | +export default function createConnector(meta: ConnectorMeta) { | |
| 213 | + return new SothebysConnector(meta); | |
| 214 | +} | |
| 215 | + | |
| 216 | +export class SothebysConnector extends BaseConnector { | |
| 217 | + readonly version = '1.0.0'; | |
| 218 | + readonly parserVersion = '1.0.0'; | |
| 219 | + override readonly urlPatterns = [/^https?:\/\/(www\.)?sothebys\.com\/en\/buy\/auction\/20\d{2}\/[a-z0-9-]+/i]; | |
| 220 | + protected override minIntervalMs = 1500; | |
| 221 | + private readonly config = ConfigSchema.parse(this.meta.config ?? {}); | |
| 222 | + | |
| 223 | + private async page(ctx: CrawlContext, url: string): Promise<string | null> { | |
| 224 | + await this.throttle(); | |
| 225 | + const res = await ctx.fetch(url, { engines: ['api'], responseType: 'text', minQuality: 0, headers: { accept: 'text/html' } }); | |
| 226 | + if (!res.success || !res.html) { | |
| 227 | + ctx.anomaly('page_fetch_failed', `${url}: ${res.error ?? res.httpStatus}`); | |
| 228 | + return null; | |
| 229 | + } | |
| 230 | + return res.html; | |
| 231 | + } | |
| 232 | + | |
| 233 | + private async graphql(ctx: CrawlContext, auctionId: string, offset: number): Promise<ReturnType<typeof parseGraphqlLots>> { | |
| 234 | + await this.throttle(); | |
| 235 | + const res = await ctx.fetch(GRAPHQL, { | |
| 236 | + engines: ['api'], | |
| 237 | + method: 'POST', | |
| 238 | + body: { operationName: 'LotCardsFilterByPaginated', query: LOT_QUERY, variables: { id: auctionId, limit: this.config.pageSize, offset } }, | |
| 239 | + headers: { origin: SITE, referer: `${SITE}/`, accept: 'application/json' }, | |
| 240 | + responseType: 'json', | |
| 241 | + minQuality: 0, | |
| 242 | + }); | |
| 243 | + if (!res.success || !res.json) { | |
| 244 | + ctx.anomaly('page_fetch_failed', `graphql ${auctionId}@${offset}: ${res.error ?? res.httpStatus}`); | |
| 245 | + return null; | |
| 246 | + } | |
| 247 | + const parsed = parseGraphqlLots(res.json); | |
| 248 | + if (!parsed) ctx.anomaly('parse_failure', `graphql ${auctionId}@${offset}: ${JSON.stringify((res.json as { errors?: unknown }).errors ?? '').slice(0, 200)}`); | |
| 249 | + return parsed; | |
| 250 | + } | |
| 251 | + | |
| 252 | + private async discover(ctx: CrawlContext): Promise<string[]> { | |
| 253 | + const found = new Set<string>(this.config.seeds); | |
| 254 | + for (const page of this.config.discoveryPages) { | |
| 255 | + const res = await ctx.fetch(page, { engines: ['firecrawl'], waitForMs: 4000, minQuality: 0 }); | |
| 256 | + if (!res.success || !res.html) { | |
| 257 | + ctx.anomaly('page_fetch_failed', `${page}: ${res.error ?? res.httpStatus}`); | |
| 258 | + continue; | |
| 259 | + } | |
| 260 | + for (const u of auctionLinks(res.html)) found.add(u); | |
| 261 | + } | |
| 262 | + return [...found]; | |
| 263 | + } | |
| 264 | + | |
| 265 | + private async *crawlAuction(ctx: CrawlContext, url: string, probe: boolean): AsyncIterable<RawRecordInput> { | |
| 266 | + const html = await this.page(ctx, url); | |
| 267 | + if (!html) return; | |
| 268 | + const parsed = parseAuctionPage(html, url); | |
| 269 | + if (!parsed) { | |
| 270 | + ctx.anomaly('parse_failure', `${url}: no Auction in __NEXT_DATA__`); | |
| 271 | + return; | |
| 272 | + } | |
| 273 | + const a = parsed.auction; | |
| 274 | + if (this.config.departments.length && !a.departments.some((d) => this.config.departments.includes(d))) return; | |
| 275 | + const kind = a.state === 'Closed' ? 'sale' : 'auction_lot'; | |
| 276 | + const first: PagePayload = { kind: 'auction_page', auction: a, offset: 0, lots: parsed.lots }; | |
| 277 | + yield { url, externalId: `${a.auctionId}#0`, kind, engine: 'api', httpStatus: 200, payload: first, fetchedAt: new Date() }; | |
| 278 | + if (probe) return; | |
| 279 | + let offset = parsed.lots.length; | |
| 280 | + const total = a.totalLots ?? Infinity; | |
| 281 | + for (let guard = 0; offset < total && guard < 60; guard++) { | |
| 282 | + const gl = await this.graphql(ctx, a.auctionId, offset); | |
| 283 | + if (!gl || !gl.lots.length) break; | |
| 284 | + const payload: PagePayload = { kind: 'auction_page', auction: a, offset, lots: gl.lots }; | |
| 285 | + yield { url: `${url}#offset=${offset}`, externalId: `${a.auctionId}#${offset}`, kind, engine: 'api', httpStatus: 200, payload, fetchedAt: new Date() }; | |
| 286 | + offset += gl.lots.length; | |
| 287 | + if (!gl.hasNextPage) break; | |
| 288 | + } | |
| 289 | + } | |
| 290 | + | |
| 291 | + async *crawl(ctx: CrawlContext): AsyncIterable<RawRecordInput> { | |
| 292 | + const cursor = { auctions: {}, ...(ctx.options.cursor ?? {}) } as { auctions: Record<string, { state: string | null; checkedAt: string }> }; | |
| 293 | + const probe = ctx.options.mode === 'probe'; | |
| 294 | + const urls = ctx.options.seeds?.length ? ctx.options.seeds : await this.discover(ctx); | |
| 295 | + // Re-check auctions previously seen open (their results become visible after close). | |
| 296 | + for (const [u, s] of Object.entries(cursor.auctions)) if (s.state !== 'Closed' && !urls.includes(u)) urls.push(u); | |
| 297 | + let n = 0; | |
| 298 | + for (const url of urls) { | |
| 299 | + if (ctx.signal?.aborted) return; | |
| 300 | + const prev = cursor.auctions[url]; | |
| 301 | + if (prev?.state === 'Closed' && ctx.options.mode !== 'backfill') continue; | |
| 302 | + if (n++ >= (probe ? 1 : this.config.maxAuctionsPerRun)) break; | |
| 303 | + let state: string | null = prev?.state ?? null; | |
| 304 | + for await (const raw of this.crawlAuction(ctx, url, probe)) { | |
| 305 | + state = (raw.payload as PagePayload).auction.state; | |
| 306 | + yield raw; | |
| 307 | + } | |
| 308 | + cursor.auctions[url] = { state, checkedAt: new Date().toISOString() }; | |
| 309 | + const entries = Object.entries(cursor.auctions); | |
| 310 | + if (entries.length > 400) cursor.auctions = Object.fromEntries(entries.slice(-400)); | |
| 311 | + await ctx.setCursor(cursor); | |
| 312 | + } | |
| 313 | + } | |
| 314 | + | |
| 315 | + async lookup(url: string, ctx: CrawlContext): Promise<RawRecordInput[]> { | |
| 316 | + const m = url.match(/^(https?:\/\/(?:www\.)?sothebys\.com\/en\/buy\/auction\/20\d{2}\/[a-z0-9-]+)(?:\/([a-z0-9-]+))?/i); | |
| 317 | + if (!m) return []; | |
| 318 | + const out: RawRecordInput[] = []; | |
| 319 | + for await (const raw of this.crawlAuction(ctx, m[1]!, true)) { | |
| 320 | + if (m[2]) { | |
| 321 | + const p = raw.payload as PagePayload; | |
| 322 | + p.lots = p.lots.filter((l) => l.slug === m[2]); | |
| 323 | + } | |
| 324 | + out.push(raw); | |
| 325 | + } | |
| 326 | + return out; | |
| 327 | + } | |
| 328 | + | |
| 329 | + async normalize(raw: RawRecordLike): Promise<NormalizedRecord[]> { | |
| 330 | + const page = PagePayloadSchema.parse(raw.payload); | |
| 331 | + const a = page.auction; | |
| 332 | + const hints = hintsForAuction(a); | |
| 333 | + const out: NormalizedRecord[] = []; | |
| 334 | + for (const lot of page.lots) { | |
| 335 | + if (lot.withdrawn) continue; | |
| 336 | + const title = lot.creators && !lot.title.toLowerCase().includes(lot.creators.toLowerCase()) ? `${lot.creators} — ${lot.title}` : lot.title; | |
| 337 | + const categorySlug = classifyTitle(title, hints); | |
| 338 | + if (!categorySlug) continue; | |
| 339 | + const cur = currency(lot.finalCurrency ?? lot.bidCurrency ?? a.currency); | |
| 340 | + if (!cur) continue; | |
| 341 | + const grade = parseGradeFromTitle(title); | |
| 342 | + const isWatch = ['rolex', 'patek_philippe', 'audemars_piguet', 'omega', 'other_watches'].includes(categorySlug); | |
| 343 | + const reference = isWatch ? watchReference(title) : null; | |
| 344 | + const identifiers: Record<string, string> = { sothebys_lot_id: lot.lotId }; | |
| 345 | + if (a.saleNumber) identifiers.sothebys_sale_number = a.saleNumber; | |
| 346 | + if (reference) identifiers.reference = reference; | |
| 347 | + if (categorySlug === 'lego_sets') { | |
| 348 | + const n = legoSetNumber(title); | |
| 349 | + if (n) identifiers.lego_set_number = n; | |
| 350 | + } | |
| 351 | + const base = { | |
| 352 | + connectorId: this.meta.id, | |
| 353 | + sourceId: this.meta.sourceId, | |
| 354 | + sourceUrl: lotUrl(a.url, lot.slug, lot.lotId), | |
| 355 | + externalId: lot.lotId, | |
| 356 | + rawTitle: title, | |
| 357 | + description: null, | |
| 358 | + imageUrls: lot.imageUrl ? [lot.imageUrl] : [], | |
| 359 | + attributes: { | |
| 360 | + categorySlug, | |
| 361 | + name: lot.title, | |
| 362 | + brand: brandFromSlug(categorySlug, title) ?? (isWatch ? lot.creators : null), | |
| 363 | + reference, | |
| 364 | + year: safeYear(title), | |
| 365 | + identifiers, | |
| 366 | + metadata: { auction_id: a.auctionId, sale_number: a.saleNumber, auction_title: a.title, auction_type: a.type, departments: a.departments, estimate_low: lot.estimateLow, estimate_high: lot.estimateHigh, hammer_price: lot.currentBid, bids: lot.numberOfBids }, | |
| 367 | + }, | |
| 368 | + grade: { grader: grade.grader, grade: grade.grade, qualifier: grade.qualifier, certificationNumber: null }, | |
| 369 | + condition: {}, | |
| 370 | + observedAt: raw.fetchedAt, | |
| 371 | + parserVersion: this.parserVersion, | |
| 372 | + }; | |
| 373 | + const closed = a.state === 'Closed' || lot.isClosed === true; | |
| 374 | + if (closed) { | |
| 375 | + if (!lot.isSold || !lot.finalPrice || lot.finalPrice <= 0) continue; | |
| 376 | + const saleDate = iso(lot.closingTime) ?? iso(a.closedAt) ?? iso(a.endsAt); | |
| 377 | + if (!saleDate || saleDate.getTime() > Date.now() + 86_400_000) continue; | |
| 378 | + out.push( | |
| 379 | + NormalizedSaleSchema.parse({ | |
| 380 | + ...base, | |
| 381 | + kind: 'sale', | |
| 382 | + confidence: 0.9, | |
| 383 | + saleType: 'auction', | |
| 384 | + saleDate, | |
| 385 | + price: lot.finalPrice, | |
| 386 | + currency: cur, | |
| 387 | + buyerPremiumIncluded: true, | |
| 388 | + quantity: 1, | |
| 389 | + isBundle: isBundleTitle(title), | |
| 390 | + location: a.location, | |
| 391 | + auctionHouse: "Sotheby's", | |
| 392 | + lotNumber: lot.lotNumber, | |
| 393 | + }), | |
| 394 | + ); | |
| 395 | + } else { | |
| 396 | + const startsAt = iso(a.startsAt); | |
| 397 | + out.push( | |
| 398 | + NormalizedAuctionLotSchema.parse({ | |
| 399 | + ...base, | |
| 400 | + kind: 'auction_lot', | |
| 401 | + confidence: 0.85, | |
| 402 | + auctionHouse: "Sotheby's", | |
| 403 | + auctionName: a.title, | |
| 404 | + lotNumber: lot.lotNumber, | |
| 405 | + startsAt, | |
| 406 | + endsAt: iso(lot.closingTime) ?? iso(a.endsAt), | |
| 407 | + estimateLow: lot.estimateLow, | |
| 408 | + estimateHigh: lot.estimateHigh, | |
| 409 | + currentBid: lot.currentBid, | |
| 410 | + currency: cur, | |
| 411 | + status: a.state === 'Opened' && startsAt && startsAt.getTime() <= Date.now() ? 'live' : 'upcoming', | |
| 412 | + location: a.location, | |
| 413 | + }), | |
| 414 | + ); | |
| 415 | + } | |
| 416 | + } | |
| 417 | + return out; | |
| 418 | + } | |
| 419 | +} | |
added
connectors/api/sothebys/meta.json
+36 −0
@@ -0,0 +1,36 @@ | ||
| 1 | +{ | |
| 2 | + "id": "sothebys", | |
| 3 | + "displayName": "Sotheby's (auction results & upcoming lots)", | |
| 4 | + "sourceId": "sothebys", | |
| 5 | + "sourceName": "Sotheby's", | |
| 6 | + "sourceType": "auction_house", | |
| 7 | + "sourceUrl": "https://www.sothebys.com", | |
| 8 | + "module": "api/sothebys", | |
| 9 | + "enginePriority": ["api", "firecrawl"], | |
| 10 | + "categories": ["rolex", "patek_philippe", "audemars_piguet", "omega", "other_watches", "luxury_handbags", "jewelry", "gemstones", "wine", "whisky", "cognac", "sneakers", "fashion_streetwear", "pokemon", "magic_the_gathering", "basketball_cards", "baseball_cards", "football_cards", "sports_memorabilia", "marvel_comics", "dc_comics", "independent_comics", "art", "contemporary_art", "photography", "books", "maps", "historical_documents", "coins", "banknotes", "design_furniture", "antiques", "automobiles", "space", "scientific_instruments", "fossils", "minerals", "meteorites", "music_memorabilia", "movie_memorabilia", "video_games", "vintage_toys"], | |
| 11 | + "regions": ["US", "GB", "HK", "FR", "CH"], | |
| 12 | + "languages": ["en"], | |
| 13 | + "currency": ["USD", "GBP", "HKD", "EUR", "CHF"], | |
| 14 | + "supportsListings": false, | |
| 15 | + "supportsSold": true, | |
| 16 | + "supportsAuctions": true, | |
| 17 | + "supportsImages": true, | |
| 18 | + "supportsCatalog": false, | |
| 19 | + "supportsPopulation": false, | |
| 20 | + "supportsLookup": true, | |
| 21 | + "refreshFrequencyMinutes": 360, | |
| 22 | + "priority": "high", | |
| 23 | + "trustScore": 0.9, | |
| 24 | + "attributionRequired": true, | |
| 25 | + "termsUrl": "https://www.sothebys.com/en/terms-conditions", | |
| 26 | + "accessNotes": "Auction pages https://www.sothebys.com/en/buy/auction/<year>/<slug> are server-rendered (__NEXT_DATA__ Apollo cache) with auction metadata, department names, currency, dates and the first 48 lot cards including estimates and, for closed sales, the visible result (BidState.sold.premiums.finalPriceV2 = price including buyer's premium, currentBidV2 = hammer). Remaining lots are paged with the same public GraphQL endpoint the page uses (clientapi.prod.sothelabs.com/graphql, query LotCardsFilterByPaginated, no authentication; we request only public lot-card fields). Auction discovery: links on the public /en/results and /en/calendar pages (rendered through Firecrawl, 1 credit each), plus config.seeds auction URLs; auctions seen while open are re-checked after they close so their results are captured. robots.txt disallows /bsp-api/* and PDFs — not used. Prices: finalPriceV2 (buyer's premium included) → buyerPremiumIncluded=true, hammer kept in metadata; sale date = lot closingTime or the auction's closed timestamp. Condition reports are behind login and are not fetched.", | |
| 27 | + "enabled": true, | |
| 28 | + "schemaVersion": "1.0", | |
| 29 | + "config": { | |
| 30 | + "seeds": [], | |
| 31 | + "discoveryPages": ["https://www.sothebys.com/en/results", "https://www.sothebys.com/en/calendar"], | |
| 32 | + "departments": [], | |
| 33 | + "maxAuctionsPerRun": 25, | |
| 34 | + "pageSize": 48 | |
| 35 | + } | |
| 36 | +} | |
modified
connectors/registry.json
+528 −28
@@ -5,7 +5,7 @@ | ||
| 5 | 5 | "id": "aucfree", |
| 6 | 6 | "displayName": "aucfree (Yahoo! Auctions Japan closed lots)", |
| 7 | 7 | "sourceId": "aucfree", |
| 8 | − "sourceName": "aucfree \u2014 \u30aa\u30fc\u30af\u30d5\u30ea\u30fc", | |
| 8 | + "sourceName": "aucfree — オークフリー", | |
| 9 | 9 | "sourceType": "analytics_provider", |
| 10 | 10 | "sourceUrl": "https://aucfree.com", |
| 11 | 11 | "module": "firecrawl/aucfree", |
@@ -43,43 +43,43 @@ | ||
| 43 | 43 | "trustScore": 0.75, |
| 44 | 44 | "attributionRequired": true, |
| 45 | 45 | "termsUrl": "https://aucfree.com/about", |
| 46 | − "accessNotes": "aucfree.com publishes closed Yahoo! Auctions Japan lots (end price, bid count, end date) free of charge; no robots.txt is served (404) so no path is disallowed. Plain HTTPS returns 403 to non-browser clients, so pages are fetched through Firecrawl (1 credit per search page of 50 lots \u2248 0.02 credit/sale) with Scrapfly as fallback. Search pages per keyword seed (`/search?o=t2&q=<kw>&p=N`, sorted by end date). Prices are JPY hammer prices without buyer premium; dates are the lot end dates (Japanese '2026\u5e749\u67086\u65e5' format). Identification is title-only (Japanese titles) \u2192 confidence 0.7; PSA/BGS grades parsed from the title. Only market data is stored; item pages, seller and bidder data are not fetched.", | |
| 46 | + "accessNotes": "aucfree.com publishes closed Yahoo! Auctions Japan lots (end price, bid count, end date) free of charge; no robots.txt is served (404) so no path is disallowed. Plain HTTPS returns 403 to non-browser clients, so pages are fetched through Firecrawl (1 credit per search page of 50 lots ≈ 0.02 credit/sale) with Scrapfly as fallback. Search pages per keyword seed (`/search?o=t2&q=<kw>&p=N`, sorted by end date). Prices are JPY hammer prices without buyer premium; dates are the lot end dates (Japanese '2026年9月6日' format). Identification is title-only (Japanese titles) → confidence 0.7; PSA/BGS grades parsed from the title. Only market data is stored; item pages, seller and bidder data are not fetched.", | |
| 47 | 47 | "enabled": true, |
| 48 | 48 | "schemaVersion": "1.0", |
| 49 | 49 | "config": { |
| 50 | 50 | "seeds": [ |
| 51 | 51 | { |
| 52 | − "q": "\u30dd\u30b1\u30e2\u30f3\u30ab\u30fc\u30c9 PSA10", | |
| 52 | + "q": "ポケモンカード PSA10", | |
| 53 | 53 | "category": "pokemon", |
| 54 | 54 | "language": "Japanese" |
| 55 | 55 | }, |
| 56 | 56 | { |
| 57 | − "q": "\u30dd\u30b1\u30e2\u30f3\u30ab\u30fc\u30c9 \u65e7\u88cf PSA", | |
| 57 | + "q": "ポケモンカード 旧裏 PSA", | |
| 58 | 58 | "category": "pokemon", |
| 59 | 59 | "language": "Japanese" |
| 60 | 60 | }, |
| 61 | 61 | { |
| 62 | − "q": "\u904a\u622f\u738b PSA10", | |
| 62 | + "q": "遊戯王 PSA10", | |
| 63 | 63 | "category": "yugioh", |
| 64 | 64 | "language": "Japanese" |
| 65 | 65 | }, |
| 66 | 66 | { |
| 67 | − "q": "\u30ef\u30f3\u30d4\u30fc\u30b9\u30ab\u30fc\u30c9 PSA10", | |
| 67 | + "q": "ワンピースカード PSA10", | |
| 68 | 68 | "category": "one_piece_card_game", |
| 69 | 69 | "language": "Japanese" |
| 70 | 70 | }, |
| 71 | 71 | { |
| 72 | − "q": "\u30ac\u30f3\u30d7\u30e9 MG \u672a\u7d44\u7acb", | |
| 72 | + "q": "ガンプラ MG 未組立", | |
| 73 | 73 | "category": "gundam", |
| 74 | 74 | "language": null |
| 75 | 75 | }, |
| 76 | 76 | { |
| 77 | − "q": "figma \u65b0\u54c1", | |
| 77 | + "q": "figma 新品", | |
| 78 | 78 | "category": "action_figures", |
| 79 | 79 | "language": null |
| 80 | 80 | }, |
| 81 | 81 | { |
| 82 | − "q": "\u30d5\u30a1\u30df\u30b3\u30f3 \u672a\u958b\u5c01", | |
| 82 | + "q": "ファミコン 未開封", | |
| 83 | 83 | "category": "nintendo_games", |
| 84 | 84 | "language": null |
| 85 | 85 | }, |
@@ -92,6 +92,129 @@ | ||
| 92 | 92 | "pagesPerSeed": 2 |
| 93 | 93 | } |
| 94 | 94 | }, |
| 95 | + { | |
| 96 | + "id": "bonhams", | |
| 97 | + "displayName": "Bonhams (auction results & upcoming lots)", | |
| 98 | + "sourceId": "bonhams", | |
| 99 | + "sourceName": "Bonhams", | |
| 100 | + "sourceType": "auction_house", | |
| 101 | + "sourceUrl": "https://www.bonhams.com", | |
| 102 | + "module": "api/bonhams", | |
| 103 | + "enginePriority": [ | |
| 104 | + "api" | |
| 105 | + ], | |
| 106 | + "categories": [ | |
| 107 | + "rolex", | |
| 108 | + "patek_philippe", | |
| 109 | + "audemars_piguet", | |
| 110 | + "omega", | |
| 111 | + "other_watches", | |
| 112 | + "wine", | |
| 113 | + "whisky", | |
| 114 | + "coins", | |
| 115 | + "banknotes", | |
| 116 | + "medals", | |
| 117 | + "automobiles", | |
| 118 | + "motorcycles", | |
| 119 | + "automotive_memorabilia", | |
| 120 | + "luxury_handbags", | |
| 121 | + "fashion_streetwear", | |
| 122 | + "jewelry", | |
| 123 | + "movie_memorabilia", | |
| 124 | + "music_memorabilia", | |
| 125 | + "musical_instruments", | |
| 126 | + "movie_posters", | |
| 127 | + "vintage_toys", | |
| 128 | + "sports_memorabilia", | |
| 129 | + "books", | |
| 130 | + "maps", | |
| 131 | + "photography", | |
| 132 | + "art", | |
| 133 | + "contemporary_art", | |
| 134 | + "clocks", | |
| 135 | + "silver", | |
| 136 | + "glass_crystal", | |
| 137 | + "porcelain", | |
| 138 | + "scientific_instruments", | |
| 139 | + "stamps", | |
| 140 | + "fossils", | |
| 141 | + "minerals", | |
| 142 | + "meteorites", | |
| 143 | + "militaria", | |
| 144 | + "design_furniture", | |
| 145 | + "antiques" | |
| 146 | + ], | |
| 147 | + "regions": [ | |
| 148 | + "GB", | |
| 149 | + "US", | |
| 150 | + "HK", | |
| 151 | + "FR", | |
| 152 | + "AU" | |
| 153 | + ], | |
| 154 | + "languages": [ | |
| 155 | + "en" | |
| 156 | + ], | |
| 157 | + "currency": [ | |
| 158 | + "GBP", | |
| 159 | + "USD", | |
| 160 | + "HKD", | |
| 161 | + "EUR", | |
| 162 | + "AUD", | |
| 163 | + "CHF" | |
| 164 | + ], | |
| 165 | + "supportsListings": false, | |
| 166 | + "supportsSold": true, | |
| 167 | + "supportsAuctions": true, | |
| 168 | + "supportsImages": true, | |
| 169 | + "supportsCatalog": false, | |
| 170 | + "supportsPopulation": false, | |
| 171 | + "supportsLookup": true, | |
| 172 | + "refreshFrequencyMinutes": 360, | |
| 173 | + "priority": "high", | |
| 174 | + "trustScore": 0.9, | |
| 175 | + "attributionRequired": true, | |
| 176 | + "termsUrl": "https://www.bonhams.com/legals/terms-of-use/", | |
| 177 | + "accessNotes": "Plain HTTPS (no rendering, no credits). Public results listing https://www.bonhams.com/auctions/results/?page=N and upcoming listing /auctions/upcoming/ are server-rendered Next.js pages whose __NEXT_DATA__ carries 24 auctions per page (11k+ past auctions); each auction page /auction/<id>/<slug>/?page=N carries 48 lots per page with estimates, hammer price, price including buyer's premium (hammerPremium), status, currency, department and end date. bonhams.com/robots.txt only disallows /ldc/, /vms-assets/, */aggregate$ and */head_image* — none used. Prices: we store hammerPremium (hammer + buyer's premium as published by Bonhams) as the sale price with buyerPremiumIncluded=true and keep the hammer price in metadata. Sale date = the lot's hammerTime / auction end date from the source. Departments outside the configured whitelist are skipped, not guessed.", | |
| 178 | + "enabled": true, | |
| 179 | + "schemaVersion": "1.0", | |
| 180 | + "config": { | |
| 181 | + "departments": [ | |
| 182 | + "Watches", | |
| 183 | + "Wine", | |
| 184 | + "Whisky", | |
| 185 | + "Coins, Medals and Banknotes", | |
| 186 | + "Cars", | |
| 187 | + "Motorcycles", | |
| 188 | + "Automobilia", | |
| 189 | + "Designer Handbags & Fashion", | |
| 190 | + "Jewellery", | |
| 191 | + "Popular Culture", | |
| 192 | + "Sporting Memorabilia", | |
| 193 | + "Books & Manuscripts", | |
| 194 | + "Photographs", | |
| 195 | + "Prints & Multiples", | |
| 196 | + "Post-War and Contemporary Art", | |
| 197 | + "Clocks", | |
| 198 | + "Silver", | |
| 199 | + "Glass", | |
| 200 | + "Scientific Instruments", | |
| 201 | + "Stamps, Covers & Postal History", | |
| 202 | + "Natural History", | |
| 203 | + "Arms and Armour", | |
| 204 | + "Modern Decorative Art & Design", | |
| 205 | + "Impressionist and Modern Art", | |
| 206 | + "Modern British & Irish Art", | |
| 207 | + "European Ceramics", | |
| 208 | + "British Ceramics", | |
| 209 | + "Travel & Exploration", | |
| 210 | + "Home and Interiors" | |
| 211 | + ], | |
| 212 | + "maxResultsPages": 20, | |
| 213 | + "maxAuctionsPerRun": 40, | |
| 214 | + "upcomingAuctionsPerRun": 12, | |
| 215 | + "lotsPerPage": 48 | |
| 216 | + } | |
| 217 | + }, | |
| 95 | 218 | { |
| 96 | 219 | "id": "brickeconomy", |
| 97 | 220 | "displayName": "BrickEconomy", |
@@ -129,7 +252,7 @@ | ||
| 129 | 252 | "trustScore": 0.65, |
| 130 | 253 | "attributionRequired": true, |
| 131 | 254 | "termsUrl": "https://www.brickeconomy.com/legal-terms", |
| 132 | − "accessNotes": "Public set pages fetched through Firecrawl (markdown; ~1 credit/page). robots.txt allows all crawlers (explicitly including AI bots). Plain HTTPS returns 403 for non-browser agents, so Firecrawl is the primary engine and Scrapfly the fallback. We capture set facts (number, name, theme, subtheme, year, release/retire dates, pieces, minifigs), retail price, and BrickEconomy's estimated New/Sealed and Used values as guide observations \u2014 never as sales. Discovery via theme/top lists in config.seeds.", | |
| 255 | + "accessNotes": "Public set pages fetched through Firecrawl (markdown; ~1 credit/page). robots.txt allows all crawlers (explicitly including AI bots). Plain HTTPS returns 403 for non-browser agents, so Firecrawl is the primary engine and Scrapfly the fallback. We capture set facts (number, name, theme, subtheme, year, release/retire dates, pieces, minifigs), retail price, and BrickEconomy's estimated New/Sealed and Used values as guide observations — never as sales. Discovery via theme/top lists in config.seeds.", | |
| 133 | 256 | "enabled": true, |
| 134 | 257 | "schemaVersion": "1.0", |
| 135 | 258 | "config": { |
@@ -184,7 +307,7 @@ | ||
| 184 | 307 | "trustScore": 0.85, |
| 185 | 308 | "attributionRequired": true, |
| 186 | 309 | "termsUrl": "https://brickset.com/about", |
| 187 | − "accessNotes": "Public set pages (brickset.com/sets/<number>-1/...) and theme listings (/sets/theme-<Theme>/page-N, 25 sets per page) fetched over plain HTTPS with the RareIndex user agent; robots.txt disallows /admin, /export, /ajax, /profile, /webservices, /buy, /news, /reviews\u2026 \u2014 none of which are used (the Brickset API/webservices need a personal key: https://brickset.com/tools/webservices/requestkey). Fields parsed from the set page definition list: pieces, minifigs, RRP (GBP + USD), launch/exit dates, availability, packaging, barcodes (UPC/EAN), theme/subtheme and the 'Current value' New/Used estimates that Brickset derives from BrickLink \u2014 stored as guide_value observations (USD, confidence 0.65). 1.5 s politeness delay.", | |
| 310 | + "accessNotes": "Public set pages (brickset.com/sets/<number>-1/...) and theme listings (/sets/theme-<Theme>/page-N, 25 sets per page) fetched over plain HTTPS with the RareIndex user agent; robots.txt disallows /admin, /export, /ajax, /profile, /webservices, /buy, /news, /reviews… — none of which are used (the Brickset API/webservices need a personal key: https://brickset.com/tools/webservices/requestkey). Fields parsed from the set page definition list: pieces, minifigs, RRP (GBP + USD), launch/exit dates, availability, packaging, barcodes (UPC/EAN), theme/subtheme and the 'Current value' New/Used estimates that Brickset derives from BrickLink — stored as guide_value observations (USD, confidence 0.65). 1.5 s politeness delay.", | |
| 188 | 311 | "enabled": true, |
| 189 | 312 | "schemaVersion": "1.0", |
| 190 | 313 | "config": { |
@@ -209,6 +332,284 @@ | ||
| 209 | 332 | "setsPerRun": 120 |
| 210 | 333 | } |
| 211 | 334 | }, |
| 335 | + { | |
| 336 | + "id": "catawiki", | |
| 337 | + "displayName": "Catawiki (closed-lot results & live lots)", | |
| 338 | + "sourceId": "catawiki", | |
| 339 | + "sourceName": "Catawiki", | |
| 340 | + "sourceType": "auction_house", | |
| 341 | + "sourceUrl": "https://www.catawiki.com", | |
| 342 | + "module": "scrapfly/catawiki", | |
| 343 | + "enginePriority": [ | |
| 344 | + "scrapfly" | |
| 345 | + ], | |
| 346 | + "categories": [ | |
| 347 | + "pokemon", | |
| 348 | + "magic_the_gathering", | |
| 349 | + "yugioh", | |
| 350 | + "one_piece_card_game", | |
| 351 | + "disney_lorcana", | |
| 352 | + "other_tcg", | |
| 353 | + "basketball_cards", | |
| 354 | + "baseball_cards", | |
| 355 | + "football_cards", | |
| 356 | + "hockey_cards", | |
| 357 | + "soccer_cards", | |
| 358 | + "f1_cards", | |
| 359 | + "non_sport_cards", | |
| 360 | + "rolex", | |
| 361 | + "patek_philippe", | |
| 362 | + "audemars_piguet", | |
| 363 | + "omega", | |
| 364 | + "other_watches", | |
| 365 | + "pens", | |
| 366 | + "lighters", | |
| 367 | + "marvel_comics", | |
| 368 | + "dc_comics", | |
| 369 | + "independent_comics", | |
| 370 | + "manga", | |
| 371 | + "animation_art", | |
| 372 | + "lego_sets", | |
| 373 | + "funko", | |
| 374 | + "model_cars", | |
| 375 | + "model_trains", | |
| 376 | + "action_figures", | |
| 377 | + "vintage_toys", | |
| 378 | + "designer_toys", | |
| 379 | + "dolls", | |
| 380 | + "plush", | |
| 381 | + "video_games", | |
| 382 | + "coins", | |
| 383 | + "banknotes", | |
| 384 | + "stamps", | |
| 385 | + "medals", | |
| 386 | + "wine", | |
| 387 | + "whisky", | |
| 388 | + "rum", | |
| 389 | + "cognac", | |
| 390 | + "music", | |
| 391 | + "movie_posters", | |
| 392 | + "cameras", | |
| 393 | + "sports_memorabilia", | |
| 394 | + "art", | |
| 395 | + "contemporary_art", | |
| 396 | + "photography", | |
| 397 | + "jewelry", | |
| 398 | + "gemstones", | |
| 399 | + "luxury_handbags", | |
| 400 | + "sneakers", | |
| 401 | + "fashion_streetwear", | |
| 402 | + "automobiles", | |
| 403 | + "motorcycles", | |
| 404 | + "automotive_memorabilia", | |
| 405 | + "books", | |
| 406 | + "maps", | |
| 407 | + "historical_documents", | |
| 408 | + "fossils", | |
| 409 | + "minerals", | |
| 410 | + "meteorites", | |
| 411 | + "antiques", | |
| 412 | + "design_furniture" | |
| 413 | + ], | |
| 414 | + "regions": [ | |
| 415 | + "NL", | |
| 416 | + "EU" | |
| 417 | + ], | |
| 418 | + "languages": [ | |
| 419 | + "en" | |
| 420 | + ], | |
| 421 | + "currency": [ | |
| 422 | + "EUR" | |
| 423 | + ], | |
| 424 | + "supportsListings": false, | |
| 425 | + "supportsSold": true, | |
| 426 | + "supportsAuctions": true, | |
| 427 | + "supportsImages": true, | |
| 428 | + "supportsCatalog": false, | |
| 429 | + "supportsPopulation": false, | |
| 430 | + "supportsLookup": true, | |
| 431 | + "refreshFrequencyMinutes": 240, | |
| 432 | + "priority": "high", | |
| 433 | + "trustScore": 0.8, | |
| 434 | + "attributionRequired": true, | |
| 435 | + "termsUrl": "https://www.catawiki.com/en/help/terms-of-use", | |
| 436 | + "accessNotes": "Scrapfly (asp, NL exit) because catawiki.com returns 403 to non-browser clients. Two-phase crawl: (1) discovery — a rendered category page (render_js, ~6 credits) lists the live themed auctions of the category; each auction page /en/a/<id>-slug is server-rendered (__NEXT_DATA__, 1 credit, no JS) with its full lot list and closeAt; live lots are emitted as auction_lot records and remembered in the cursor; (2) harvest — after an auction closes, each remembered lot page /en/l/<id>-slug (1 credit, no JS) exposes biddingBlockResponse {closed, sold, final bid in EUR, biddingEndTime} plus title/subtitle/specifications/expert estimate/images/seller country, and sold lots become sale records. Robots (via Scrapfly): /*/c/*/* and *lot_id are disallowed — we only use single-segment category URLs, auction pages and lot pages, never the lot_id query. Prices: Catawiki's final bid is the hammer; the buyer pays an additional ~9% buyer protection fee, so buyerPremiumIncluded=false (fee noted in metadata). Sale date = biddingEndTime from the source. Unsold closed lots are discarded.", | |
| 437 | + "enabled": true, | |
| 438 | + "schemaVersion": "1.0", | |
| 439 | + "config": { | |
| 440 | + "seeds": [ | |
| 441 | + { | |
| 442 | + "id": 725, | |
| 443 | + "path": "725-trading-cards", | |
| 444 | + "hint": "cards" | |
| 445 | + }, | |
| 446 | + { | |
| 447 | + "id": 299, | |
| 448 | + "path": "299-watches-pens-lighters", | |
| 449 | + "hint": "watches" | |
| 450 | + }, | |
| 451 | + { | |
| 452 | + "id": 139, | |
| 453 | + "path": "139-comics-animation", | |
| 454 | + "hint": "comics" | |
| 455 | + }, | |
| 456 | + { | |
| 457 | + "id": 363, | |
| 458 | + "path": "363-toys-models", | |
| 459 | + "hint": "toys" | |
| 460 | + }, | |
| 461 | + { | |
| 462 | + "id": 165, | |
| 463 | + "path": "165-coins-stamps", | |
| 464 | + "hint": "coins" | |
| 465 | + }, | |
| 466 | + { | |
| 467 | + "id": 720, | |
| 468 | + "path": "720-wine-whisky-spirits", | |
| 469 | + "hint": "wine" | |
| 470 | + }, | |
| 471 | + { | |
| 472 | + "id": 347, | |
| 473 | + "path": "347-music-movies-cameras", | |
| 474 | + "hint": "music" | |
| 475 | + }, | |
| 476 | + { | |
| 477 | + "id": 1097, | |
| 478 | + "path": "1097-sports", | |
| 479 | + "hint": "sports" | |
| 480 | + }, | |
| 481 | + { | |
| 482 | + "id": 714, | |
| 483 | + "path": "714-jewellery-precious-stones", | |
| 484 | + "hint": "jewelry" | |
| 485 | + }, | |
| 486 | + { | |
| 487 | + "id": 721, | |
| 488 | + "path": "721-fashion", | |
| 489 | + "hint": "fashion" | |
| 490 | + }, | |
| 491 | + { | |
| 492 | + "id": 85, | |
| 493 | + "path": "85-art", | |
| 494 | + "hint": "art" | |
| 495 | + }, | |
| 496 | + { | |
| 497 | + "id": 708, | |
| 498 | + "path": "708-classic-cars-motorcycles-automobilia", | |
| 499 | + "hint": "cars" | |
| 500 | + }, | |
| 501 | + { | |
| 502 | + "id": 863, | |
| 503 | + "path": "863-archaeology-natural-history", | |
| 504 | + "hint": "natural_history" | |
| 505 | + }, | |
| 506 | + { | |
| 507 | + "id": 1099, | |
| 508 | + "path": "1099-books-historical-memorabilia", | |
| 509 | + "hint": "books" | |
| 510 | + } | |
| 511 | + ], | |
| 512 | + "maxNewAuctionsPerRun": 30, | |
| 513 | + "maxLotFetchesPerRun": 400, | |
| 514 | + "pendingCap": 6000, | |
| 515 | + "harvestDelayMinutes": 20 | |
| 516 | + } | |
| 517 | + }, | |
| 518 | + { | |
| 519 | + "id": "christies", | |
| 520 | + "displayName": "Christie's (auction results)", | |
| 521 | + "sourceId": "christies", | |
| 522 | + "sourceName": "Christie's", | |
| 523 | + "sourceType": "auction_house", | |
| 524 | + "sourceUrl": "https://www.christies.com", | |
| 525 | + "module": "api/christies", | |
| 526 | + "enginePriority": [ | |
| 527 | + "api" | |
| 528 | + ], | |
| 529 | + "categories": [ | |
| 530 | + "rolex", | |
| 531 | + "patek_philippe", | |
| 532 | + "audemars_piguet", | |
| 533 | + "omega", | |
| 534 | + "other_watches", | |
| 535 | + "luxury_handbags", | |
| 536 | + "jewelry", | |
| 537 | + "gemstones", | |
| 538 | + "wine", | |
| 539 | + "whisky", | |
| 540 | + "cognac", | |
| 541 | + "art", | |
| 542 | + "contemporary_art", | |
| 543 | + "photography", | |
| 544 | + "books", | |
| 545 | + "maps", | |
| 546 | + "historical_documents", | |
| 547 | + "antiques", | |
| 548 | + "design_furniture", | |
| 549 | + "scientific_instruments", | |
| 550 | + "fossils", | |
| 551 | + "minerals", | |
| 552 | + "meteorites", | |
| 553 | + "sports_memorabilia", | |
| 554 | + "movie_memorabilia", | |
| 555 | + "music_memorabilia", | |
| 556 | + "sneakers", | |
| 557 | + "vintage_toys", | |
| 558 | + "automobiles" | |
| 559 | + ], | |
| 560 | + "regions": [ | |
| 561 | + "US", | |
| 562 | + "GB", | |
| 563 | + "HK", | |
| 564 | + "FR", | |
| 565 | + "CH" | |
| 566 | + ], | |
| 567 | + "languages": [ | |
| 568 | + "en" | |
| 569 | + ], | |
| 570 | + "currency": [ | |
| 571 | + "USD", | |
| 572 | + "GBP", | |
| 573 | + "HKD", | |
| 574 | + "EUR", | |
| 575 | + "CHF" | |
| 576 | + ], | |
| 577 | + "supportsListings": false, | |
| 578 | + "supportsSold": true, | |
| 579 | + "supportsAuctions": false, | |
| 580 | + "supportsImages": true, | |
| 581 | + "supportsCatalog": false, | |
| 582 | + "supportsPopulation": false, | |
| 583 | + "supportsLookup": false, | |
| 584 | + "refreshFrequencyMinutes": 720, | |
| 585 | + "priority": "high", | |
| 586 | + "trustScore": 0.9, | |
| 587 | + "attributionRequired": true, | |
| 588 | + "termsUrl": "https://www.christies.com/en/help/terms-and-conditions", | |
| 589 | + "accessNotes": "Plain HTTPS JSON (no rendering, no credits) from the two endpoints the public christies.com pages themselves call: /api/discoverywebsite/auctioncalendar/auctionresults?language=en&month=M&year=Y (closed sales of a month with SaleID/SaleNumber, category/location filters and sale totals) and /api/discoverywebsite/auctionpages/lotsearch?language=en&SaleNumber=…&SaleId=…&page=N&pageSize=…&sortby=lotnumber (lots with estimate, price_realised, dates, image, lot url; max ~84 lots per page). christies.com/robots.txt (User-agent: *) disallows */search, */AjaxPages, */lotimages, */mychristies and similar — none of these paths are used. Prices realised are published by Christie's inclusive of buyer's premium → buyerPremiumIncluded=true; currency comes from price_realised_txt (e.g. 'GBP 190,500'); sale date = the lot's end_date. Categories come from the sale's category filter labels plus title keywords; unmapped lots keep the family suggested by the sale category. Upcoming lots are not exposed by these endpoints (calendar of future sales is a different client app), so supportsAuctions=false. Note: christies.com's edge drops requests whose User-Agent contains a URL or an e-mail address, so the connector identifies itself as 'RareIndex/0.1 (market data research; contact data at rareindex.io)' — no browser impersonation.", | |
| 590 | + "enabled": true, | |
| 591 | + "schemaVersion": "1.0", | |
| 592 | + "config": { | |
| 593 | + "categoryLabels": [ | |
| 594 | + "Jewellery, Watches & Handbags", | |
| 595 | + "Wines & Spirits", | |
| 596 | + "Collectibles", | |
| 597 | + "Books & Manuscripts", | |
| 598 | + "Science and Natural History", | |
| 599 | + "Photographs & Prints", | |
| 600 | + "Fine Art", | |
| 601 | + "Furniture & Decorative Art", | |
| 602 | + "Antiquities", | |
| 603 | + "Asian Art", | |
| 604 | + "Design", | |
| 605 | + "Cars" | |
| 606 | + ], | |
| 607 | + "monthsPerRun": 2, | |
| 608 | + "backfillMonths": 36, | |
| 609 | + "maxSalesPerRun": 30, | |
| 610 | + "pageSize": 84 | |
| 611 | + } | |
| 612 | + }, | |
| 212 | 613 | { |
| 213 | 614 | "id": "chrono24", |
| 214 | 615 | "displayName": "Chrono24", |
@@ -250,7 +651,7 @@ | ||
| 250 | 651 | "trustScore": 0.7, |
| 251 | 652 | "attributionRequired": true, |
| 252 | 653 | "termsUrl": "https://www.chrono24.com/info/terms-of-use.htm", |
| 253 | − "accessNotes": "Public model listing pages (e.g. /rolex/daytona--mod2.htm) fetched through Scrapfly without JS rendering (Cloudflare shield \u2192 ~40 credits/page); robots.txt allows these paths (Crawl-delay 0.1). Each page embeds a schema.org ItemList of Offers (name, price in the site currency, image, listing URL) \u2014 we store asking prices as listings only, never as sales. No login, no per-listing detail fetch (seller details stay on Chrono24). Model pages are configured in config.seeds; pagination via --modN-P.htm.", | |
| 654 | + "accessNotes": "Public model listing pages (e.g. /rolex/daytona--mod2.htm) fetched through Scrapfly without JS rendering (Cloudflare shield → ~40 credits/page); robots.txt allows these paths (Crawl-delay 0.1). Each page embeds a schema.org ItemList of Offers (name, price in the site currency, image, listing URL) — we store asking prices as listings only, never as sales. No login, no per-listing detail fetch (seller details stay on Chrono24). Model pages are configured in config.seeds; pagination via --modN-P.htm.", | |
| 254 | 655 | "enabled": true, |
| 255 | 656 | "schemaVersion": "1.0", |
| 256 | 657 | "config": { |
@@ -316,7 +717,7 @@ | ||
| 316 | 717 | "trustScore": 0.9, |
| 317 | 718 | "attributionRequired": true, |
| 318 | 719 | "termsUrl": "https://www.comicconnect.com/terms", |
| 319 | − "accessNotes": "Public sold archive (/browse/comics/?filtertype=Sold, ~479k results, 20 per page) fetched over plain HTTPS with the RareIndex user agent. robots.txt: Allow / with Content-Signal search=yes, ai-train=no (we only index sale facts and link back). Each card exposes title, publisher + grade, sold date/time, 'Sold For' price and whether a 15% buyer's premium applies (bp attribute) \u2014 we store hammer price with buyer_premium_included=false and keep the premium note in metadata. No login, no bidder data. 1.5 s politeness delay.", | |
| 720 | + "accessNotes": "Public sold archive (/browse/comics/?filtertype=Sold, ~479k results, 20 per page) fetched over plain HTTPS with the RareIndex user agent. robots.txt: Allow / with Content-Signal search=yes, ai-train=no (we only index sale facts and link back). Each card exposes title, publisher + grade, sold date/time, 'Sold For' price and whether a 15% buyer's premium applies (bp attribute) — we store hammer price with buyer_premium_included=false and keep the premium note in metadata. No login, no bidder data. 1.5 s politeness delay.", | |
| 320 | 721 | "enabled": true, |
| 321 | 722 | "schemaVersion": "1.0", |
| 322 | 723 | "config": { |
@@ -360,7 +761,7 @@ | ||
| 360 | 761 | "trustScore": 0.85, |
| 361 | 762 | "attributionRequired": true, |
| 362 | 763 | "termsUrl": "https://support.discogs.com/hc/en-us/articles/360009334593-API-Terms-of-Use", |
| 363 | − "accessNotes": "Official public Discogs API (api.discogs.com) used unauthenticated with the RareIndex user agent: database/search (type=master), masters/{id}/versions (pressings with label, catno, country, year, format and community have/want counts) and marketplace/stats/{release_id} (lowest asking price + number for sale). Unauthenticated limit is 25 requests/minute \u2192 2.6 s throttle; price_suggestions requires a personal token and is not used. Marketplace stats have no timestamp: observationDate = fetch date (confidence 0.7). Catalog data is CC0; images are hot-linked thumbnails and attributed to Discogs. Sold-price history is not exposed publicly.", | |
| 764 | + "accessNotes": "Official public Discogs API (api.discogs.com) used unauthenticated with the RareIndex user agent: database/search (type=master), masters/{id}/versions (pressings with label, catno, country, year, format and community have/want counts) and marketplace/stats/{release_id} (lowest asking price + number for sale). Unauthenticated limit is 25 requests/minute → 2.6 s throttle; price_suggestions requires a personal token and is not used. Marketplace stats have no timestamp: observationDate = fetch date (confidence 0.7). Catalog data is CC0; images are hot-linked thumbnails and attributed to Discogs. Sold-price history is not exposed publicly.", | |
| 364 | 765 | "enabled": true, |
| 365 | 766 | "schemaVersion": "1.0", |
| 366 | 767 | "config": { |
@@ -389,7 +790,7 @@ | ||
| 389 | 790 | "Tyler, The Creator Igor", |
| 390 | 791 | "Frank Ocean Blonde", |
| 391 | 792 | "Arctic Monkeys AM", |
| 392 | − "Bj\u00f6rk Homogenic", | |
| 793 | + "Björk Homogenic", | |
| 393 | 794 | "Kraftwerk Autobahn", |
| 394 | 795 | "Sex Pistols Never Mind The Bollocks", |
| 395 | 796 | "Bruce Springsteen Born To Run", |
@@ -451,7 +852,7 @@ | ||
| 451 | 852 | "trustScore": 0.9, |
| 452 | 853 | "attributionRequired": true, |
| 453 | 854 | "termsUrl": "https://goldin.co/useragreement", |
| 454 | − "accessNotes": "Public 'Sold Items' result grids (https://goldin.co/buy/sc/<subcategory>?show_only=Sold%20Items&sort=Most_Recent_Bids&number_of_lots=240) rendered through Scrapfly (asp + JS rendering, ~6 credits per page of 240 sold lots). goldin.co/robots.txt allows /buy/ and /item/ and disallows /api/; we never call goldin.co/api ourselves \u2014 the lot data is read from the XHR (lots_v2 on their CloudFront search endpoint) that the public page performs during rendering, exactly what a browser does. Plain HTTP and Firecrawl return the empty SPA shell / an Akamai challenge. Prices: the grid shows the final price INCLUDING buyer's premium (current_price \u00d7 (1 + buyer_premium%)); we store that as the sale price with buyerPremiumIncluded=true and keep the hammer price and BP % in metadata. Sale date = lot end_timestamp; lots whose end_timestamp is in the future (placeholder private-sale dates like 2235-06-04) are skipped and counted as anomalies. Cert numbers appear only in item-page descriptions (lookup).", | |
| 855 | + "accessNotes": "Public 'Sold Items' result grids (https://goldin.co/buy/sc/<subcategory>?show_only=Sold%20Items&sort=Most_Recent_Bids&number_of_lots=240) rendered through Scrapfly (asp + JS rendering, ~6 credits per page of 240 sold lots). goldin.co/robots.txt allows /buy/ and /item/ and disallows /api/; we never call goldin.co/api ourselves — the lot data is read from the XHR (lots_v2 on their CloudFront search endpoint) that the public page performs during rendering, exactly what a browser does. Plain HTTP and Firecrawl return the empty SPA shell / an Akamai challenge. Prices: the grid shows the final price INCLUDING buyer's premium (current_price × (1 + buyer_premium%)); we store that as the sale price with buyerPremiumIncluded=true and keep the hammer price and BP % in metadata. Sale date = lot end_timestamp; lots whose end_timestamp is in the future (placeholder private-sale dates like 2235-06-04) are skipped and counted as anomalies. Cert numbers appear only in item-page descriptions (lookup).", | |
| 455 | 856 | "enabled": true, |
| 456 | 857 | "schemaVersion": "1.0", |
| 457 | 858 | "config": { |
@@ -604,7 +1005,7 @@ | ||
| 604 | 1005 | "trustScore": 0.7, |
| 605 | 1006 | "attributionRequired": true, |
| 606 | 1007 | "termsUrl": "https://novelship.com/terms", |
| 607 | − "accessNotes": "Public Novelship browse pages (novelship.com/sneakers/<brand>?page=N) and product pages fetched over plain HTTPS with the RareIndex user agent; robots.txt only disallows sell/auth/dashboard/pay paths. The server-rendered payload embeds each product's SKU (style code), colorway, retail cost, release date, last sale price, lowest listing price and 180-day sales count \u2014 no login or private endpoint is used. Prices are read as USD (the anonymous international storefront prices in US$; cost_retail matches US retail) with confidence 0.7; per-size asks are not exposed on listing pages. Sizes/stock are not fetched. 1.5 s politeness delay.", | |
| 1008 | + "accessNotes": "Public Novelship browse pages (novelship.com/sneakers/<brand>?page=N) and product pages fetched over plain HTTPS with the RareIndex user agent; robots.txt only disallows sell/auth/dashboard/pay paths. The server-rendered payload embeds each product's SKU (style code), colorway, retail cost, release date, last sale price, lowest listing price and 180-day sales count — no login or private endpoint is used. Prices are read as USD (the anonymous international storefront prices in US$; cost_retail matches US retail) with confidence 0.7; per-size asks are not exposed on listing pages. Sizes/stock are not fetched. 1.5 s politeness delay.", | |
| 608 | 1009 | "enabled": true, |
| 609 | 1010 | "schemaVersion": "1.0", |
| 610 | 1011 | "config": { |
@@ -695,7 +1096,7 @@ | ||
| 695 | 1096 | "trustScore": 0.9, |
| 696 | 1097 | "attributionRequired": true, |
| 697 | 1098 | "termsUrl": "https://www.pcgs.com/legal", |
| 698 | − "accessNotes": "Public PCGS Price Guide category pages (pcgs.com/prices/detail/<series>/<id>/most-active) \u2014 no login required; robots.txt does not restrict /prices. Plain HTTPS is refused by the CDN (403) so pages are rendered through Firecrawl (1 credit per category page \u2248 100 coins \u00d7 10 grades). Values are PCGS retail guide values in USD per grade (columns 4\u202670 and '+' grades), dated with the page's 'Last Update' stamp. Stored as guide_value observations with grader 'pcgs' and grade like MS65 / PR65 / MS65+; PCGS coin numbers are kept as identifiers (pcgs_number). Auction Prices Realized and the Population Report on pcgs.com require a Collectors account and are not fetched.", | |
| 1099 | + "accessNotes": "Public PCGS Price Guide category pages (pcgs.com/prices/detail/<series>/<id>/most-active) — no login required; robots.txt does not restrict /prices. Plain HTTPS is refused by the CDN (403) so pages are rendered through Firecrawl (1 credit per category page ≈ 100 coins × 10 grades). Values are PCGS retail guide values in USD per grade (columns 4…70 and '+' grades), dated with the page's 'Last Update' stamp. Stored as guide_value observations with grader 'pcgs' and grade like MS65 / PR65 / MS65+; PCGS coin numbers are kept as identifiers (pcgs_number). Auction Prices Realized and the Population Report on pcgs.com require a Collectors account and are not fetched.", | |
| 699 | 1100 | "enabled": true, |
| 700 | 1101 | "schemaVersion": "1.0", |
| 701 | 1102 | "config": { |
@@ -770,7 +1171,7 @@ | ||
| 770 | 1171 | "trustScore": 0.95, |
| 771 | 1172 | "attributionRequired": true, |
| 772 | 1173 | "termsUrl": "https://www.phillips.com/about/terms", |
| 773 | − "accessNotes": "Past watch sales are discovered from the public /auctions/past page (plain HTTPS; embedded JSON with saleNumber, title, end date, location). Each sale page is rendered through Firecrawl (JS wait ~6 s, 1 credit) to read the public lot list: lot number, maker, reference, model, estimate and 'Sold For' (Phillips publishes prices realised including buyer's premium). robots.txt disallows only /search and filter paths. No login, no bidder data. Large sales may lazy-load beyond the first ~70 lots \u2014 coverage is recorded per run.", | |
| 1174 | + "accessNotes": "Past watch sales are discovered from the public /auctions/past page (plain HTTPS; embedded JSON with saleNumber, title, end date, location). Each sale page is rendered through Firecrawl (JS wait ~6 s, 1 credit) to read the public lot list: lot number, maker, reference, model, estimate and 'Sold For' (Phillips publishes prices realised including buyer's premium). robots.txt disallows only /search and filter paths. No login, no bidder data. Large sales may lazy-load beyond the first ~70 lots — coverage is recorded per run.", | |
| 774 | 1175 | "enabled": true, |
| 775 | 1176 | "schemaVersion": "1.0", |
| 776 | 1177 | "config": { |
@@ -781,9 +1182,9 @@ | ||
| 781 | 1182 | }, |
| 782 | 1183 | { |
| 783 | 1184 | "id": "pokemontcg", |
| 784 | − "displayName": "Pok\u00e9mon TCG API (pokemontcg.io)", | |
| 1185 | + "displayName": "Pokémon TCG API (pokemontcg.io)", | |
| 785 | 1186 | "sourceId": "pokemontcg", |
| 786 | − "sourceName": "Pok\u00e9mon TCG API", | |
| 1187 | + "sourceName": "Pokémon TCG API", | |
| 787 | 1188 | "sourceType": "catalog", |
| 788 | 1189 | "sourceUrl": "https://pokemontcg.io", |
| 789 | 1190 | "module": "api/pokemontcg", |
@@ -817,7 +1218,7 @@ | ||
| 817 | 1218 | "trustScore": 0.8, |
| 818 | 1219 | "attributionRequired": true, |
| 819 | 1220 | "termsUrl": "https://docs.pokemontcg.io/", |
| 820 | − "accessNotes": "Public REST API v2 (https://api.pokemontcg.io/v2). Optional X-Api-Key (POKEMONTCG_API_KEY) raises limits (20k/day) \u2014 without a key ~1k/day and 30/min. Crawl = sets, then cards per set (pageSize 250, cursor {setIndex,page}). The API is intermittently unavailable (5xx); the connector retries with backoff and falls back to the maintainers' public GitHub mirror (PokemonTCG/pokemon-tcg-data, same card schema, no prices) for the catalog when the API keeps failing. Prices are TCGplayer (USD, per printing variant: normal/holofoil/reverseHolofoil/1stEdition\u2026) and Cardmarket (EUR) daily aggregates with their own updatedAt \u2192 stored as price_observations, never as sales. Pok\u00e9mon \u00a9 Nintendo/Creatures/GAME FREAK; data attributed to pokemontcg.io.", | |
| 1221 | + "accessNotes": "Public REST API v2 (https://api.pokemontcg.io/v2). Optional X-Api-Key (POKEMONTCG_API_KEY) raises limits (20k/day) — without a key ~1k/day and 30/min. Crawl = sets, then cards per set (pageSize 250, cursor {setIndex,page}). The API is intermittently unavailable (5xx); the connector retries with backoff and falls back to the maintainers' public GitHub mirror (PokemonTCG/pokemon-tcg-data, same card schema, no prices) for the catalog when the API keeps failing. Prices are TCGplayer (USD, per printing variant: normal/holofoil/reverseHolofoil/1stEdition…) and Cardmarket (EUR) daily aggregates with their own updatedAt → stored as price_observations, never as sales. Pokémon © Nintendo/Creatures/GAME FREAK; data attributed to pokemontcg.io.", | |
| 821 | 1222 | "enabled": true, |
| 822 | 1223 | "schemaVersion": "1.0", |
| 823 | 1224 | "config": { |
@@ -879,7 +1280,7 @@ | ||
| 879 | 1280 | "trustScore": 0.7, |
| 880 | 1281 | "attributionRequired": true, |
| 881 | 1282 | "termsUrl": "https://www.pricecharting.com/page/terms-of-service", |
| 882 | − "accessNotes": "Public product pages fetched over plain HTTPS with the RareIndex user agent (robots.txt only disallows /buy, /publish-offer, /stripe-connect). Each product page exposes PriceCharting guide values per condition and a table of recently completed eBay sales (date, title, price, eBay item id) \u2014 we store those as sales with the PriceCharting page as source URL. No account, no API key, no photos (TimeWarp is paid and not used). Console listings paginate through the public ?format=json cursor endpoint. ~1 request per product, 1.5 s politeness delay. Trading-card consoles (Pok\u00e9mon, Magic, Yu-Gi-Oh!) are discovered from the public /category/<game>-cards pages; card pages expose guide values and eBay sales per grade (Ungraded, Grade 1\u20139.5, TAG/ACE/SGC/CGC/PSA/BGS 10, BGS 10 Black, CGC 10 Pristine). Graded rows without a named company use the generic grader 'graded' unless the eBay title names it. Pok\u00e9mon sets are mapped to pokemontcg ids/codes through the maintainers' GitHub mirror and Magic sets/cards to Scryfall (one exact-name API lookup per Magic product, \u2264 10 req/s) so sales attach to the API catalogs' canonical assets.", | |
| 1283 | + "accessNotes": "Public product pages fetched over plain HTTPS with the RareIndex user agent (robots.txt only disallows /buy, /publish-offer, /stripe-connect). Each product page exposes PriceCharting guide values per condition and a table of recently completed eBay sales (date, title, price, eBay item id) — we store those as sales with the PriceCharting page as source URL. No account, no API key, no photos (TimeWarp is paid and not used). Console listings paginate through the public ?format=json cursor endpoint. ~1 request per product, 1.5 s politeness delay. Trading-card consoles (Pokémon, Magic, Yu-Gi-Oh!) are discovered from the public /category/<game>-cards pages; card pages expose guide values and eBay sales per grade (Ungraded, Grade 1–9.5, TAG/ACE/SGC/CGC/PSA/BGS 10, BGS 10 Black, CGC 10 Pristine). Graded rows without a named company use the generic grader 'graded' unless the eBay title names it. Pokémon sets are mapped to pokemontcg ids/codes through the maintainers' GitHub mirror and Magic sets/cards to Scryfall (one exact-name API lookup per Magic product, ≤ 10 req/s) so sales attach to the API catalogs' canonical assets.", | |
| 883 | 1284 | "enabled": true, |
| 884 | 1285 | "schemaVersion": "2.0", |
| 885 | 1286 | "config": { |
@@ -1010,7 +1411,7 @@ | ||
| 1010 | 1411 | "trustScore": 0.85, |
| 1011 | 1412 | "attributionRequired": true, |
| 1012 | 1413 | "termsUrl": "https://scryfall.com/docs/api", |
| 1013 | − "accessNotes": "Official public API, no key. Bulk 'default_cards' JSONL (gzip, ~78 MB, refreshed daily) is streamed for the full catalog; single-card lookups use /cards/<set>/<number>. Scryfall asks for \u226410 req/s (we pace 100 ms), an identifying User-Agent and Accept headers. Prices (usd/usd_foil/usd_etched/eur/eur_foil) are Scryfall's daily market aggregates from TCGplayer/Cardmarket \u2192 stored as price_observations, never as sales. Card data \u00a9 Wizards of the Coast; Scryfall requests attribution and no implication of endorsement.", | |
| 1414 | + "accessNotes": "Official public API, no key. Bulk 'default_cards' JSONL (gzip, ~78 MB, refreshed daily) is streamed for the full catalog; single-card lookups use /cards/<set>/<number>. Scryfall asks for ≤10 req/s (we pace 100 ms), an identifying User-Agent and Accept headers. Prices (usd/usd_foil/usd_etched/eur/eur_foil) are Scryfall's daily market aggregates from TCGplayer/Cardmarket → stored as price_observations, never as sales. Card data © Wizards of the Coast; Scryfall requests attribution and no implication of endorsement.", | |
| 1014 | 1415 | "enabled": true, |
| 1015 | 1416 | "schemaVersion": "1.0", |
| 1016 | 1417 | "config": { |
@@ -1018,6 +1419,105 @@ | ||
| 1018 | 1419 | "requestIntervalMs": 100 |
| 1019 | 1420 | } |
| 1020 | 1421 | }, |
| 1422 | + { | |
| 1423 | + "id": "sothebys", | |
| 1424 | + "displayName": "Sotheby's (auction results & upcoming lots)", | |
| 1425 | + "sourceId": "sothebys", | |
| 1426 | + "sourceName": "Sotheby's", | |
| 1427 | + "sourceType": "auction_house", | |
| 1428 | + "sourceUrl": "https://www.sothebys.com", | |
| 1429 | + "module": "api/sothebys", | |
| 1430 | + "enginePriority": [ | |
| 1431 | + "api", | |
| 1432 | + "firecrawl" | |
| 1433 | + ], | |
| 1434 | + "categories": [ | |
| 1435 | + "rolex", | |
| 1436 | + "patek_philippe", | |
| 1437 | + "audemars_piguet", | |
| 1438 | + "omega", | |
| 1439 | + "other_watches", | |
| 1440 | + "luxury_handbags", | |
| 1441 | + "jewelry", | |
| 1442 | + "gemstones", | |
| 1443 | + "wine", | |
| 1444 | + "whisky", | |
| 1445 | + "cognac", | |
| 1446 | + "sneakers", | |
| 1447 | + "fashion_streetwear", | |
| 1448 | + "pokemon", | |
| 1449 | + "magic_the_gathering", | |
| 1450 | + "basketball_cards", | |
| 1451 | + "baseball_cards", | |
| 1452 | + "football_cards", | |
| 1453 | + "sports_memorabilia", | |
| 1454 | + "marvel_comics", | |
| 1455 | + "dc_comics", | |
| 1456 | + "independent_comics", | |
| 1457 | + "art", | |
| 1458 | + "contemporary_art", | |
| 1459 | + "photography", | |
| 1460 | + "books", | |
| 1461 | + "maps", | |
| 1462 | + "historical_documents", | |
| 1463 | + "coins", | |
| 1464 | + "banknotes", | |
| 1465 | + "design_furniture", | |
| 1466 | + "antiques", | |
| 1467 | + "automobiles", | |
| 1468 | + "space", | |
| 1469 | + "scientific_instruments", | |
| 1470 | + "fossils", | |
| 1471 | + "minerals", | |
| 1472 | + "meteorites", | |
| 1473 | + "music_memorabilia", | |
| 1474 | + "movie_memorabilia", | |
| 1475 | + "video_games", | |
| 1476 | + "vintage_toys" | |
| 1477 | + ], | |
| 1478 | + "regions": [ | |
| 1479 | + "US", | |
| 1480 | + "GB", | |
| 1481 | + "HK", | |
| 1482 | + "FR", | |
| 1483 | + "CH" | |
| 1484 | + ], | |
| 1485 | + "languages": [ | |
| 1486 | + "en" | |
| 1487 | + ], | |
| 1488 | + "currency": [ | |
| 1489 | + "USD", | |
| 1490 | + "GBP", | |
| 1491 | + "HKD", | |
| 1492 | + "EUR", | |
| 1493 | + "CHF" | |
| 1494 | + ], | |
| 1495 | + "supportsListings": false, | |
| 1496 | + "supportsSold": true, | |
| 1497 | + "supportsAuctions": true, | |
| 1498 | + "supportsImages": true, | |
| 1499 | + "supportsCatalog": false, | |
| 1500 | + "supportsPopulation": false, | |
| 1501 | + "supportsLookup": true, | |
| 1502 | + "refreshFrequencyMinutes": 360, | |
| 1503 | + "priority": "high", | |
| 1504 | + "trustScore": 0.9, | |
| 1505 | + "attributionRequired": true, | |
| 1506 | + "termsUrl": "https://www.sothebys.com/en/terms-conditions", | |
| 1507 | + "accessNotes": "Auction pages https://www.sothebys.com/en/buy/auction/<year>/<slug> are server-rendered (__NEXT_DATA__ Apollo cache) with auction metadata, department names, currency, dates and the first 48 lot cards including estimates and, for closed sales, the visible result (BidState.sold.premiums.finalPriceV2 = price including buyer's premium, currentBidV2 = hammer). Remaining lots are paged with the same public GraphQL endpoint the page uses (clientapi.prod.sothelabs.com/graphql, query LotCardsFilterByPaginated, no authentication; we request only public lot-card fields). Auction discovery: links on the public /en/results and /en/calendar pages (rendered through Firecrawl, 1 credit each), plus config.seeds auction URLs; auctions seen while open are re-checked after they close so their results are captured. robots.txt disallows /bsp-api/* and PDFs — not used. Prices: finalPriceV2 (buyer's premium included) → buyerPremiumIncluded=true, hammer kept in metadata; sale date = lot closingTime or the auction's closed timestamp. Condition reports are behind login and are not fetched.", | |
| 1508 | + "enabled": true, | |
| 1509 | + "schemaVersion": "1.0", | |
| 1510 | + "config": { | |
| 1511 | + "seeds": [], | |
| 1512 | + "discoveryPages": [ | |
| 1513 | + "https://www.sothebys.com/en/results", | |
| 1514 | + "https://www.sothebys.com/en/calendar" | |
| 1515 | + ], | |
| 1516 | + "departments": [], | |
| 1517 | + "maxAuctionsPerRun": 25, | |
| 1518 | + "pageSize": 48 | |
| 1519 | + } | |
| 1520 | + }, | |
| 1021 | 1521 | { |
| 1022 | 1522 | "id": "sportscardspro", |
| 1023 | 1523 | "displayName": "SportsCardsPro", |
@@ -1061,7 +1561,7 @@ | ||
| 1061 | 1561 | "trustScore": 0.7, |
| 1062 | 1562 | "attributionRequired": true, |
| 1063 | 1563 | "termsUrl": "https://www.sportscardspro.com/page/terms-of-service", |
| 1064 | − "accessNotes": "Public product pages of PriceCharting's sports-card site. robots.txt only disallows /buy, /publish-offer, /stripe-connect. Plain HTTP with our user agent gets a Cloudflare interstitial (HTTP 403), so pages are fetched through Firecrawl (1 credit per page, ~1 MB each) \u2014 no login, no CAPTCHA solving, no account. Each page exposes guide values per grade (Ungraded, Grade 1\u20139.5, TAG/ACE/SGC/CGC/PSA/BGS 10, BGS 10 Black, CGC 10 Pristine) and recently completed eBay sales per grade tab; graded rows without a named grading company are stored with the generic grader 'graded' unless the eBay title names the company. Set lists come from the public /category/<sport>-cards pages; console listings use the ?format=json cursor endpoint.", | |
| 1564 | + "accessNotes": "Public product pages of PriceCharting's sports-card site. robots.txt only disallows /buy, /publish-offer, /stripe-connect. Plain HTTP with our user agent gets a Cloudflare interstitial (HTTP 403), so pages are fetched through Firecrawl (1 credit per page, ~1 MB each) — no login, no CAPTCHA solving, no account. Each page exposes guide values per grade (Ungraded, Grade 1–9.5, TAG/ACE/SGC/CGC/PSA/BGS 10, BGS 10 Black, CGC 10 Pristine) and recently completed eBay sales per grade tab; graded rows without a named grading company are stored with the generic grader 'graded' unless the eBay title names the company. Set lists come from the public /category/<sport>-cards pages; console listings use the ?format=json cursor endpoint.", | |
| 1065 | 1565 | "enabled": true, |
| 1066 | 1566 | "schemaVersion": "2.0", |
| 1067 | 1567 | "config": { |
@@ -1100,7 +1600,7 @@ | ||
| 1100 | 1600 | }, |
| 1101 | 1601 | { |
| 1102 | 1602 | "id": "tcgdex", |
| 1103 | − "displayName": "TCGdex (Pok\u00e9mon, multilingual)", | |
| 1603 | + "displayName": "TCGdex (Pokémon, multilingual)", | |
| 1104 | 1604 | "sourceId": "tcgdex", |
| 1105 | 1605 | "sourceName": "TCGdex", |
| 1106 | 1606 | "sourceType": "catalog", |
@@ -1142,7 +1642,7 @@ | ||
| 1142 | 1642 | "trustScore": 0.8, |
| 1143 | 1643 | "attributionRequired": true, |
| 1144 | 1644 | "termsUrl": "https://tcgdex.dev/", |
| 1145 | − "accessNotes": "Open REST API (https://api.tcgdex.net/v2, no key, MIT-licensed data) covering every Pok\u00e9mon TCG language including Japanese; English cards carry TCGplayer (USD) and Cardmarket (EUR) prices per variant with their own update timestamps, which we store as price observations dated by the price's `updated` field. One request per set and per card at \u22488 req/s (self-throttled 120 ms). English ids match pokemontcg.io (base1-4) so `pokemontcg_id` aligns; set codes use the PTCGO abbreviation like pokemontcg's ptcgoCode.", | |
| 1645 | + "accessNotes": "Open REST API (https://api.tcgdex.net/v2, no key, MIT-licensed data) covering every Pokémon TCG language including Japanese; English cards carry TCGplayer (USD) and Cardmarket (EUR) prices per variant with their own update timestamps, which we store as price observations dated by the price's `updated` field. One request per set and per card at ≈8 req/s (self-throttled 120 ms). English ids match pokemontcg.io (base1-4) so `pokemontcg_id` aligns; set codes use the PTCGO abbreviation like pokemontcg's ptcgoCode.", | |
| 1146 | 1646 | "enabled": true, |
| 1147 | 1647 | "schemaVersion": "1.0", |
| 1148 | 1648 | "config": { |
@@ -1189,7 +1689,7 @@ | ||
| 1189 | 1689 | "trustScore": 0.75, |
| 1190 | 1690 | "attributionRequired": true, |
| 1191 | 1691 | "termsUrl": "https://ygoprodeck.com/api-guide/", |
| 1192 | − "accessNotes": "Public API v7 (https://db.ygoprodeck.com/api/v7/cardinfo.php), no key; rate limit 20 req/s \u2014 a full crawl is ONE request (~21 MB, ~14.5k cards / ~44k printings) plus optional misc=yes. The API carries no price timestamp: card_sets[].set_price (USD, per printing) and card_prices (cardmarket EUR / tcgplayer / ebay / amazon / coolstuffinc USD, card-level) are recorded as price_observations dated at fetch time with confidence 0.7 and metadata.price_scope. Images may not be hot-linked in bulk per the API guide (we store URLs, never mirror). Yu-Gi-Oh! \u00a9 Konami.", | |
| 1692 | + "accessNotes": "Public API v7 (https://db.ygoprodeck.com/api/v7/cardinfo.php), no key; rate limit 20 req/s — a full crawl is ONE request (~21 MB, ~14.5k cards / ~44k printings) plus optional misc=yes. The API carries no price timestamp: card_sets[].set_price (USD, per printing) and card_prices (cardmarket EUR / tcgplayer / ebay / amazon / coolstuffinc USD, card-level) are recorded as price_observations dated at fetch time with confidence 0.7 and metadata.price_scope. Images may not be hot-linked in bulk per the API guide (we store URLs, never mirror). Yu-Gi-Oh! © Konami.", | |
| 1193 | 1693 | "enabled": true, |
| 1194 | 1694 | "schemaVersion": "1.0", |
| 1195 | 1695 | "config": { |
added
connectors/scrapfly/catawiki/index.test.ts
+75 −0
@@ -0,0 +1,75 @@ | ||
| 1 | +import { describe, expect, it } from 'vitest'; | |
| 2 | +import { getConnectorMeta } from '@rareindex/connectors'; | |
| 3 | +import { loadFixture, runFixtureSuite } from '@rareindex/connectors/testing'; | |
| 4 | +import createConnector, { categoryPageAuctionIds, classifyLot, parseAuctionPage, parseLotPage, type AuctionLotsPayload, type LotPayload } from './index.js'; | |
| 5 | + | |
| 6 | +const connector = createConnector(getConnectorMeta('catawiki')); | |
| 7 | + | |
| 8 | +describe('catawiki connector', () => { | |
| 9 | + runFixtureSuite(connector, it, expect); | |
| 10 | + | |
| 11 | + it('turns a closed, sold lot into a hammer-price sale in EUR with the source end time', async () => { | |
| 12 | + const fx = loadFixture('catawiki', 'seeded-1'); | |
| 13 | + const lot = fx.raw.payload as LotPayload; | |
| 14 | + const out = await connector.normalize(fx.raw); | |
| 15 | + expect(out).toHaveLength(1); | |
| 16 | + const r = out[0]!; | |
| 17 | + if (r.kind !== 'sale') throw new Error('expected sale'); | |
| 18 | + expect(r.price).toBe(lot.bidding.finalBidEur); | |
| 19 | + expect(r.currency).toBe('EUR'); | |
| 20 | + expect(r.buyerPremiumIncluded).toBe(false); | |
| 21 | + expect(r.saleDate.getTime()).toBe(lot.bidding.biddingEndTime); | |
| 22 | + expect(r.auctionHouse).toBe('Catawiki'); | |
| 23 | + expect(r.location).toBe(lot.sellerCountry); | |
| 24 | + expect(r.attributes.identifiers.catawiki_lot_id).toBe(String(lot.id)); | |
| 25 | + expect(r.attributes.metadata.estimate_min_eur).toBe(lot.estimateMinEur); | |
| 26 | + expect(r.attributes.material).toBe('Wood'); | |
| 27 | + expect(r.attributes.categorySlug).toBe('antiques'); | |
| 28 | + }); | |
| 29 | + | |
| 30 | + it('drops closed-unsold lots and emits live lots as auction_lot', async () => { | |
| 31 | + const fx = loadFixture('catawiki', 'seeded-1'); | |
| 32 | + const lot = structuredClone(fx.raw.payload) as LotPayload; | |
| 33 | + const unsold = { ...lot, bidding: { ...lot.bidding, sold: false } }; | |
| 34 | + expect(await connector.normalize({ ...fx.raw, payload: unsold })).toHaveLength(0); | |
| 35 | + const live = { ...lot, bidding: { ...lot.bidding, closed: false, sold: null, biddingEndTime: Date.now() + 3 * 86_400_000 } }; | |
| 36 | + const out = await connector.normalize({ ...fx.raw, payload: live }); | |
| 37 | + expect(out).toHaveLength(1); | |
| 38 | + expect(out[0]!.kind).toBe('auction_lot'); | |
| 39 | + if (out[0]!.kind === 'auction_lot') { | |
| 40 | + expect(out[0]!.status).toBe('live'); | |
| 41 | + expect(out[0]!.currentBid).toBe(lot.bidding.finalBidEur); | |
| 42 | + expect(out[0]!.estimateLow).toBe(lot.estimateMinEur); | |
| 43 | + } | |
| 44 | + }); | |
| 45 | + | |
| 46 | + it('emits auction_lot records for a live themed auction and none for a stale one', async () => { | |
| 47 | + const fx = loadFixture('catawiki', 'seeded-2'); | |
| 48 | + const payload = structuredClone(fx.raw.payload) as AuctionLotsPayload; | |
| 49 | + const future = new Date(Date.now() + 2 * 86_400_000).toISOString(); | |
| 50 | + payload.auction = { ...payload.auction, closeAt: future, startAt: new Date(Date.now() - 86_400_000).toISOString() }; | |
| 51 | + const out = await connector.normalize({ ...fx.raw, payload }); | |
| 52 | + expect(out.length).toBeGreaterThan(payload.lots.length * 0.8); | |
| 53 | + for (const r of out) { | |
| 54 | + expect(r.kind).toBe('auction_lot'); | |
| 55 | + if (r.kind !== 'auction_lot') continue; | |
| 56 | + expect(r.endsAt?.toISOString()).toBe(new Date(future).toISOString()); | |
| 57 | + expect(r.currency).toBe('EUR'); | |
| 58 | + expect(['rolex', 'patek_philippe', 'audemars_piguet', 'omega', 'other_watches', 'pens', 'lighters', 'clocks', 'jewelry']).toContain(r.attributes.categorySlug); | |
| 59 | + } | |
| 60 | + const stale = { ...payload, auction: { ...payload.auction, closeAt: '2020-01-01T00:00:00Z' } }; | |
| 61 | + expect(await connector.normalize({ ...fx.raw, payload: stale })).toHaveLength(0); | |
| 62 | + }); | |
| 63 | + | |
| 64 | + it('classifies lots from category path, specs and titles', () => { | |
| 65 | + const base: LotPayload = { kind: 'lot', seedHint: 'toys', id: 1, url: 'https://www.catawiki.com/en/l/1', title: 'LEGO - Star Wars - 10179 - Millennium Falcon UCS', subtitle: 'Sealed', description: null, images: [], categoryId: null, categoryUrl: null, auction: { id: 1, title: 'LEGO Auction', url: 'https://www.catawiki.com/en/a/1', status: 'closed', startAt: null, closeAt: null, closedAt: null, categories: ['Toys & Models', 'LEGO'], lotCount: null }, specs: [{ name: 'Set number', value: '10179' }], estimateMinEur: null, estimateMaxEur: null, sellerCountry: 'NL', sellerName: null, sellerIsPro: null, bidding: { closed: true, sold: true, finalBidEur: 2500, biddingStartTime: null, biddingEndTime: 1, bidCount: null, reservePriceMet: null } }; | |
| 66 | + expect(classifyLot(base).slug).toBe('lego_sets'); | |
| 67 | + expect(classifyLot({ ...base, seedHint: 'cards', title: 'Pokémon - Charizard Base Set 4/102 - PSA 9', auction: { ...base.auction!, categories: ['Trading Cards', 'Pokémon'] } }).slug).toBe('pokemon'); | |
| 68 | + expect(classifyLot({ ...base, seedHint: 'watches', title: 'Rolex - Submariner 16610 - Men - 2005', auction: { ...base.auction!, categories: ['Watches, Pens & Lighters', 'Watches'] } }).slug).toBe('rolex'); | |
| 69 | + expect(classifyLot({ ...base, seedHint: 'wine', title: 'Macallan 18 Sherry Oak 2020 release', auction: { ...base.auction!, categories: ['Wine, Whisky & Spirits', 'Whisky'] } }).slug).toBe('whisky'); | |
| 70 | + expect(classifyLot({ ...base, seedHint: 'coins', title: 'Netherlands 10 Gulden 1875 gold', auction: { ...base.auction!, categories: ['Coins & Stamps', 'Coins'] } }).slug).toBe('coins'); | |
| 71 | + expect(categoryPageAuctionIds('<a href="/en/a/1263062-vintage"></a><a href="https://www.catawiki.com/en/a/1263062-vintage"></a><a href="/en/a/99-x">')).toEqual([1263062, 99]); | |
| 72 | + expect(parseAuctionPage('<html></html>')).toBeNull(); | |
| 73 | + expect(parseLotPage('<html></html>', 'https://www.catawiki.com/en/l/1', 'unknown')).toBeNull(); | |
| 74 | + }); | |
| 75 | +}); | |
added
connectors/scrapfly/catawiki/index.ts
+493 −0
@@ -0,0 +1,493 @@ | ||
| 1 | +import { z } from 'zod'; | |
| 2 | +import { BaseConnector, type ConnectorMeta, type CrawlContext, type RawRecordInput, type RawRecordLike } from '@rareindex/connectors'; | |
| 3 | +import { NormalizedAuctionLotSchema, NormalizedSaleSchema, type NormalizedRecord } from '@rareindex/shared'; | |
| 4 | +import { normalizeCondition, parseGradeFromTitle } from '@rareindex/taxonomy'; | |
| 5 | +import { brandFromSlug, hintFromLabel, isBundleTitle, legoSetNumber, safeYear, slugFromTitle, watchBrand, watchReference, type DeptHint } from '../../api/_auction-lib/categories.js'; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * Catawiki — closed-lot results (hammer = final bid, EUR) and live lots, two-phase crawl. | |
| 9 | + * Engine: Scrapfly. See meta.json accessNotes for the access rationale and cost model. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +const SITE = 'https://www.catawiki.com'; | |
| 13 | + | |
| 14 | +const SeedSchema = z.object({ id: z.number().int(), path: z.string(), hint: z.string() }); | |
| 15 | +type Seed = z.infer<typeof SeedSchema>; | |
| 16 | + | |
| 17 | +export const AuctionInfoSchema = z.object({ | |
| 18 | + id: z.number().int(), | |
| 19 | + title: z.string(), | |
| 20 | + url: z.string(), | |
| 21 | + status: z.string().nullable(), | |
| 22 | + startAt: z.string().nullable(), | |
| 23 | + closeAt: z.string().nullable(), | |
| 24 | + closedAt: z.string().nullable(), | |
| 25 | + categories: z.array(z.string()), | |
| 26 | + lotCount: z.number().nullable(), | |
| 27 | +}); | |
| 28 | +export type AuctionInfo = z.infer<typeof AuctionInfoSchema>; | |
| 29 | + | |
| 30 | +export const LiveLotSchema = z.object({ | |
| 31 | + id: z.number().int(), | |
| 32 | + title: z.string(), | |
| 33 | + subtitle: z.string().nullable(), | |
| 34 | + url: z.string(), | |
| 35 | + imageUrl: z.string().nullable(), | |
| 36 | + reservePriceSet: z.boolean().nullable(), | |
| 37 | + biddingStartTime: z.string().nullable(), | |
| 38 | +}); | |
| 39 | +export const AuctionLotsPayloadSchema = z.object({ | |
| 40 | + kind: z.literal('auction_lots'), | |
| 41 | + seedHint: z.string(), | |
| 42 | + auction: AuctionInfoSchema, | |
| 43 | + lots: z.array(LiveLotSchema), | |
| 44 | +}); | |
| 45 | +export type AuctionLotsPayload = z.infer<typeof AuctionLotsPayloadSchema>; | |
| 46 | + | |
| 47 | +export const LotPayloadSchema = z.object({ | |
| 48 | + kind: z.literal('lot'), | |
| 49 | + seedHint: z.string(), | |
| 50 | + id: z.number().int(), | |
| 51 | + url: z.string(), | |
| 52 | + title: z.string(), | |
| 53 | + subtitle: z.string().nullable(), | |
| 54 | + description: z.string().nullable(), | |
| 55 | + images: z.array(z.string()), | |
| 56 | + categoryId: z.number().nullable(), | |
| 57 | + categoryUrl: z.string().nullable(), | |
| 58 | + auction: AuctionInfoSchema.nullable(), | |
| 59 | + specs: z.array(z.object({ name: z.string(), value: z.string() })), | |
| 60 | + estimateMinEur: z.number().nullable(), | |
| 61 | + estimateMaxEur: z.number().nullable(), | |
| 62 | + sellerCountry: z.string().nullable(), | |
| 63 | + sellerName: z.string().nullable(), | |
| 64 | + sellerIsPro: z.boolean().nullable(), | |
| 65 | + bidding: z.object({ | |
| 66 | + closed: z.boolean().nullable(), | |
| 67 | + sold: z.boolean().nullable(), | |
| 68 | + finalBidEur: z.number().nullable(), | |
| 69 | + biddingStartTime: z.number().nullable(), | |
| 70 | + biddingEndTime: z.number().nullable(), | |
| 71 | + bidCount: z.number().nullable(), | |
| 72 | + reservePriceMet: z.boolean().nullable(), | |
| 73 | + }), | |
| 74 | +}); | |
| 75 | +export type LotPayload = z.infer<typeof LotPayloadSchema>; | |
| 76 | + | |
| 77 | +const ConfigSchema = z.object({ | |
| 78 | + seeds: z.array(SeedSchema).default([]), | |
| 79 | + maxNewAuctionsPerRun: z.number().int().default(30), | |
| 80 | + maxLotFetchesPerRun: z.number().int().default(400), | |
| 81 | + pendingCap: z.number().int().default(6000), | |
| 82 | + harvestDelayMinutes: z.number().int().default(20), | |
| 83 | +}); | |
| 84 | + | |
| 85 | +interface Pending { | |
| 86 | + id: number; | |
| 87 | + url: string; | |
| 88 | + auctionId: number; | |
| 89 | + closeAt: string; | |
| 90 | + hint: string; | |
| 91 | +} | |
| 92 | +interface Cursor { | |
| 93 | + auctions?: Record<string, { closeAt: string | null; hint: string }>; | |
| 94 | + pending?: Pending[]; | |
| 95 | +} | |
| 96 | + | |
| 97 | +export function nextData(html: string): Record<string, any> | null { | |
| 98 | + const m = html.match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/); | |
| 99 | + if (!m) return null; | |
| 100 | + try { | |
| 101 | + return (JSON.parse(m[1]!) as { props?: { pageProps?: Record<string, any> } }).props?.pageProps ?? null; | |
| 102 | + } catch { | |
| 103 | + return null; | |
| 104 | + } | |
| 105 | +} | |
| 106 | + | |
| 107 | +function auctionInfo(a: Record<string, any> | null | undefined): AuctionInfo | null { | |
| 108 | + if (!a || !a.id) return null; | |
| 109 | + return AuctionInfoSchema.parse({ | |
| 110 | + id: Number(a.id), | |
| 111 | + title: String(a.title ?? ''), | |
| 112 | + url: String(a.url ?? `${SITE}/en/a/${a.id}`), | |
| 113 | + status: a.status ?? null, | |
| 114 | + startAt: a.startAt ?? null, | |
| 115 | + closeAt: a.closeAt ?? null, | |
| 116 | + closedAt: a.closedAt ?? null, | |
| 117 | + categories: ((a.categories as Array<{ title?: string; titleEn?: string }> | undefined) ?? []).map((c) => c.titleEn ?? c.title ?? '').filter(Boolean), | |
| 118 | + lotCount: typeof a.lotCount === 'number' ? a.lotCount : typeof a.numberOfLots === 'number' ? a.numberOfLots : null, | |
| 119 | + }); | |
| 120 | +} | |
| 121 | + | |
| 122 | +/** Auction page → auction info + live lot list. */ | |
| 123 | +export function parseAuctionPage(html: string): { auction: AuctionInfo; lots: z.infer<typeof LiveLotSchema>[] } | null { | |
| 124 | + const pp = nextData(html); | |
| 125 | + const auction = auctionInfo(pp?.auction); | |
| 126 | + if (!auction) return null; | |
| 127 | + const lots = ((pp?.lots as Array<Record<string, any>> | undefined) ?? []).map((l) => | |
| 128 | + LiveLotSchema.parse({ | |
| 129 | + id: Number(l.id), | |
| 130 | + title: String(l.title ?? ''), | |
| 131 | + subtitle: l.subtitle ?? null, | |
| 132 | + url: String(l.url ?? `${SITE}/en/l/${l.id}`), | |
| 133 | + imageUrl: l.originalImageUrl ?? l.thumbImageUrl ?? null, | |
| 134 | + reservePriceSet: typeof l.reservePriceSet === 'boolean' ? l.reservePriceSet : null, | |
| 135 | + biddingStartTime: l.biddingStartTime ?? null, | |
| 136 | + }), | |
| 137 | + ); | |
| 138 | + return { auction, lots }; | |
| 139 | +} | |
| 140 | + | |
| 141 | +/** Lot page → compact payload. */ | |
| 142 | +export function parseLotPage(html: string, url: string, seedHint: string): LotPayload | null { | |
| 143 | + const pp = nextData(html); | |
| 144 | + const ld = pp?.lotDetailsData; | |
| 145 | + if (!ld) return null; | |
| 146 | + const bb = pp?.biddingBlockResponse ?? {}; | |
| 147 | + const live = bb.live?.lot ?? {}; | |
| 148 | + const est = ld.expertsEstimate ?? {}; | |
| 149 | + const seller = ld.sellerInfo ?? {}; | |
| 150 | + const finalBid = typeof live.bid?.EUR === 'number' ? live.bid.EUR : typeof bb.localizedCurrentBidAmount === 'number' ? bb.localizedCurrentBidAmount : null; | |
| 151 | + const bids = bb.biddingHistory?.bids; | |
| 152 | + const bidCount = Array.isArray(bids) && bids.length ? Number(bids[0]?.totalBids ?? bids.length) : null; | |
| 153 | + return LotPayloadSchema.parse({ | |
| 154 | + kind: 'lot', | |
| 155 | + seedHint, | |
| 156 | + id: Number(ld.lotId ?? pp?.lotId), | |
| 157 | + url, | |
| 158 | + title: String(ld.lotTitle ?? ''), | |
| 159 | + subtitle: ld.lotSubtitle ?? null, | |
| 160 | + description: typeof ld.description === 'string' ? ld.description.replace(/\s+/g, ' ').slice(0, 800) : null, | |
| 161 | + images: ((ld.images as Array<{ large?: string; id?: string }> | undefined) ?? []).map((i) => i.large ?? i.id ?? '').filter(Boolean).slice(0, 3), | |
| 162 | + categoryId: typeof ld.category?.id === 'number' ? ld.category.id : null, | |
| 163 | + categoryUrl: ld.category?.url ?? null, | |
| 164 | + auction: auctionInfo(pp?.auction), | |
| 165 | + specs: ((ld.specifications as Array<{ name?: string; value?: string }> | undefined) ?? []).filter((s) => s.name && s.value).map((s) => ({ name: String(s.name), value: String(s.value) })), | |
| 166 | + estimateMinEur: typeof est.min?.EUR === 'number' && est.min.EUR > 0 ? est.min.EUR : null, | |
| 167 | + estimateMaxEur: typeof est.max?.EUR === 'number' && est.max.EUR > 0 ? est.max.EUR : null, | |
| 168 | + sellerCountry: seller.address?.country?.shortCode ? String(seller.address.country.shortCode).toUpperCase() : null, | |
| 169 | + sellerName: seller.sellerName ?? null, | |
| 170 | + sellerIsPro: typeof seller.isPro === 'boolean' ? seller.isPro : null, | |
| 171 | + bidding: { | |
| 172 | + closed: typeof bb.closed === 'boolean' ? bb.closed : typeof ld.isClosed === 'boolean' ? ld.isClosed : null, | |
| 173 | + sold: typeof bb.sold === 'boolean' ? bb.sold : null, | |
| 174 | + finalBidEur: finalBid, | |
| 175 | + biddingStartTime: typeof bb.biddingStartTime === 'number' ? bb.biddingStartTime : null, | |
| 176 | + biddingEndTime: typeof bb.biddingEndTime === 'number' ? bb.biddingEndTime : typeof live.biddingEndTime === 'number' ? live.biddingEndTime : null, | |
| 177 | + bidCount, | |
| 178 | + reservePriceMet: typeof bb.reservePriceMet === 'boolean' ? bb.reservePriceMet : null, | |
| 179 | + }, | |
| 180 | + }); | |
| 181 | +} | |
| 182 | + | |
| 183 | +export function categoryPageAuctionIds(html: string): number[] { | |
| 184 | + return [...new Set([...html.matchAll(/\/en\/a\/(\d+)/g)].map((m) => Number(m[1])))]; | |
| 185 | +} | |
| 186 | + | |
| 187 | +function spec(specs: Array<{ name: string; value: string }>, ...names: string[]): string | null { | |
| 188 | + for (const n of names) { | |
| 189 | + const hit = specs.find((s) => s.name.toLowerCase() === n.toLowerCase()); | |
| 190 | + if (hit) return hit.value; | |
| 191 | + } | |
| 192 | + return null; | |
| 193 | +} | |
| 194 | + | |
| 195 | +/** Derive taxonomy slug + attributes from a Catawiki lot (seed hint + auction categories + specs + title). */ | |
| 196 | +export function classifyLot(lot: LotPayload): { slug: string | null; hint: DeptHint } { | |
| 197 | + const cats = lot.auction?.categories ?? []; | |
| 198 | + const labelHint = hintFromLabel(cats[cats.length - 1]) !== 'unknown' ? hintFromLabel(cats[cats.length - 1]) : hintFromLabel(cats[0]); | |
| 199 | + const hint: DeptHint = (lot.seedHint as DeptHint) !== 'unknown' && lot.seedHint ? (lot.seedHint as DeptHint) : labelHint; | |
| 200 | + const catText = cats.join(' '); | |
| 201 | + // The most specific (leaf) category decides; the full path only for franchise-style families. | |
| 202 | + const leaf = cats[cats.length - 1] ?? ''; | |
| 203 | + const text = `${lot.title} ${lot.subtitle ?? ''}`; | |
| 204 | + if (/lego/i.test(catText)) return { slug: 'lego_sets', hint }; | |
| 205 | + if (/funko/i.test(catText)) return { slug: 'funko', hint }; | |
| 206 | + if (/pok[eé]mon/i.test(catText)) return { slug: 'pokemon', hint }; | |
| 207 | + if (/model (?:cars|trains)|modelauto|diecast/i.test(leaf)) return { slug: /train/i.test(leaf) ? 'model_trains' : 'model_cars', hint }; | |
| 208 | + if (/video ?games|retro gaming/i.test(leaf)) return { slug: 'video_games', hint }; | |
| 209 | + if (/sneaker/i.test(leaf)) return { slug: 'sneakers', hint }; | |
| 210 | + if (/handbag|bags/i.test(leaf)) return { slug: 'luxury_handbags', hint }; | |
| 211 | + if (/whisky|whiskey/i.test(leaf)) return { slug: 'whisky', hint }; | |
| 212 | + if (/\bwine|champagne/i.test(leaf)) return { slug: slugFromTitle(text, 'wine') ?? 'wine', hint }; | |
| 213 | + if (/watch/i.test(leaf) && !/pen|lighter/i.test(leaf)) return { slug: watchBrand(text).slug, hint: 'watches' }; | |
| 214 | + if (/banknote/i.test(leaf)) return { slug: 'banknotes', hint }; | |
| 215 | + if (/stamp/i.test(leaf) && !/coin/i.test(leaf)) return { slug: 'stamps', hint }; | |
| 216 | + if (/coin|numismat/i.test(leaf)) return { slug: slugFromTitle(text, 'coins') ?? 'coins', hint: 'coins' }; | |
| 217 | + if (/vinyl|records/i.test(leaf)) return { slug: 'music', hint }; | |
| 218 | + if (/movie poster|film poster/i.test(leaf)) return { slug: 'movie_posters', hint }; | |
| 219 | + if (/camera/i.test(leaf)) return { slug: 'cameras', hint }; | |
| 220 | + return { slug: slugFromTitle(text, hint), hint }; | |
| 221 | +} | |
| 222 | + | |
| 223 | +function toDate(ms: number | null | undefined): Date | null { | |
| 224 | + return typeof ms === 'number' && ms > 0 ? new Date(ms) : null; | |
| 225 | +} | |
| 226 | + | |
| 227 | +export default function createConnector(meta: ConnectorMeta) { | |
| 228 | + return new CatawikiConnector(meta); | |
| 229 | +} | |
| 230 | + | |
| 231 | +export class CatawikiConnector extends BaseConnector { | |
| 232 | + readonly version = '1.0.0'; | |
| 233 | + readonly parserVersion = '1.0.0'; | |
| 234 | + override readonly urlPatterns = [/^https?:\/\/(www\.)?catawiki\.[a-z]+\/[a-z]{2}\/l\/\d+/i]; | |
| 235 | + protected override minIntervalMs = 2000; | |
| 236 | + private readonly config = ConfigSchema.parse(this.meta.config ?? {}); | |
| 237 | + | |
| 238 | + private async html(ctx: CrawlContext, url: string, renderJs: boolean): Promise<string | null> { | |
| 239 | + await this.throttle(); | |
| 240 | + const res = await ctx.fetch(url, { engines: ['scrapfly'], renderJs, country: 'nl', minQuality: 0, waitForMs: renderJs ? 3000 : undefined, timeoutMs: renderJs ? 120_000 : 60_000 }); | |
| 241 | + if (!res.success || !res.html) { | |
| 242 | + ctx.anomaly('page_fetch_failed', `${url}: ${res.error ?? res.httpStatus}`); | |
| 243 | + return null; | |
| 244 | + } | |
| 245 | + return res.html; | |
| 246 | + } | |
| 247 | + | |
| 248 | + private async fetchLot(ctx: CrawlContext, url: string, hint: string): Promise<LotPayload | null> { | |
| 249 | + const html = await this.html(ctx, url, false); | |
| 250 | + if (!html) return null; | |
| 251 | + const lot = parseLotPage(html, url, hint); | |
| 252 | + if (!lot) ctx.anomaly('parse_failure', `${url}: no lotDetailsData`); | |
| 253 | + return lot; | |
| 254 | + } | |
| 255 | + | |
| 256 | + async *crawl(ctx: CrawlContext): AsyncIterable<RawRecordInput> { | |
| 257 | + const cursor: Cursor = { auctions: {}, pending: [], ...(ctx.options.cursor ?? {}) }; | |
| 258 | + const probe = ctx.options.mode === 'probe'; | |
| 259 | + const now = Date.now(); | |
| 260 | + let yielded = 0; | |
| 261 | + | |
| 262 | + // 0. Explicit seeds (lot or auction URLs) — used by probes, smoke tests and backfills. | |
| 263 | + for (const s of ctx.options.seeds ?? []) { | |
| 264 | + const lotM = s.match(/\/l\/(\d+)/); | |
| 265 | + if (lotM) { | |
| 266 | + const lot = await this.fetchLot(ctx, s, 'unknown'); | |
| 267 | + if (lot && lot.bidding.closed && lot.bidding.sold) { | |
| 268 | + yield { url: s, externalId: String(lot.id), kind: 'sale', engine: 'scrapfly', httpStatus: 200, payload: lot, fetchedAt: new Date() }; | |
| 269 | + if (this.reached(ctx, ++yielded)) return; | |
| 270 | + } | |
| 271 | + continue; | |
| 272 | + } | |
| 273 | + if (/\/a\/\d+/.test(s)) { | |
| 274 | + const html = await this.html(ctx, s, false); | |
| 275 | + const parsed = html ? parseAuctionPage(html) : null; | |
| 276 | + if (parsed) { | |
| 277 | + const payload: AuctionLotsPayload = { kind: 'auction_lots', seedHint: 'unknown', auction: parsed.auction, lots: parsed.lots }; | |
| 278 | + yield { url: s, externalId: `a${parsed.auction.id}`, kind: 'auction_lot', engine: 'scrapfly', httpStatus: 200, payload, fetchedAt: new Date() }; | |
| 279 | + this.remember(cursor, parsed, 'unknown'); | |
| 280 | + } | |
| 281 | + } | |
| 282 | + } | |
| 283 | + if (probe && (ctx.options.seeds?.length ?? 0) > 0) { | |
| 284 | + await ctx.setCursor(cursor as Record<string, unknown>); | |
| 285 | + return; | |
| 286 | + } | |
| 287 | + | |
| 288 | + // 1. Harvest closed lots | |
| 289 | + const delayMs = this.config.harvestDelayMinutes * 60_000; | |
| 290 | + const due = (cursor.pending ?? []).filter((p) => new Date(p.closeAt).getTime() + delayMs <= now).slice(0, probe ? 3 : this.config.maxLotFetchesPerRun); | |
| 291 | + const dueIds = new Set(due.map((p) => p.id)); | |
| 292 | + for (const p of due) { | |
| 293 | + if (ctx.signal?.aborted) break; | |
| 294 | + const lot = await this.fetchLot(ctx, p.url, p.hint); | |
| 295 | + if (lot && lot.bidding.closed === false) { | |
| 296 | + // extended bidding — try again next run | |
| 297 | + dueIds.delete(p.id); | |
| 298 | + continue; | |
| 299 | + } | |
| 300 | + if (lot && lot.bidding.closed && lot.bidding.sold) { | |
| 301 | + yield { url: p.url, externalId: String(lot.id), kind: 'sale', engine: 'scrapfly', httpStatus: 200, payload: lot, fetchedAt: new Date() }; | |
| 302 | + if (this.reached(ctx, ++yielded)) break; | |
| 303 | + } | |
| 304 | + } | |
| 305 | + cursor.pending = (cursor.pending ?? []).filter((p) => !dueIds.has(p.id)); | |
| 306 | + await ctx.setCursor(cursor as Record<string, unknown>); | |
| 307 | + | |
| 308 | + // 2. Discovery of live auctions per seed category | |
| 309 | + const seeds = ctx.options.categories?.length ? this.config.seeds.filter((s) => ctx.options.categories!.includes(s.hint)) : this.config.seeds; | |
| 310 | + let newAuctions = 0; | |
| 311 | + for (const seed of probe ? seeds.slice(0, 1) : seeds) { | |
| 312 | + if (ctx.signal?.aborted) break; | |
| 313 | + const html = await this.html(ctx, `${SITE}/en/c/${seed.path}`, true); | |
| 314 | + if (!html) continue; | |
| 315 | + const ids = categoryPageAuctionIds(html); | |
| 316 | + if (!ids.length) ctx.anomaly('empty_page', `category ${seed.path}: no auction links after render`); | |
| 317 | + for (const id of ids) { | |
| 318 | + if (cursor.auctions?.[String(id)]) continue; | |
| 319 | + if (newAuctions >= (probe ? 1 : this.config.maxNewAuctionsPerRun)) break; | |
| 320 | + const url = `${SITE}/en/a/${id}`; | |
| 321 | + const ahtml = await this.html(ctx, url, false); | |
| 322 | + const parsed = ahtml ? parseAuctionPage(ahtml) : null; | |
| 323 | + if (!parsed) continue; | |
| 324 | + newAuctions++; | |
| 325 | + this.remember(cursor, parsed, seed.hint); | |
| 326 | + if (parsed.lots.length) { | |
| 327 | + const payload: AuctionLotsPayload = { kind: 'auction_lots', seedHint: seed.hint, auction: parsed.auction, lots: parsed.lots }; | |
| 328 | + yield { url: parsed.auction.url, externalId: `a${parsed.auction.id}`, kind: 'auction_lot', engine: 'scrapfly', httpStatus: 200, payload, fetchedAt: new Date() }; | |
| 329 | + } | |
| 330 | + await ctx.setCursor(cursor as Record<string, unknown>); | |
| 331 | + } | |
| 332 | + } | |
| 333 | + // prune remembered auctions older than 30 days | |
| 334 | + const cutoff = now - 30 * 86_400_000; | |
| 335 | + for (const [id, a] of Object.entries(cursor.auctions ?? {})) if (a.closeAt && new Date(a.closeAt).getTime() < cutoff) delete cursor.auctions![id]; | |
| 336 | + await ctx.setCursor(cursor as Record<string, unknown>); | |
| 337 | + } | |
| 338 | + | |
| 339 | + private remember(cursor: Cursor, parsed: NonNullable<ReturnType<typeof parseAuctionPage>>, hint: string): void { | |
| 340 | + cursor.auctions ??= {}; | |
| 341 | + cursor.pending ??= []; | |
| 342 | + cursor.auctions[String(parsed.auction.id)] = { closeAt: parsed.auction.closeAt, hint }; | |
| 343 | + if (!parsed.auction.closeAt) return; | |
| 344 | + const known = new Set(cursor.pending.map((p) => p.id)); | |
| 345 | + for (const l of parsed.lots) { | |
| 346 | + if (known.has(l.id)) continue; | |
| 347 | + cursor.pending.push({ id: l.id, url: l.url, auctionId: parsed.auction.id, closeAt: parsed.auction.closeAt, hint }); | |
| 348 | + } | |
| 349 | + if (cursor.pending.length > this.config.pendingCap) cursor.pending = cursor.pending.slice(-this.config.pendingCap); | |
| 350 | + } | |
| 351 | + | |
| 352 | + async lookup(url: string, ctx: CrawlContext): Promise<RawRecordInput[]> { | |
| 353 | + const lot = await this.fetchLot(ctx, url, 'unknown'); | |
| 354 | + if (!lot) return []; | |
| 355 | + return [{ url, externalId: String(lot.id), kind: lot.bidding.closed ? 'sale' : 'auction_lot', engine: 'scrapfly', httpStatus: 200, payload: lot, fetchedAt: new Date() }]; | |
| 356 | + } | |
| 357 | + | |
| 358 | + async normalize(raw: RawRecordLike): Promise<NormalizedRecord[]> { | |
| 359 | + const p = raw.payload as { kind?: string }; | |
| 360 | + if (p?.kind === 'auction_lots') return this.normalizeAuctionLots(raw, AuctionLotsPayloadSchema.parse(raw.payload)); | |
| 361 | + const lot = LotPayloadSchema.parse(raw.payload); | |
| 362 | + const { slug } = classifyLot(lot); | |
| 363 | + if (!slug) return []; | |
| 364 | + const text = `${lot.title} ${lot.subtitle ?? ''}`.trim(); | |
| 365 | + const grade = parseGradeFromTitle(text); | |
| 366 | + const grader = spec(lot.specs, 'Grading company', 'Graded by'); | |
| 367 | + const gradeSpec = spec(lot.specs, 'Grade', 'Card grade'); | |
| 368 | + const brandSpec = spec(lot.specs, 'Brand', 'Manufacturer', 'Producer', 'Publisher', 'Winery', 'Distillery'); | |
| 369 | + const model = spec(lot.specs, 'Model', 'Series', 'Theme', 'Set'); | |
| 370 | + const reference = spec(lot.specs, 'Reference number', 'Reference', 'Set number', 'Catalogue number') ?? (['rolex', 'patek_philippe', 'audemars_piguet', 'omega', 'other_watches'].includes(slug) ? watchReference(text) : null); | |
| 371 | + const yearSpec = spec(lot.specs, 'Year', 'Year of production', 'Vintage', 'Year of publication', 'Release year'); | |
| 372 | + const conditionRaw = spec(lot.specs, 'Condition', 'Card condition', 'Condition of the item'); | |
| 373 | + const identifiers: Record<string, string> = { catawiki_lot_id: String(lot.id) }; | |
| 374 | + if (reference) identifiers.reference = reference; | |
| 375 | + if (slug === 'lego_sets') { | |
| 376 | + const n = spec(lot.specs, 'Set number') ?? legoSetNumber(text); | |
| 377 | + if (n) identifiers.lego_set_number = n; | |
| 378 | + } | |
| 379 | + const attributes = { | |
| 380 | + categorySlug: slug, | |
| 381 | + name: lot.title, | |
| 382 | + brand: brandSpec ?? brandFromSlug(slug, text), | |
| 383 | + model, | |
| 384 | + reference, | |
| 385 | + year: yearSpec ? safeYear(yearSpec) : safeYear(text), | |
| 386 | + country: spec(lot.specs, 'Country of origin', 'Country'), | |
| 387 | + material: spec(lot.specs, 'Material'), | |
| 388 | + identifiers, | |
| 389 | + metadata: { auction_id: lot.auction?.id ?? null, auction_title: lot.auction?.title ?? null, auction_categories: lot.auction?.categories ?? [], category_id: lot.categoryId, category_url: lot.categoryUrl, specs: Object.fromEntries(lot.specs.map((s) => [s.name, s.value])), estimate_min_eur: lot.estimateMinEur, estimate_max_eur: lot.estimateMaxEur, seller_country: lot.sellerCountry, seller_pro: lot.sellerIsPro, bids: lot.bidding.bidCount, buyer_fee_note: 'Catawiki charges the buyer an additional protection fee (~9% + VAT) on top of the final bid' }, | |
| 390 | + }; | |
| 391 | + const base = { | |
| 392 | + connectorId: this.meta.id, | |
| 393 | + sourceId: this.meta.sourceId, | |
| 394 | + sourceUrl: lot.url, | |
| 395 | + externalId: String(lot.id), | |
| 396 | + rawTitle: text, | |
| 397 | + description: lot.description, | |
| 398 | + imageUrls: lot.images, | |
| 399 | + attributes, | |
| 400 | + grade: { grader: grader ? (parseGradeFromTitle(`${grader} 1`).grader ?? grader.toLowerCase()) : grade.grader, grade: gradeSpec ?? grade.grade, qualifier: grade.qualifier, certificationNumber: spec(lot.specs, 'Certificate number', 'Certification number') }, | |
| 401 | + condition: { condition: normalizeCondition(slug, conditionRaw), conditionRaw, completeness: null }, | |
| 402 | + observedAt: raw.fetchedAt, | |
| 403 | + parserVersion: this.parserVersion, | |
| 404 | + }; | |
| 405 | + const endsAt = toDate(lot.bidding.biddingEndTime); | |
| 406 | + if (lot.bidding.closed && lot.bidding.sold && lot.bidding.finalBidEur && endsAt) { | |
| 407 | + if (endsAt.getTime() > Date.now() + 86_400_000) return []; | |
| 408 | + return [ | |
| 409 | + NormalizedSaleSchema.parse({ | |
| 410 | + ...base, | |
| 411 | + kind: 'sale', | |
| 412 | + confidence: 0.85, | |
| 413 | + saleType: 'auction', | |
| 414 | + saleDate: endsAt, | |
| 415 | + price: lot.bidding.finalBidEur, | |
| 416 | + currency: 'EUR', | |
| 417 | + buyerPremiumIncluded: false, | |
| 418 | + quantity: 1, | |
| 419 | + isBundle: isBundleTitle(text), | |
| 420 | + location: lot.sellerCountry, | |
| 421 | + auctionHouse: 'Catawiki', | |
| 422 | + lotNumber: null, | |
| 423 | + }), | |
| 424 | + ]; | |
| 425 | + } | |
| 426 | + if (!lot.bidding.closed) { | |
| 427 | + return [ | |
| 428 | + NormalizedAuctionLotSchema.parse({ | |
| 429 | + ...base, | |
| 430 | + kind: 'auction_lot', | |
| 431 | + confidence: 0.8, | |
| 432 | + auctionHouse: 'Catawiki', | |
| 433 | + auctionName: lot.auction?.title ?? null, | |
| 434 | + lotNumber: null, | |
| 435 | + startsAt: toDate(lot.bidding.biddingStartTime), | |
| 436 | + endsAt, | |
| 437 | + estimateLow: lot.estimateMinEur, | |
| 438 | + estimateHigh: lot.estimateMaxEur, | |
| 439 | + currentBid: lot.bidding.finalBidEur, | |
| 440 | + currency: 'EUR', | |
| 441 | + status: 'live', | |
| 442 | + location: lot.sellerCountry, | |
| 443 | + }), | |
| 444 | + ]; | |
| 445 | + } | |
| 446 | + return []; | |
| 447 | + } | |
| 448 | + | |
| 449 | + private normalizeAuctionLots(raw: RawRecordLike, page: AuctionLotsPayload): NormalizedRecord[] { | |
| 450 | + const out: NormalizedRecord[] = []; | |
| 451 | + const a = page.auction; | |
| 452 | + const closeAt = a.closeAt ? new Date(a.closeAt) : null; | |
| 453 | + const startAt = a.startAt ? new Date(a.startAt) : null; | |
| 454 | + if (closeAt && closeAt.getTime() < Date.now()) return []; // stale listing page | |
| 455 | + const catLabel = a.categories[a.categories.length - 1] ?? a.categories[0] ?? null; | |
| 456 | + for (const l of page.lots) { | |
| 457 | + const text = `${l.title} ${l.subtitle ?? ''}`.trim(); | |
| 458 | + const slug = classifyLot({ kind: 'lot', seedHint: page.seedHint, id: l.id, url: l.url, title: l.title, subtitle: l.subtitle, description: null, images: [], categoryId: null, categoryUrl: null, auction: a, specs: [], estimateMinEur: null, estimateMaxEur: null, sellerCountry: null, sellerName: null, sellerIsPro: null, bidding: { closed: false, sold: null, finalBidEur: null, biddingStartTime: null, biddingEndTime: null, bidCount: null, reservePriceMet: null } }).slug; | |
| 459 | + if (!slug) continue; | |
| 460 | + const grade = parseGradeFromTitle(text); | |
| 461 | + out.push( | |
| 462 | + NormalizedAuctionLotSchema.parse({ | |
| 463 | + kind: 'auction_lot', | |
| 464 | + connectorId: this.meta.id, | |
| 465 | + sourceId: this.meta.sourceId, | |
| 466 | + sourceUrl: l.url, | |
| 467 | + externalId: String(l.id), | |
| 468 | + rawTitle: text, | |
| 469 | + description: null, | |
| 470 | + imageUrls: l.imageUrl ? [l.imageUrl] : [], | |
| 471 | + attributes: { categorySlug: slug, name: l.title, brand: brandFromSlug(slug, text), year: safeYear(text), identifiers: { catawiki_lot_id: String(l.id) }, metadata: { auction_id: a.id, auction_title: a.title, auction_categories: a.categories, category_label: catLabel } }, | |
| 472 | + grade: { grader: grade.grader, grade: grade.grade, qualifier: grade.qualifier, certificationNumber: null }, | |
| 473 | + condition: {}, | |
| 474 | + observedAt: raw.fetchedAt, | |
| 475 | + confidence: 0.7, | |
| 476 | + parserVersion: this.parserVersion, | |
| 477 | + auctionHouse: 'Catawiki', | |
| 478 | + auctionName: a.title, | |
| 479 | + lotNumber: null, | |
| 480 | + startsAt: startAt, | |
| 481 | + endsAt: closeAt, | |
| 482 | + estimateLow: null, | |
| 483 | + estimateHigh: null, | |
| 484 | + currentBid: null, | |
| 485 | + currency: 'EUR', | |
| 486 | + status: startAt && startAt.getTime() <= Date.now() ? 'live' : 'upcoming', | |
| 487 | + location: null, | |
| 488 | + }), | |
| 489 | + ); | |
| 490 | + } | |
| 491 | + return out; | |
| 492 | + } | |
| 493 | +} | |
added
connectors/scrapfly/catawiki/meta.json
+51 −0
@@ -0,0 +1,51 @@ | ||
| 1 | +{ | |
| 2 | + "id": "catawiki", | |
| 3 | + "displayName": "Catawiki (closed-lot results & live lots)", | |
| 4 | + "sourceId": "catawiki", | |
| 5 | + "sourceName": "Catawiki", | |
| 6 | + "sourceType": "auction_house", | |
| 7 | + "sourceUrl": "https://www.catawiki.com", | |
| 8 | + "module": "scrapfly/catawiki", | |
| 9 | + "enginePriority": ["scrapfly"], | |
| 10 | + "categories": ["pokemon", "magic_the_gathering", "yugioh", "one_piece_card_game", "disney_lorcana", "other_tcg", "basketball_cards", "baseball_cards", "football_cards", "hockey_cards", "soccer_cards", "f1_cards", "non_sport_cards", "rolex", "patek_philippe", "audemars_piguet", "omega", "other_watches", "pens", "lighters", "marvel_comics", "dc_comics", "independent_comics", "manga", "animation_art", "lego_sets", "funko", "model_cars", "model_trains", "action_figures", "vintage_toys", "designer_toys", "dolls", "plush", "video_games", "coins", "banknotes", "stamps", "medals", "wine", "whisky", "rum", "cognac", "music", "movie_posters", "cameras", "sports_memorabilia", "art", "contemporary_art", "photography", "jewelry", "gemstones", "luxury_handbags", "sneakers", "fashion_streetwear", "automobiles", "motorcycles", "automotive_memorabilia", "books", "maps", "historical_documents", "fossils", "minerals", "meteorites", "antiques", "design_furniture"], | |
| 11 | + "regions": ["NL", "EU"], | |
| 12 | + "languages": ["en"], | |
| 13 | + "currency": ["EUR"], | |
| 14 | + "supportsListings": false, | |
| 15 | + "supportsSold": true, | |
| 16 | + "supportsAuctions": true, | |
| 17 | + "supportsImages": true, | |
| 18 | + "supportsCatalog": false, | |
| 19 | + "supportsPopulation": false, | |
| 20 | + "supportsLookup": true, | |
| 21 | + "refreshFrequencyMinutes": 240, | |
| 22 | + "priority": "high", | |
| 23 | + "trustScore": 0.8, | |
| 24 | + "attributionRequired": true, | |
| 25 | + "termsUrl": "https://www.catawiki.com/en/help/terms-of-use", | |
| 26 | + "accessNotes": "Scrapfly (asp, NL exit) because catawiki.com returns 403 to non-browser clients. Two-phase crawl: (1) discovery — a rendered category page (render_js, ~6 credits) lists the live themed auctions of the category; each auction page /en/a/<id>-slug is server-rendered (__NEXT_DATA__, 1 credit, no JS) with its full lot list and closeAt; live lots are emitted as auction_lot records and remembered in the cursor; (2) harvest — after an auction closes, each remembered lot page /en/l/<id>-slug (1 credit, no JS) exposes biddingBlockResponse {closed, sold, final bid in EUR, biddingEndTime} plus title/subtitle/specifications/expert estimate/images/seller country, and sold lots become sale records. Robots (via Scrapfly): /*/c/*/* and *lot_id are disallowed — we only use single-segment category URLs, auction pages and lot pages, never the lot_id query. Prices: Catawiki's final bid is the hammer; the buyer pays an additional ~9% buyer protection fee, so buyerPremiumIncluded=false (fee noted in metadata). Sale date = biddingEndTime from the source. Unsold closed lots are discarded.", | |
| 27 | + "enabled": true, | |
| 28 | + "schemaVersion": "1.0", | |
| 29 | + "config": { | |
| 30 | + "seeds": [ | |
| 31 | + { "id": 725, "path": "725-trading-cards", "hint": "cards" }, | |
| 32 | + { "id": 299, "path": "299-watches-pens-lighters", "hint": "watches" }, | |
| 33 | + { "id": 139, "path": "139-comics-animation", "hint": "comics" }, | |
| 34 | + { "id": 363, "path": "363-toys-models", "hint": "toys" }, | |
| 35 | + { "id": 165, "path": "165-coins-stamps", "hint": "coins" }, | |
| 36 | + { "id": 720, "path": "720-wine-whisky-spirits", "hint": "wine" }, | |
| 37 | + { "id": 347, "path": "347-music-movies-cameras", "hint": "music" }, | |
| 38 | + { "id": 1097, "path": "1097-sports", "hint": "sports" }, | |
| 39 | + { "id": 714, "path": "714-jewellery-precious-stones", "hint": "jewelry" }, | |
| 40 | + { "id": 721, "path": "721-fashion", "hint": "fashion" }, | |
| 41 | + { "id": 85, "path": "85-art", "hint": "art" }, | |
| 42 | + { "id": 708, "path": "708-classic-cars-motorcycles-automobilia", "hint": "cars" }, | |
| 43 | + { "id": 863, "path": "863-archaeology-natural-history", "hint": "natural_history" }, | |
| 44 | + { "id": 1099, "path": "1099-books-historical-memorabilia", "hint": "books" } | |
| 45 | + ], | |
| 46 | + "maxNewAuctionsPerRun": 30, | |
| 47 | + "maxLotFetchesPerRun": 400, | |
| 48 | + "pendingCap": 6000, | |
| 49 | + "harvestDelayMinutes": 20 | |
| 50 | + } | |
| 51 | +} | |
added
data/fixtures/bonhams/results-1.json
+1106 −0
@@ -0,0 +1,1106 @@ | ||
| 1 | +{ | |
| 2 | + "raw": { | |
| 3 | + "url": "https://www.bonhams.com/auction/32080/hong-kong-online-watches-beyond-time/", | |
| 4 | + "externalId": "32080#1", | |
| 5 | + "kind": "sale", | |
| 6 | + "engine": "api", | |
| 7 | + "httpStatus": 200, | |
| 8 | + "payload": { | |
| 9 | + "kind": "auction_lots", | |
| 10 | + "auction": { | |
| 11 | + "id": "32080", | |
| 12 | + "title": "Hong Kong Online Watches: Beyond Time", | |
| 13 | + "slug": "hong-kong-online-watches-beyond-time", | |
| 14 | + "status": "READY", | |
| 15 | + "type": "ONLINE", | |
| 16 | + "departments": [ | |
| 17 | + "Watches" | |
| 18 | + ], | |
| 19 | + "categories": [ | |
| 20 | + "Handbags, Jewels & Watches" | |
| 21 | + ], | |
| 22 | + "currency": "HKD", | |
| 23 | + "country": "HK", | |
| 24 | + "venue": "Online, Hong Kong", | |
| 25 | + "start": "2026-08-26T04:00:00+00:00", | |
| 26 | + "end": "2026-09-03T08:00:00+00:00", | |
| 27 | + "isEnded": false, | |
| 28 | + "numberOfLots": 84 | |
| 29 | + }, | |
| 30 | + "page": 1, | |
| 31 | + "nbHits": 84, | |
| 32 | + "lots": [ | |
| 33 | + { | |
| 34 | + "lotId": "1001", | |
| 35 | + "lotUniqueId": "6184003", | |
| 36 | + "lotNo": "1001", | |
| 37 | + "title": "ŌTSUKA LŌTEC | NO.5 KAI, A BRAND NEW STAINLESS STEEL SEMI-SKELETONISED WRISTWATCH WITH WANDERING HOURS, CIRCA 2026", | |
| 38 | + "heading": null, | |
| 39 | + "slug": "otsuka-lotec-no5-kai-a-brand-new-stainless-steel-semi-skeletonised-wristwatch-with-wandering-hours-circa-2026", | |
| 40 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25890386-1-5.jpg", | |
| 41 | + "estimateLow": 40000, | |
| 42 | + "estimateHigh": 80000, | |
| 43 | + "hammerPrice": 85000, | |
| 44 | + "hammerPremium": 108800, | |
| 45 | + "startingBid": 36000, | |
| 46 | + "currency": "HKD", | |
| 47 | + "status": "SOLD", | |
| 48 | + "hammerTime": "2026-09-03T08:00:00+00:00", | |
| 49 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 50 | + "department": "Watches", | |
| 51 | + "categories": [], | |
| 52 | + "isEnded": false, | |
| 53 | + "isWithoutReserve": false | |
| 54 | + }, | |
| 55 | + { | |
| 56 | + "lotId": "1002", | |
| 57 | + "lotUniqueId": "6184004", | |
| 58 | + "lotNo": "1002", | |
| 59 | + "title": "[NO RESERVE] ŌTSUKA LŌTEC | NO.7.5, A RARE BRAND NEW STAINLESS STEEL WRISTWATCH WITH JUMPING HOURS, CIRCA 2026", | |
| 60 | + "heading": null, | |
| 61 | + "slug": "no-reserve-otsuka-lotec-no75-a-rare-brand-new-stainless-steel-wristwatch-with-jumping-hours-circa-2026", | |
| 62 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25890386-2-5.jpg", | |
| 63 | + "estimateLow": 20000, | |
| 64 | + "estimateHigh": 40000, | |
| 65 | + "hammerPrice": 65000, | |
| 66 | + "hammerPremium": 83200, | |
| 67 | + "startingBid": 10000, | |
| 68 | + "currency": "HKD", | |
| 69 | + "status": "SOLD", | |
| 70 | + "hammerTime": "2026-09-03T08:01:00+00:00", | |
| 71 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 72 | + "department": "Watches", | |
| 73 | + "categories": [], | |
| 74 | + "isEnded": false, | |
| 75 | + "isWithoutReserve": true | |
| 76 | + }, | |
| 77 | + { | |
| 78 | + "lotId": "1003", | |
| 79 | + "lotUniqueId": "6184005", | |
| 80 | + "lotNo": "1003", | |
| 81 | + "title": "[NO RESERVE] ŌTSUKA LŌTEC | NO.6, A BRAND NEW STAINLESS STEEL WRISTWATCH WITH RETROGRADE HOURS AND MINUTES, CIRCA 2026", | |
| 82 | + "heading": null, | |
| 83 | + "slug": "no-reserve-otsuka-lotec-no6-a-brand-new-stainless-steel-wristwatch-with-retrograde-hours-and-minutes-circa-2026", | |
| 84 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25878926-1-5.jpg", | |
| 85 | + "estimateLow": 20000, | |
| 86 | + "estimateHigh": 40000, | |
| 87 | + "hammerPrice": 65000, | |
| 88 | + "hammerPremium": 83200, | |
| 89 | + "startingBid": 10000, | |
| 90 | + "currency": "HKD", | |
| 91 | + "status": "SOLD", | |
| 92 | + "hammerTime": "2026-09-03T08:02:00+00:00", | |
| 93 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 94 | + "department": "Watches", | |
| 95 | + "categories": [], | |
| 96 | + "isEnded": false, | |
| 97 | + "isWithoutReserve": true | |
| 98 | + }, | |
| 99 | + { | |
| 100 | + "lotId": "1004", | |
| 101 | + "lotUniqueId": "6184006", | |
| 102 | + "lotNo": "1004", | |
| 103 | + "title": "PARMIGIANI FLEURIER | TONDA, REF.PFC914-1020001-100182, A BRAND NEW STAINLESS STEEL BRACELET WATCH WITH DATE, CIRCA 2026", | |
| 104 | + "heading": null, | |
| 105 | + "slug": "parmigiani-fleurier-tonda-refpfc914-1020001-100182-a-brand-new-stainless-steel-bracelet-watch-with-date-circa-2026", | |
| 106 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25901935-11-1.jpg", | |
| 107 | + "estimateLow": 70000, | |
| 108 | + "estimateHigh": 140000, | |
| 109 | + "hammerPrice": 100000, | |
| 110 | + "hammerPremium": 128000, | |
| 111 | + "startingBid": 60000, | |
| 112 | + "currency": "HKD", | |
| 113 | + "status": "SOLD", | |
| 114 | + "hammerTime": "2026-09-03T08:03:00+00:00", | |
| 115 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 116 | + "department": "Watches", | |
| 117 | + "categories": [], | |
| 118 | + "isEnded": false, | |
| 119 | + "isWithoutReserve": false | |
| 120 | + }, | |
| 121 | + { | |
| 122 | + "lotId": "1005", | |
| 123 | + "lotUniqueId": "6184007", | |
| 124 | + "lotNo": "1005", | |
| 125 | + "title": "URWERK | REF.UR-100V T-REX, AN INNOVATIVE AND WELL-PRESERVED LIMITED EDITION BRONZED AND PVD TITANIUM SEMI-SKELETONISED WRISTWATCH WITH REVOLVING SATELLITE HOURS, DISTANCE TRAVELLED ON EARTH AND DISTANCE TRAVELLED BY EARTH INDICATION, CIRCA 2021", | |
| 126 | + "heading": null, | |
| 127 | + "slug": "urwerk-refur-100v-t-rex-an-innovative-and-well-preserved-limited-edition-bronzed-and-pvd-titanium-semi-skeletonised-wristwatch-with-revolving-satellite-hours-distance-travelled-on-earth-and-distance-travelled-by-earth-indication-circa-2021", | |
| 128 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/26/25901935-6-5.jpg", | |
| 129 | + "estimateLow": 220000, | |
| 130 | + "estimateHigh": 440000, | |
| 131 | + "hammerPrice": 200000, | |
| 132 | + "hammerPremium": 256000, | |
| 133 | + "startingBid": 170000, | |
| 134 | + "currency": "HKD", | |
| 135 | + "status": "SOLD", | |
| 136 | + "hammerTime": "2026-09-03T08:04:00+00:00", | |
| 137 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 138 | + "department": "Watches", | |
| 139 | + "categories": [], | |
| 140 | + "isEnded": false, | |
| 141 | + "isWithoutReserve": false | |
| 142 | + }, | |
| 143 | + { | |
| 144 | + "lotId": "1006", | |
| 145 | + "lotUniqueId": "6184008", | |
| 146 | + "lotNo": "1006", | |
| 147 | + "title": "TUDOR | HERITAGE BLACK BAY BRONZE BLUE BUCHERER EDITION, REF.79250B, A SPECIAL EDITION BRONZE WRISTWATCH MADE TO CELEBRATE THE 130TH ANNIVERSARY OF BUCHERER, CIRCA 2018", | |
| 148 | + "heading": null, | |
| 149 | + "slug": "tudor-heritage-black-bay-bronze-blue-bucherer-edition-ref79250b-a-special-edition-bronze-wristwatch-made-to-celebrate-the-130th-anniversary-of-bucherer-circa-2018", | |
| 150 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/21/25907584-2-1.jpg", | |
| 151 | + "estimateLow": 10000, | |
| 152 | + "estimateHigh": 20000, | |
| 153 | + "hammerPrice": 17000, | |
| 154 | + "hammerPremium": 21760, | |
| 155 | + "startingBid": 8500, | |
| 156 | + "currency": "HKD", | |
| 157 | + "status": "SOLD", | |
| 158 | + "hammerTime": "2026-09-03T08:05:00+00:00", | |
| 159 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 160 | + "department": "Watches", | |
| 161 | + "categories": [], | |
| 162 | + "isEnded": false, | |
| 163 | + "isWithoutReserve": false | |
| 164 | + }, | |
| 165 | + { | |
| 166 | + "lotId": "1007", | |
| 167 | + "lotUniqueId": "6184009", | |
| 168 | + "lotNo": "1007", | |
| 169 | + "title": "OMEGA | SPEEDMASTER MOONPHASE \"BLUE SIDE OF THE MOON\", REF.304.93.44.52.03.002, A LIKE NEW CERAMIC CHRONOGRAPH WRISTWATCH WITH MOON PHASES, DATE AND AVENTURINE DIAL, CIRCA 2025", | |
| 170 | + "heading": null, | |
| 171 | + "slug": "omega-speedmaster-moonphase-blue-side-of-the-moon-ref30493445203002-a-like-new-ceramic-chronograph-wristwatch-with-moon-phases-date-and-aventurine-dial-circa-2025", | |
| 172 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/25/25907584-7-4.jpg", | |
| 173 | + "estimateLow": 40000, | |
| 174 | + "estimateHigh": 80000, | |
| 175 | + "hammerPrice": 60000, | |
| 176 | + "hammerPremium": 76800, | |
| 177 | + "startingBid": 32000, | |
| 178 | + "currency": "HKD", | |
| 179 | + "status": "SOLD", | |
| 180 | + "hammerTime": "2026-09-03T08:06:00+00:00", | |
| 181 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 182 | + "department": "Watches", | |
| 183 | + "categories": [], | |
| 184 | + "isEnded": false, | |
| 185 | + "isWithoutReserve": false | |
| 186 | + }, | |
| 187 | + { | |
| 188 | + "lotId": "1008", | |
| 189 | + "lotUniqueId": "6184010", | |
| 190 | + "lotNo": "1008", | |
| 191 | + "title": "OMEGA | SPEEDMASTER \"PROFESSIONAL\", REF.105.012-66, A STAINLESS STEEL CHRONOGRAPH WRISTWATCH WITH CB CASE, CIRCA 1967", | |
| 192 | + "heading": null, | |
| 193 | + "slug": "omega-speedmaster-professional-ref105012-66-a-stainless-steel-chronograph-wristwatch-with-cb-case-circa-1967", | |
| 194 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/21/25902351-1-3.jpg", | |
| 195 | + "estimateLow": 28000, | |
| 196 | + "estimateHigh": 56000, | |
| 197 | + "hammerPrice": 30000, | |
| 198 | + "hammerPremium": 38400, | |
| 199 | + "startingBid": 24000, | |
| 200 | + "currency": "HKD", | |
| 201 | + "status": "SOLD", | |
| 202 | + "hammerTime": "2026-09-03T08:07:00+00:00", | |
| 203 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 204 | + "department": "Watches", | |
| 205 | + "categories": [], | |
| 206 | + "isEnded": false, | |
| 207 | + "isWithoutReserve": false | |
| 208 | + }, | |
| 209 | + { | |
| 210 | + "lotId": "1009", | |
| 211 | + "lotUniqueId": "6184011", | |
| 212 | + "lotNo": "1009", | |
| 213 | + "title": "[NO RESERVE] OMEGA | SPEEDMASTER CHRONOSCOPE, REF.329.30.43.51.03.001, A BRAND NEW STAINLESS STEEL CHRONOGRAPH BRACELET WATCH, CIRCA 2026", | |
| 214 | + "heading": null, | |
| 215 | + "slug": "no-reserve-omega-speedmaster-chronoscope-ref32930435103001-a-brand-new-stainless-steel-chronograph-bracelet-watch-circa-2026", | |
| 216 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25901935-3-1.jpg", | |
| 217 | + "estimateLow": 20000, | |
| 218 | + "estimateHigh": 40000, | |
| 219 | + "hammerPrice": 36000, | |
| 220 | + "hammerPremium": 46080, | |
| 221 | + "startingBid": 10000, | |
| 222 | + "currency": "HKD", | |
| 223 | + "status": "SOLD", | |
| 224 | + "hammerTime": "2026-09-03T08:08:00+00:00", | |
| 225 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 226 | + "department": "Watches", | |
| 227 | + "categories": [], | |
| 228 | + "isEnded": false, | |
| 229 | + "isWithoutReserve": true | |
| 230 | + }, | |
| 231 | + { | |
| 232 | + "lotId": "1010", | |
| 233 | + "lotUniqueId": "6178242", | |
| 234 | + "lotNo": "1010", | |
| 235 | + "title": "ROLEX | GMT-MASTER II, REF.126719BLRO, A WHITE GOLD DUAL TIME BRACELET WATCH WITH METEORITE DIAL, CERAMIC BEZEL AND DATE, CIRCA 2019", | |
| 236 | + "heading": null, | |
| 237 | + "slug": "rolex-gmt-master-ii-ref126719blro-a-white-gold-dual-time-bracelet-watch-with-meteorite-dial-ceramic-bezel-and-date-circa-2019", | |
| 238 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25880933-1-4.jpg", | |
| 239 | + "estimateLow": 300000, | |
| 240 | + "estimateHigh": 600000, | |
| 241 | + "hammerPrice": 360000, | |
| 242 | + "hammerPremium": 460800, | |
| 243 | + "startingBid": 260000, | |
| 244 | + "currency": "HKD", | |
| 245 | + "status": "SOLD", | |
| 246 | + "hammerTime": "2026-09-03T08:09:00+00:00", | |
| 247 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 248 | + "department": "Watches", | |
| 249 | + "categories": [], | |
| 250 | + "isEnded": false, | |
| 251 | + "isWithoutReserve": false | |
| 252 | + }, | |
| 253 | + { | |
| 254 | + "lotId": "1011", | |
| 255 | + "lotUniqueId": "6184012", | |
| 256 | + "lotNo": "1011", | |
| 257 | + "title": "ROLEX | COSMOGRAPH DAYTONA, REF.116519LN, A WHITE GOLD CHRONOGRAPH BRACELET WATCH WITH CERAMIC BEZEL, CIRCA 2017", | |
| 258 | + "heading": null, | |
| 259 | + "slug": "rolex-cosmograph-daytona-ref116519ln-a-white-gold-chronograph-bracelet-watch-with-ceramic-bezel-circa-2017", | |
| 260 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25898045-1-1.jpg", | |
| 261 | + "estimateLow": 200000, | |
| 262 | + "estimateHigh": 400000, | |
| 263 | + "hammerPrice": 300000, | |
| 264 | + "hammerPremium": 384000, | |
| 265 | + "startingBid": 180000, | |
| 266 | + "currency": "HKD", | |
| 267 | + "status": "SOLD", | |
| 268 | + "hammerTime": "2026-09-03T08:10:00+00:00", | |
| 269 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 270 | + "department": "Watches", | |
| 271 | + "categories": [], | |
| 272 | + "isEnded": false, | |
| 273 | + "isWithoutReserve": false | |
| 274 | + }, | |
| 275 | + { | |
| 276 | + "lotId": "1012", | |
| 277 | + "lotUniqueId": "6184013", | |
| 278 | + "lotNo": "1012", | |
| 279 | + "title": "ROLEX | DAY-DATE, REF.1803, A WHITE GOLD BRACELET WATCH WITH DIAMOND-SET INDEXES, DAY AND DATE, CIRCA 1971", | |
| 280 | + "heading": null, | |
| 281 | + "slug": "rolex-day-date-ref1803-a-white-gold-bracelet-watch-with-diamond-set-indexes-day-and-date-circa-1971", | |
| 282 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/26/25864145-13-3.jpg", | |
| 283 | + "estimateLow": 100000, | |
| 284 | + "estimateHigh": 200000, | |
| 285 | + "hammerPrice": 110000, | |
| 286 | + "hammerPremium": 140800, | |
| 287 | + "startingBid": 85000, | |
| 288 | + "currency": "HKD", | |
| 289 | + "status": "SOLD", | |
| 290 | + "hammerTime": "2026-09-03T08:11:00+00:00", | |
| 291 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 292 | + "department": "Watches", | |
| 293 | + "categories": [], | |
| 294 | + "isEnded": false, | |
| 295 | + "isWithoutReserve": false | |
| 296 | + }, | |
| 297 | + { | |
| 298 | + "lotId": "1013", | |
| 299 | + "lotUniqueId": "6184014", | |
| 300 | + "lotNo": "1013", | |
| 301 | + "title": "ROLEX | YACHT-MASTER 37, REF.268622, A PLATINUM AND STAINLESS STEEL WRISTWATCH WITH DATE, CIRCA 2023", | |
| 302 | + "heading": null, | |
| 303 | + "slug": "rolex-yacht-master-37-ref268622-a-platinum-and-stainless-steel-wristwatch-with-date-circa-2023", | |
| 304 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/26/25895221-1-4.jpg", | |
| 305 | + "estimateLow": 70000, | |
| 306 | + "estimateHigh": 140000, | |
| 307 | + "hammerPrice": 80000, | |
| 308 | + "hammerPremium": 102400, | |
| 309 | + "startingBid": 60000, | |
| 310 | + "currency": "HKD", | |
| 311 | + "status": "SOLD", | |
| 312 | + "hammerTime": "2026-09-03T08:12:00+00:00", | |
| 313 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 314 | + "department": "Watches", | |
| 315 | + "categories": [], | |
| 316 | + "isEnded": false, | |
| 317 | + "isWithoutReserve": false | |
| 318 | + }, | |
| 319 | + { | |
| 320 | + "lotId": "1014", | |
| 321 | + "lotUniqueId": "6184015", | |
| 322 | + "lotNo": "1014", | |
| 323 | + "title": "ROLEX | DATEJUST, REF.16014, A STAINLESS STEEL AND WHITE GOLD BRACELET WATCH WITH DATE, CIRCA 1980", | |
| 324 | + "heading": null, | |
| 325 | + "slug": "rolex-datejust-ref16014-a-stainless-steel-and-white-gold-bracelet-watch-with-date-circa-1980", | |
| 326 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25902351-2-1.jpg", | |
| 327 | + "estimateLow": 15000, | |
| 328 | + "estimateHigh": 30000, | |
| 329 | + "hammerPrice": 32000, | |
| 330 | + "hammerPremium": 40960, | |
| 331 | + "startingBid": 13000, | |
| 332 | + "currency": "HKD", | |
| 333 | + "status": "SOLD", | |
| 334 | + "hammerTime": "2026-09-03T08:13:00+00:00", | |
| 335 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 336 | + "department": "Watches", | |
| 337 | + "categories": [], | |
| 338 | + "isEnded": false, | |
| 339 | + "isWithoutReserve": false | |
| 340 | + }, | |
| 341 | + { | |
| 342 | + "lotId": "1015", | |
| 343 | + "lotUniqueId": "6184016", | |
| 344 | + "lotNo": "1015", | |
| 345 | + "title": "ROLEX | CELLINI, REF.6623, A YELLOW GOLD BRACELET WATCH, CIRCA 1990", | |
| 346 | + "heading": null, | |
| 347 | + "slug": "rolex-cellini-ref6623-a-yellow-gold-bracelet-watch-circa-1990", | |
| 348 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/21/25901935-7-2.jpg", | |
| 349 | + "estimateLow": 70000, | |
| 350 | + "estimateHigh": 140000, | |
| 351 | + "hammerPrice": 75000, | |
| 352 | + "hammerPremium": 96000, | |
| 353 | + "startingBid": 60000, | |
| 354 | + "currency": "HKD", | |
| 355 | + "status": "SOLD", | |
| 356 | + "hammerTime": "2026-09-03T08:14:00+00:00", | |
| 357 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 358 | + "department": "Watches", | |
| 359 | + "categories": [], | |
| 360 | + "isEnded": false, | |
| 361 | + "isWithoutReserve": false | |
| 362 | + }, | |
| 363 | + { | |
| 364 | + "lotId": "1016", | |
| 365 | + "lotUniqueId": "6184017", | |
| 366 | + "lotNo": "1016", | |
| 367 | + "title": "ROLEX | PEARLMASTER 34, REF.81318, A YELLOW GOLD AND DIAMOND-SET BRACELET WATCH WITH MOTHER-OF-PEARL DIAL, CIRCA 2009", | |
| 368 | + "heading": null, | |
| 369 | + "slug": "rolex-pearlmaster-34-ref81318-a-yellow-gold-and-diamond-set-bracelet-watch-with-mother-of-pearl-dial-circa-2009", | |
| 370 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25898045-5-1.jpg", | |
| 371 | + "estimateLow": 60000, | |
| 372 | + "estimateHigh": 120000, | |
| 373 | + "hammerPrice": 130000, | |
| 374 | + "hammerPremium": 166400, | |
| 375 | + "startingBid": 50000, | |
| 376 | + "currency": "HKD", | |
| 377 | + "status": "SOLD", | |
| 378 | + "hammerTime": "2026-09-03T08:15:00+00:00", | |
| 379 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 380 | + "department": "Watches", | |
| 381 | + "categories": [], | |
| 382 | + "isEnded": false, | |
| 383 | + "isWithoutReserve": false | |
| 384 | + }, | |
| 385 | + { | |
| 386 | + "lotId": "1017", | |
| 387 | + "lotUniqueId": "6184018", | |
| 388 | + "lotNo": "1017", | |
| 389 | + "title": "RICHARD MILLE | REF.RM07-01 \"RED LIP\", A RARE PINK GOLD SEMI-SKELETONISED WRISTWATCH WITH RED JASPER AND DIAMOND-SET DIAL, CIRCA 2016", | |
| 390 | + "heading": "PROPERTY FROM AN IMPORTANT PRIVATE COLLECTOR\n重要私人珍藏", | |
| 391 | + "slug": "richard-mille-refrm07-01-red-lip-a-rare-pink-gold-semi-skeletonised-wristwatch-with-red-jasper-and-diamond-set-dial-circa-2016", | |
| 392 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25902455-1-1.jpg", | |
| 393 | + "estimateLow": 700000, | |
| 394 | + "estimateHigh": 1400000, | |
| 395 | + "hammerPrice": 750000, | |
| 396 | + "hammerPremium": 956500, | |
| 397 | + "startingBid": 600000, | |
| 398 | + "currency": "HKD", | |
| 399 | + "status": "SOLD", | |
| 400 | + "hammerTime": "2026-09-03T08:16:00+00:00", | |
| 401 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 402 | + "department": "Watches", | |
| 403 | + "categories": [], | |
| 404 | + "isEnded": false, | |
| 405 | + "isWithoutReserve": false | |
| 406 | + }, | |
| 407 | + { | |
| 408 | + "lotId": "1018", | |
| 409 | + "lotUniqueId": "6184019", | |
| 410 | + "lotNo": "1018", | |
| 411 | + "title": "PATEK PHILIPPE | NAUTILUS, REF.7010/1R-013, A PINK GOLD AND DIAMOND-SET BRACELET WATCH WITH DATE, CIRCA 2024", | |
| 412 | + "heading": "PROPERTY FROM AN IMPORTANT PRIVATE COLLECTOR\n重要私人珍藏", | |
| 413 | + "slug": "patek-philippe-nautilus-ref70101r-013-a-pink-gold-and-diamond-set-bracelet-watch-with-date-circa-2024", | |
| 414 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25902455-3-1.jpg", | |
| 415 | + "estimateLow": 480000, | |
| 416 | + "estimateHigh": 900000, | |
| 417 | + "hammerPrice": 700000, | |
| 418 | + "hammerPremium": 893000, | |
| 419 | + "startingBid": 400000, | |
| 420 | + "currency": "HKD", | |
| 421 | + "status": "SOLD", | |
| 422 | + "hammerTime": "2026-09-03T08:17:00+00:00", | |
| 423 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 424 | + "department": "Watches", | |
| 425 | + "categories": [], | |
| 426 | + "isEnded": false, | |
| 427 | + "isWithoutReserve": false | |
| 428 | + }, | |
| 429 | + { | |
| 430 | + "lotId": "1019", | |
| 431 | + "lotUniqueId": "6184020", | |
| 432 | + "lotNo": "1019", | |
| 433 | + "title": "PATEK PHILIPPE | AQUANAUT, REF.5067A-001, A STAINLESS STEEL AND DIAMOND-SET WRISTWATCH WITH DATE, CIRCA 2015", | |
| 434 | + "heading": "PROPERTY FROM AN IMPORTANT PRIVATE COLLECTOR\n重要私人珍藏", | |
| 435 | + "slug": "patek-philippe-aquanaut-ref5067a-001-a-stainless-steel-and-diamond-set-wristwatch-with-date-circa-2015", | |
| 436 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25902455-6-1.jpg", | |
| 437 | + "estimateLow": 150000, | |
| 438 | + "estimateHigh": 300000, | |
| 439 | + "hammerPrice": 260000, | |
| 440 | + "hammerPremium": 332800, | |
| 441 | + "startingBid": 130000, | |
| 442 | + "currency": "HKD", | |
| 443 | + "status": "SOLD", | |
| 444 | + "hammerTime": "2026-09-03T08:18:00+00:00", | |
| 445 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 446 | + "department": "Watches", | |
| 447 | + "categories": [], | |
| 448 | + "isEnded": false, | |
| 449 | + "isWithoutReserve": false | |
| 450 | + }, | |
| 451 | + { | |
| 452 | + "lotId": "1020", | |
| 453 | + "lotUniqueId": "6184021", | |
| 454 | + "lotNo": "1020", | |
| 455 | + "title": "PATEK PHILIPPE | CALATRAVA, REF.7200/200R-001, A PINK GOLD AND DIAMOND-SET WRISTWATCH, CIRCA 2023", | |
| 456 | + "heading": "PROPERTY FROM AN IMPORTANT PRIVATE COLLECTOR\n重要私人珍藏", | |
| 457 | + "slug": "patek-philippe-calatrava-ref7200200r-001-a-pink-gold-and-diamond-set-wristwatch-circa-2023", | |
| 458 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25902455-5-1.jpg", | |
| 459 | + "estimateLow": 100000, | |
| 460 | + "estimateHigh": 200000, | |
| 461 | + "hammerPrice": 120000, | |
| 462 | + "hammerPremium": 153600, | |
| 463 | + "startingBid": 90000, | |
| 464 | + "currency": "HKD", | |
| 465 | + "status": "SOLD", | |
| 466 | + "hammerTime": "2026-09-03T08:19:00+00:00", | |
| 467 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 468 | + "department": "Watches", | |
| 469 | + "categories": [], | |
| 470 | + "isEnded": false, | |
| 471 | + "isWithoutReserve": false | |
| 472 | + }, | |
| 473 | + { | |
| 474 | + "lotId": "1021", | |
| 475 | + "lotUniqueId": "6184022", | |
| 476 | + "lotNo": "1021", | |
| 477 | + "title": "PATEK PHILIPPE | CALATRAVA TRAVEL TIME, REF.4934G-001, A FINE WHITE GOLD AND DIAMOND-SET DUAL TIME WRISTWATCH WITH MOTHER-OF-PEARL DIAL, CIRCA 2008", | |
| 478 | + "heading": null, | |
| 479 | + "slug": "patek-philippe-calatrava-travel-time-ref4934g-001-a-fine-white-gold-and-diamond-set-dual-time-wristwatch-with-mother-of-pearl-dial-circa-2008", | |
| 480 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25898045-4-1.jpg", | |
| 481 | + "estimateLow": 110000, | |
| 482 | + "estimateHigh": 220000, | |
| 483 | + "hammerPrice": 110000, | |
| 484 | + "hammerPremium": 140800, | |
| 485 | + "startingBid": 80000, | |
| 486 | + "currency": "HKD", | |
| 487 | + "status": "SOLD", | |
| 488 | + "hammerTime": "2026-09-03T08:20:00+00:00", | |
| 489 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 490 | + "department": "Watches", | |
| 491 | + "categories": [], | |
| 492 | + "isEnded": false, | |
| 493 | + "isWithoutReserve": false | |
| 494 | + }, | |
| 495 | + { | |
| 496 | + "lotId": "1022", | |
| 497 | + "lotUniqueId": "6184023", | |
| 498 | + "lotNo": "1022", | |
| 499 | + "title": "PATEK PHILIPPE | CALATRAVA PILOT TRAVEL TIME, REF.7234A-001, A RARE LIMITED EDITION STAINLESS STEEL DUAL TIME WRISTWATCH WITH DAY/NIGHT INDICATION AND DATE, MADE EXCLUSIVELY FOR THE SINGAPORE WATCH ART GRAND EXHIBITION, CIRCA 2020", | |
| 500 | + "heading": "PROPERTY FROM AN IMPORTANT PRIVATE COLLECTOR\n重要私人珍藏", | |
| 501 | + "slug": "patek-philippe-calatrava-pilot-travel-time-ref7234a-001-a-rare-limited-edition-stainless-steel-dual-time-wristwatch-with-daynight-indication-and-date-made-exclusively-for-the-singapore-watch-art-grand-exhibition-circa-2020", | |
| 502 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25902455-2-1.jpg", | |
| 503 | + "estimateLow": 200000, | |
| 504 | + "estimateHigh": 400000, | |
| 505 | + "hammerPrice": 280000, | |
| 506 | + "hammerPremium": 358400, | |
| 507 | + "startingBid": 170000, | |
| 508 | + "currency": "HKD", | |
| 509 | + "status": "SOLD", | |
| 510 | + "hammerTime": "2026-09-03T08:21:00+00:00", | |
| 511 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 512 | + "department": "Watches", | |
| 513 | + "categories": [], | |
| 514 | + "isEnded": false, | |
| 515 | + "isWithoutReserve": false | |
| 516 | + }, | |
| 517 | + { | |
| 518 | + "lotId": "1023", | |
| 519 | + "lotUniqueId": "6184024", | |
| 520 | + "lotNo": "1023", | |
| 521 | + "title": "PATEK PHILIPPE | WORLD TIME, REF.7130G-014, A WHITE GOLD AND DIAMOND-SET WORLD TIME WRISTWATCH, CIRCA 2018", | |
| 522 | + "heading": null, | |
| 523 | + "slug": "patek-philippe-world-time-ref7130g-014-a-white-gold-and-diamond-set-world-time-wristwatch-circa-2018", | |
| 524 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25902327-1-1.jpg", | |
| 525 | + "estimateLow": 200000, | |
| 526 | + "estimateHigh": 400000, | |
| 527 | + "hammerPrice": 260000, | |
| 528 | + "hammerPremium": 332800, | |
| 529 | + "startingBid": 180000, | |
| 530 | + "currency": "HKD", | |
| 531 | + "status": "SOLD", | |
| 532 | + "hammerTime": "2026-09-03T08:22:00+00:00", | |
| 533 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 534 | + "department": "Watches", | |
| 535 | + "categories": [], | |
| 536 | + "isEnded": false, | |
| 537 | + "isWithoutReserve": false | |
| 538 | + }, | |
| 539 | + { | |
| 540 | + "lotId": "1024", | |
| 541 | + "lotUniqueId": "6184025", | |
| 542 | + "lotNo": "1024", | |
| 543 | + "title": "PATEK PHILIPPE | GONDOLO SERATA, REF.4962/200R-010, A LADY'S PINK GOLD AND SPESSARTINE-SET WRISTWATCH WITH ZEBRA MOTIF, CIRCA 2025", | |
| 544 | + "heading": null, | |
| 545 | + "slug": "patek-philippe-gondolo-serata-ref4962200r-010-a-ladys-pink-gold-and-spessartine-set-wristwatch-with-zebra-motif-circa-2025", | |
| 546 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/21/25850273-2-6.jpg", | |
| 547 | + "estimateLow": 130000, | |
| 548 | + "estimateHigh": 260000, | |
| 549 | + "hammerPrice": 160000, | |
| 550 | + "hammerPremium": 204800, | |
| 551 | + "startingBid": 110000, | |
| 552 | + "currency": "HKD", | |
| 553 | + "status": "SOLD", | |
| 554 | + "hammerTime": "2026-09-03T08:23:00+00:00", | |
| 555 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 556 | + "department": "Watches", | |
| 557 | + "categories": [], | |
| 558 | + "isEnded": false, | |
| 559 | + "isWithoutReserve": false | |
| 560 | + }, | |
| 561 | + { | |
| 562 | + "lotId": "1025", | |
| 563 | + "lotUniqueId": "6184026", | |
| 564 | + "lotNo": "1025", | |
| 565 | + "title": "PATEK PHILIPPE | GRAND COMPLICATIONS, REF.5320G-001, A WHITE GOLD PERPETUAL CALENDAR WRISTWATCH WITH MOON PHASES, LEAP YEAR AND DAY/NIGHT INDICATION, CIRCA 2022", | |
| 566 | + "heading": null, | |
| 567 | + "slug": "patek-philippe-grand-complications-ref5320g-001-a-white-gold-perpetual-calendar-wristwatch-with-moon-phases-leap-year-and-daynight-indication-circa-2022", | |
| 568 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/24/25902343-1-5.jpg", | |
| 569 | + "estimateLow": 280000, | |
| 570 | + "estimateHigh": 560000, | |
| 571 | + "hammerPrice": 380000, | |
| 572 | + "hammerPremium": 486400, | |
| 573 | + "startingBid": 240000, | |
| 574 | + "currency": "HKD", | |
| 575 | + "status": "SOLD", | |
| 576 | + "hammerTime": "2026-09-03T08:24:00+00:00", | |
| 577 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 578 | + "department": "Watches", | |
| 579 | + "categories": [], | |
| 580 | + "isEnded": false, | |
| 581 | + "isWithoutReserve": false | |
| 582 | + }, | |
| 583 | + { | |
| 584 | + "lotId": "1026", | |
| 585 | + "lotUniqueId": "6184027", | |
| 586 | + "lotNo": "1026", | |
| 587 | + "title": "[NO RESERVE] PATEK PHILIPPE | A SET OF ACCESSORIES INCLUDING A WATCH CYLINDER, A LEATHER TRAVEL CASE AND LIMOGES PORCELAIN DISH", | |
| 588 | + "heading": null, | |
| 589 | + "slug": "no-reserve-patek-philippe-a-set-of-accessories-including-a-watch-cylinder-a-leather-travel-case-and-limoges-porcelain-dish", | |
| 590 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25877737-1-4.jpg", | |
| 591 | + "estimateLow": 15000, | |
| 592 | + "estimateHigh": 30000, | |
| 593 | + "hammerPrice": 4200, | |
| 594 | + "hammerPremium": 5376, | |
| 595 | + "startingBid": 3000, | |
| 596 | + "currency": "HKD", | |
| 597 | + "status": "SOLD", | |
| 598 | + "hammerTime": "2026-09-03T08:25:00+00:00", | |
| 599 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 600 | + "department": "Watches", | |
| 601 | + "categories": [], | |
| 602 | + "isEnded": false, | |
| 603 | + "isWithoutReserve": true | |
| 604 | + }, | |
| 605 | + { | |
| 606 | + "lotId": "1027", | |
| 607 | + "lotUniqueId": "6184028", | |
| 608 | + "lotNo": "1027", | |
| 609 | + "title": "A.LANGE & SÖHNE | LANGE 1 SOIRÉE, REF.110.041, A SUPER RARE LIMITED PRODUCTION PLATINUM WRISTWATCH WITH TAHITIAN MOTHER-OF-PEARL DIAL AND DATE, CIRCA 2003", | |
| 610 | + "heading": null, | |
| 611 | + "slug": "alange-and-sohne-lange-1-soiree-ref110041-a-super-rare-limited-production-platinum-wristwatch-with-tahitian-mother-of-pearl-dial-and-date-circa-2003", | |
| 612 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25902865-12-1.jpg", | |
| 613 | + "estimateLow": 400000, | |
| 614 | + "estimateHigh": 800000, | |
| 615 | + "hammerPrice": 4000000, | |
| 616 | + "hammerPremium": 5084000, | |
| 617 | + "startingBid": 360000, | |
| 618 | + "currency": "HKD", | |
| 619 | + "status": "SOLD", | |
| 620 | + "hammerTime": "2026-09-03T08:26:00+00:00", | |
| 621 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 622 | + "department": "Watches", | |
| 623 | + "categories": [], | |
| 624 | + "isEnded": false, | |
| 625 | + "isWithoutReserve": false | |
| 626 | + }, | |
| 627 | + { | |
| 628 | + "lotId": "1028", | |
| 629 | + "lotUniqueId": "6184029", | |
| 630 | + "lotNo": "1028", | |
| 631 | + "title": "GLASHÜTTE ORIGINAL | PANOMATIC TOURBILLON, REF.93-01-01-01-04, A LIMITED EDITION PINK GOLD TOURBILLON WRISTWATCH WITH DATE, CIRCA 2014", | |
| 632 | + "heading": null, | |
| 633 | + "slug": "glashutte-original-panomatic-tourbillon-ref93-01-01-01-04-a-limited-edition-pink-gold-tourbillon-wristwatch-with-date-circa-2014", | |
| 634 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/21/25907584-3-1.jpg", | |
| 635 | + "estimateLow": 120000, | |
| 636 | + "estimateHigh": 240000, | |
| 637 | + "hammerPrice": 140000, | |
| 638 | + "hammerPremium": 179200, | |
| 639 | + "startingBid": 100000, | |
| 640 | + "currency": "HKD", | |
| 641 | + "status": "SOLD", | |
| 642 | + "hammerTime": "2026-09-03T08:27:00+00:00", | |
| 643 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 644 | + "department": "Watches", | |
| 645 | + "categories": [], | |
| 646 | + "isEnded": false, | |
| 647 | + "isWithoutReserve": false | |
| 648 | + }, | |
| 649 | + { | |
| 650 | + "lotId": "1029", | |
| 651 | + "lotUniqueId": "6184030", | |
| 652 | + "lotNo": "1029", | |
| 653 | + "title": "GLASHÜTTE ORIGINAL | PANOMATIC CHRONO, REF.95-01-03-03-04, A LIMITED EDITION PLATINUM CHRONOGRAPH WRISTWATCH WITH DATE, CIRCA 2005", | |
| 654 | + "heading": null, | |
| 655 | + "slug": "glashutte-original-panomatic-chrono-ref95-01-03-03-04-a-limited-edition-platinum-chronograph-wristwatch-with-date-circa-2005", | |
| 656 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/21/25907584-4-1.jpg", | |
| 657 | + "estimateLow": 60000, | |
| 658 | + "estimateHigh": 120000, | |
| 659 | + "hammerPrice": 110000, | |
| 660 | + "hammerPremium": 140800, | |
| 661 | + "startingBid": 48000, | |
| 662 | + "currency": "HKD", | |
| 663 | + "status": "SOLD", | |
| 664 | + "hammerTime": "2026-09-03T08:28:00+00:00", | |
| 665 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 666 | + "department": "Watches", | |
| 667 | + "categories": [], | |
| 668 | + "isEnded": false, | |
| 669 | + "isWithoutReserve": false | |
| 670 | + }, | |
| 671 | + { | |
| 672 | + "lotId": "1030", | |
| 673 | + "lotUniqueId": "6184031", | |
| 674 | + "lotNo": "1030", | |
| 675 | + "title": "GLASHÜTTE ORIGINAL | SENATOR CHRONOGRAPH \"100 JAHRE WEMPE\", REF.49-11-02-02-04, A LIMITED EDITION STAINLESS STEEL CHRONOGRAPH WRISTWATCH, CIRCA 2006", | |
| 676 | + "heading": null, | |
| 677 | + "slug": "glashutte-original-senator-chronograph-100-jahre-wempe-ref49-11-02-02-04-a-limited-edition-stainless-steel-chronograph-wristwatch-circa-2006", | |
| 678 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25895855-2-1.jpg", | |
| 679 | + "estimateLow": 34000, | |
| 680 | + "estimateHigh": 68000, | |
| 681 | + "hammerPrice": 34000, | |
| 682 | + "hammerPremium": 43520, | |
| 683 | + "startingBid": 30000, | |
| 684 | + "currency": "HKD", | |
| 685 | + "status": "SOLD", | |
| 686 | + "hammerTime": "2026-09-03T08:29:00+00:00", | |
| 687 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 688 | + "department": "Watches", | |
| 689 | + "categories": [], | |
| 690 | + "isEnded": false, | |
| 691 | + "isWithoutReserve": false | |
| 692 | + }, | |
| 693 | + { | |
| 694 | + "lotId": "1031", | |
| 695 | + "lotUniqueId": "6184032", | |
| 696 | + "lotNo": "1031", | |
| 697 | + "title": "IWC | PORTUGUESE, REF.IW500106, A WHITE GOLD WRISTWATCH WITH POWER RESERVE INDICATOR AND DATE, CIRCA 2020", | |
| 698 | + "heading": null, | |
| 699 | + "slug": "iwc-portuguese-refiw500106-a-white-gold-wristwatch-with-power-reserve-indicator-and-date-circa-2020", | |
| 700 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/21/25907584-1-1.jpg", | |
| 701 | + "estimateLow": 50000, | |
| 702 | + "estimateHigh": 100000, | |
| 703 | + "hammerPrice": 50000, | |
| 704 | + "hammerPremium": 64000, | |
| 705 | + "startingBid": 40000, | |
| 706 | + "currency": "HKD", | |
| 707 | + "status": "SOLD", | |
| 708 | + "hammerTime": "2026-09-03T08:30:00+00:00", | |
| 709 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 710 | + "department": "Watches", | |
| 711 | + "categories": [], | |
| 712 | + "isEnded": false, | |
| 713 | + "isWithoutReserve": false | |
| 714 | + }, | |
| 715 | + { | |
| 716 | + "lotId": "1032", | |
| 717 | + "lotUniqueId": "6184033", | |
| 718 | + "lotNo": "1032", | |
| 719 | + "title": "JACOB & CO | THE WORLD IS YOURS DUAL TIME, REF.DT100.10.AA.AA.A, A BRAND NEW STAINLESS STEEL DUAL TIME ZONE WRISTWATCH, CIRCA 2026", | |
| 720 | + "heading": null, | |
| 721 | + "slug": "jacob-and-co-the-world-is-yours-dual-time-refdt10010aaaaa-a-brand-new-stainless-steel-dual-time-zone-wristwatch-circa-2026", | |
| 722 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/26/25832097-18-7.jpg", | |
| 723 | + "estimateLow": 90000, | |
| 724 | + "estimateHigh": 180000, | |
| 725 | + "hammerPrice": 120000, | |
| 726 | + "hammerPremium": 153600, | |
| 727 | + "startingBid": 80000, | |
| 728 | + "currency": "HKD", | |
| 729 | + "status": "SOLD", | |
| 730 | + "hammerTime": "2026-09-03T08:31:00+00:00", | |
| 731 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 732 | + "department": "Watches", | |
| 733 | + "categories": [], | |
| 734 | + "isEnded": false, | |
| 735 | + "isWithoutReserve": false | |
| 736 | + }, | |
| 737 | + { | |
| 738 | + "lotId": "1033", | |
| 739 | + "lotUniqueId": "6184034", | |
| 740 | + "lotNo": "1033", | |
| 741 | + "title": "VACHERON CONSTANTIN | PATRIMONY RETROGRADE DAY DATE, REF.86020/000R-9239, A PINK GOLD WRISTWATCH WITH RETROGRADE DAY AND DATE, CIRCA 2014", | |
| 742 | + "heading": null, | |
| 743 | + "slug": "vacheron-constantin-patrimony-retrograde-day-date-ref86020000r-9239-a-pink-gold-wristwatch-with-retrograde-day-and-date-circa-2014", | |
| 744 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25902865-11-1.jpg", | |
| 745 | + "estimateLow": 120000, | |
| 746 | + "estimateHigh": 240000, | |
| 747 | + "hammerPrice": 170000, | |
| 748 | + "hammerPremium": 217600, | |
| 749 | + "startingBid": 100000, | |
| 750 | + "currency": "HKD", | |
| 751 | + "status": "SOLD", | |
| 752 | + "hammerTime": "2026-09-03T08:32:00+00:00", | |
| 753 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 754 | + "department": "Watches", | |
| 755 | + "categories": [], | |
| 756 | + "isEnded": false, | |
| 757 | + "isWithoutReserve": false | |
| 758 | + }, | |
| 759 | + { | |
| 760 | + "lotId": "1034", | |
| 761 | + "lotUniqueId": "6184035", | |
| 762 | + "lotNo": "1034", | |
| 763 | + "title": "VACHERON CONSTANTIN | PATRIMONY MOON PHASE RETROGRADE DATE, REF.4010U/000G-H070, A NEW OLD STOCK WHITE GOLD WRISTWATCH WITH RETROGRADE DATE AND MOON PHASES, CIRCA 2025", | |
| 764 | + "heading": null, | |
| 765 | + "slug": "vacheron-constantin-patrimony-moon-phase-retrograde-date-ref4010u000g-h070-a-new-old-stock-white-gold-wristwatch-with-retrograde-date-and-moon-phases-circa-2025", | |
| 766 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25901935-12-1.jpg", | |
| 767 | + "estimateLow": 100000, | |
| 768 | + "estimateHigh": 200000, | |
| 769 | + "hammerPrice": 190000, | |
| 770 | + "hammerPremium": 243200, | |
| 771 | + "startingBid": 90000, | |
| 772 | + "currency": "HKD", | |
| 773 | + "status": "SOLD", | |
| 774 | + "hammerTime": "2026-09-03T08:33:00+00:00", | |
| 775 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 776 | + "department": "Watches", | |
| 777 | + "categories": [], | |
| 778 | + "isEnded": false, | |
| 779 | + "isWithoutReserve": false | |
| 780 | + }, | |
| 781 | + { | |
| 782 | + "lotId": "1035", | |
| 783 | + "lotUniqueId": "6184036", | |
| 784 | + "lotNo": "1035", | |
| 785 | + "title": "VACHERON CONSTANTIN | MALTE GRAND CLASSIQUE, REF.81000/000J, A YELLOW GOLD WRISTWATCH WITH DIAMOND-SET INDEXES, CIRCA 2008", | |
| 786 | + "heading": null, | |
| 787 | + "slug": "vacheron-constantin-malte-grand-classique-ref81000000j-a-yellow-gold-wristwatch-with-diamond-set-indexes-circa-2008", | |
| 788 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25895855-1-1.jpg", | |
| 789 | + "estimateLow": 46000, | |
| 790 | + "estimateHigh": 92000, | |
| 791 | + "hammerPrice": 48000, | |
| 792 | + "hammerPremium": 61440, | |
| 793 | + "startingBid": 42000, | |
| 794 | + "currency": "HKD", | |
| 795 | + "status": "SOLD", | |
| 796 | + "hammerTime": "2026-09-03T08:34:00+00:00", | |
| 797 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 798 | + "department": "Watches", | |
| 799 | + "categories": [], | |
| 800 | + "isEnded": false, | |
| 801 | + "isWithoutReserve": false | |
| 802 | + }, | |
| 803 | + { | |
| 804 | + "lotId": "1036", | |
| 805 | + "lotUniqueId": "6184037", | |
| 806 | + "lotNo": "1036", | |
| 807 | + "title": "VACHERON CONSTANTIN | PATRIMONY, REF.34170/000J-3, A YELLOW GOLD WRISTWATCH, CIRCA 1994", | |
| 808 | + "heading": null, | |
| 809 | + "slug": "vacheron-constantin-patrimony-ref34170000j-3-a-yellow-gold-wristwatch-circa-1994", | |
| 810 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25901796-3-1.jpg", | |
| 811 | + "estimateLow": 34000, | |
| 812 | + "estimateHigh": 68000, | |
| 813 | + "hammerPrice": 42000, | |
| 814 | + "hammerPremium": 53760, | |
| 815 | + "startingBid": 30000, | |
| 816 | + "currency": "HKD", | |
| 817 | + "status": "SOLD", | |
| 818 | + "hammerTime": "2026-09-03T08:35:00+00:00", | |
| 819 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 820 | + "department": "Watches", | |
| 821 | + "categories": [], | |
| 822 | + "isEnded": false, | |
| 823 | + "isWithoutReserve": false | |
| 824 | + }, | |
| 825 | + { | |
| 826 | + "lotId": "1037", | |
| 827 | + "lotUniqueId": "6184038", | |
| 828 | + "lotNo": "1037", | |
| 829 | + "title": "[NO RESERVE] BLANCPAIN | VILLERET ULTRA SLIM, REF.0072-1418-55, A YELLOW GOLD WRISTWATCH, CIRCA 1990", | |
| 830 | + "heading": null, | |
| 831 | + "slug": "no-reserve-blancpain-villeret-ultra-slim-ref0072-1418-55-a-yellow-gold-wristwatch-circa-1990", | |
| 832 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/21/25907584-6-1.jpg", | |
| 833 | + "estimateLow": 20000, | |
| 834 | + "estimateHigh": 40000, | |
| 835 | + "hammerPrice": 24000, | |
| 836 | + "hammerPremium": 30720, | |
| 837 | + "startingBid": 10000, | |
| 838 | + "currency": "HKD", | |
| 839 | + "status": "SOLD", | |
| 840 | + "hammerTime": "2026-09-03T08:36:00+00:00", | |
| 841 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 842 | + "department": "Watches", | |
| 843 | + "categories": [], | |
| 844 | + "isEnded": false, | |
| 845 | + "isWithoutReserve": true | |
| 846 | + }, | |
| 847 | + { | |
| 848 | + "lotId": "1038", | |
| 849 | + "lotUniqueId": "6184039", | |
| 850 | + "lotNo": "1038", | |
| 851 | + "title": "GIRARD-PERREGAUX | GYROMATIC, A 14K YELLOW GOLD WRISTWATCH, CIRCA 1960", | |
| 852 | + "heading": null, | |
| 853 | + "slug": "girard-perregaux-gyromatic-a-14k-yellow-gold-wristwatch-circa-1960", | |
| 854 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25901796-1-1.jpg", | |
| 855 | + "estimateLow": 12000, | |
| 856 | + "estimateHigh": 24000, | |
| 857 | + "hammerPrice": 12000, | |
| 858 | + "hammerPremium": 15360, | |
| 859 | + "startingBid": 10000, | |
| 860 | + "currency": "HKD", | |
| 861 | + "status": "SOLD", | |
| 862 | + "hammerTime": "2026-09-03T08:37:00+00:00", | |
| 863 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 864 | + "department": "Watches", | |
| 865 | + "categories": [], | |
| 866 | + "isEnded": false, | |
| 867 | + "isWithoutReserve": false | |
| 868 | + }, | |
| 869 | + { | |
| 870 | + "lotId": "1039", | |
| 871 | + "lotUniqueId": "6184040", | |
| 872 | + "lotNo": "1039", | |
| 873 | + "title": "CHOPARD | POINÇON DE GENÈVE 125TH ANNIVERSARY EDITION, REF.161932-5001, A LIMITED EDITION PINK GOLD WRISTWATCH WITH DATE, CIRCA 2011", | |
| 874 | + "heading": null, | |
| 875 | + "slug": "chopard-poincon-de-geneve-125th-anniversary-edition-ref161932-5001-a-limited-edition-pink-gold-wristwatch-with-date-circa-2011", | |
| 876 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/26/25896383-1-9.jpg", | |
| 877 | + "estimateLow": 55000, | |
| 878 | + "estimateHigh": 110000, | |
| 879 | + "hammerPrice": 60000, | |
| 880 | + "hammerPremium": 76800, | |
| 881 | + "startingBid": 48000, | |
| 882 | + "currency": "HKD", | |
| 883 | + "status": "SOLD", | |
| 884 | + "hammerTime": "2026-09-03T08:38:00+00:00", | |
| 885 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 886 | + "department": "Watches", | |
| 887 | + "categories": [], | |
| 888 | + "isEnded": false, | |
| 889 | + "isWithoutReserve": false | |
| 890 | + }, | |
| 891 | + { | |
| 892 | + "lotId": "1040", | |
| 893 | + "lotUniqueId": "6184041", | |
| 894 | + "lotNo": "1040", | |
| 895 | + "title": "[NO RESERVE] CHOPARD | MILLIE MIGLIA, REF.8407, A LIMITED EDITION TITANIUM CHRONOGRAPH WRISTWATCH WITH DATE, CIRCA 2001", | |
| 896 | + "heading": null, | |
| 897 | + "slug": "no-reserve-chopard-millie-miglia-ref8407-a-limited-edition-titanium-chronograph-wristwatch-with-date-circa-2001", | |
| 898 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25902397-2-1.jpg", | |
| 899 | + "estimateLow": 20000, | |
| 900 | + "estimateHigh": 40000, | |
| 901 | + "hammerPrice": 20000, | |
| 902 | + "hammerPremium": 25600, | |
| 903 | + "startingBid": 10000, | |
| 904 | + "currency": "HKD", | |
| 905 | + "status": "SOLD", | |
| 906 | + "hammerTime": "2026-09-03T08:39:00+00:00", | |
| 907 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 908 | + "department": "Watches", | |
| 909 | + "categories": [], | |
| 910 | + "isEnded": false, | |
| 911 | + "isWithoutReserve": true | |
| 912 | + }, | |
| 913 | + { | |
| 914 | + "lotId": "1041", | |
| 915 | + "lotUniqueId": "6184042", | |
| 916 | + "lotNo": "1041", | |
| 917 | + "title": "AUDEMARS PIGUET | ROYAL OAK OFFSHORE \"JUAN PABLO MONTOYA, REF.26030IO.OO.D001IN.01, A LIMITED EDITION TITANIUM AND CARBON FIBRE CHRONOGRAPH WRISTWATCH WITH DATE, CIRCA 2005", | |
| 918 | + "heading": null, | |
| 919 | + "slug": "audemars-piguet-royal-oak-offshore-juan-pablo-montoya-ref26030ioood001in01-a-limited-edition-titanium-and-carbon-fibre-chronograph-wristwatch-with-date-circa-2005", | |
| 920 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25898045-3-1.jpg", | |
| 921 | + "estimateLow": 90000, | |
| 922 | + "estimateHigh": 180000, | |
| 923 | + "hammerPrice": 140000, | |
| 924 | + "hammerPremium": 179200, | |
| 925 | + "startingBid": 80000, | |
| 926 | + "currency": "HKD", | |
| 927 | + "status": "SOLD", | |
| 928 | + "hammerTime": "2026-09-03T08:40:00+00:00", | |
| 929 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 930 | + "department": "Watches", | |
| 931 | + "categories": [], | |
| 932 | + "isEnded": false, | |
| 933 | + "isWithoutReserve": false | |
| 934 | + }, | |
| 935 | + { | |
| 936 | + "lotId": "1042", | |
| 937 | + "lotUniqueId": "6184043", | |
| 938 | + "lotNo": "1042", | |
| 939 | + "title": "AUDEMARS PIGUET | MILLENARY, REF. 77301OR.ZZ.D015CR.01, A PINK GOLD AND DIAMOND-SET WRISTWATCH WITH MOTHER-OF-PEARL DIAL, CIRCA 2013", | |
| 940 | + "heading": null, | |
| 941 | + "slug": "audemars-piguet-millenary-ref-77301orzzd015cr01-a-pink-gold-and-diamond-set-wristwatch-with-mother-of-pearl-dial-circa-2013", | |
| 942 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/21/25902865-8-3.jpg", | |
| 943 | + "estimateLow": 65000, | |
| 944 | + "estimateHigh": 130000, | |
| 945 | + "hammerPrice": 70000, | |
| 946 | + "hammerPremium": 89600, | |
| 947 | + "startingBid": 55000, | |
| 948 | + "currency": "HKD", | |
| 949 | + "status": "SOLD", | |
| 950 | + "hammerTime": "2026-09-03T08:41:00+00:00", | |
| 951 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 952 | + "department": "Watches", | |
| 953 | + "categories": [], | |
| 954 | + "isEnded": false, | |
| 955 | + "isWithoutReserve": false | |
| 956 | + }, | |
| 957 | + { | |
| 958 | + "lotId": "1043", | |
| 959 | + "lotUniqueId": "6184044", | |
| 960 | + "lotNo": "1043", | |
| 961 | + "title": "AUDEMARS PIGUET | MILLENARY CHRONOGRAPH, REF.25822OR, A PINK GOLD CHRONOGRAPH WRISTWATCH WITH DATE AND TELEMETER SCALE, CIRCA 2004", | |
| 962 | + "heading": null, | |
| 963 | + "slug": "audemars-piguet-millenary-chronograph-ref25822or-a-pink-gold-chronograph-wristwatch-with-date-and-telemeter-scale-circa-2004", | |
| 964 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25901935-13-1.jpg", | |
| 965 | + "estimateLow": 50000, | |
| 966 | + "estimateHigh": 100000, | |
| 967 | + "hammerPrice": 70000, | |
| 968 | + "hammerPremium": 89600, | |
| 969 | + "startingBid": 46000, | |
| 970 | + "currency": "HKD", | |
| 971 | + "status": "SOLD", | |
| 972 | + "hammerTime": "2026-09-03T08:42:00+00:00", | |
| 973 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 974 | + "department": "Watches", | |
| 975 | + "categories": [], | |
| 976 | + "isEnded": false, | |
| 977 | + "isWithoutReserve": false | |
| 978 | + }, | |
| 979 | + { | |
| 980 | + "lotId": "1044", | |
| 981 | + "lotUniqueId": "6184045", | |
| 982 | + "lotNo": "1044", | |
| 983 | + "title": "AUDEMARS PIGUET | MILLENARY, REF.26018ST.ZZ.D007CR.01, A STAINLESS STEEL AND DIAMOND-SET CHRONOGRAPH WRISTWATCH WITH DATE, CIRCA 2009", | |
| 984 | + "heading": null, | |
| 985 | + "slug": "audemars-piguet-millenary-ref26018stzzd007cr01-a-stainless-steel-and-diamond-set-chronograph-wristwatch-with-date-circa-2009", | |
| 986 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/26/25860654-6-4.jpg", | |
| 987 | + "estimateLow": 22000, | |
| 988 | + "estimateHigh": 44000, | |
| 989 | + "hammerPrice": 32000, | |
| 990 | + "hammerPremium": 40960, | |
| 991 | + "startingBid": 19000, | |
| 992 | + "currency": "HKD", | |
| 993 | + "status": "SOLD", | |
| 994 | + "hammerTime": "2026-09-03T08:43:00+00:00", | |
| 995 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 996 | + "department": "Watches", | |
| 997 | + "categories": [], | |
| 998 | + "isEnded": false, | |
| 999 | + "isWithoutReserve": false | |
| 1000 | + }, | |
| 1001 | + { | |
| 1002 | + "lotId": "1045", | |
| 1003 | + "lotUniqueId": "6184046", | |
| 1004 | + "lotNo": "1045", | |
| 1005 | + "title": "AUDEMARS PIGUET | MERIDIAN, BA.56340.756, A YELLOW GOLD BRACELET WATCH WITH DATE, CIRCA 1988", | |
| 1006 | + "heading": null, | |
| 1007 | + "slug": "audemars-piguet-meridian-ba56340756-a-yellow-gold-bracelet-watch-with-date-circa-1988", | |
| 1008 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/21/25902865-7-2.jpg", | |
| 1009 | + "estimateLow": 40000, | |
| 1010 | + "estimateHigh": 80000, | |
| 1011 | + "hammerPrice": 65000, | |
| 1012 | + "hammerPremium": 83200, | |
| 1013 | + "startingBid": 36000, | |
| 1014 | + "currency": "HKD", | |
| 1015 | + "status": "SOLD", | |
| 1016 | + "hammerTime": "2026-09-03T08:44:00+00:00", | |
| 1017 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 1018 | + "department": "Watches", | |
| 1019 | + "categories": [], | |
| 1020 | + "isEnded": false, | |
| 1021 | + "isWithoutReserve": false | |
| 1022 | + }, | |
| 1023 | + { | |
| 1024 | + "lotId": "1046", | |
| 1025 | + "lotUniqueId": "6184047", | |
| 1026 | + "lotNo": "1046", | |
| 1027 | + "title": "AUDEMARS PIGUET | A FINE WHITE GOLD BRACELET WATCH WITH DIAMOND-SET INDEXES AND HANDS, CIRCA 1975", | |
| 1028 | + "heading": null, | |
| 1029 | + "slug": "audemars-piguet-a-fine-white-gold-bracelet-watch-with-diamond-set-indexes-and-hands-circa-1975", | |
| 1030 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25901935-9-1.jpg", | |
| 1031 | + "estimateLow": 44000, | |
| 1032 | + "estimateHigh": 85000, | |
| 1033 | + "hammerPrice": 70000, | |
| 1034 | + "hammerPremium": 89600, | |
| 1035 | + "startingBid": 40000, | |
| 1036 | + "currency": "HKD", | |
| 1037 | + "status": "SOLD", | |
| 1038 | + "hammerTime": "2026-09-03T08:45:00+00:00", | |
| 1039 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 1040 | + "department": "Watches", | |
| 1041 | + "categories": [], | |
| 1042 | + "isEnded": false, | |
| 1043 | + "isWithoutReserve": false | |
| 1044 | + }, | |
| 1045 | + { | |
| 1046 | + "lotId": "1047", | |
| 1047 | + "lotUniqueId": "6184048", | |
| 1048 | + "lotNo": "1047", | |
| 1049 | + "title": "PIAGET | REF.612773, A YELLOW GOLD DUAL TIME BRACELET WATCH, CIRCA 1970", | |
| 1050 | + "heading": null, | |
| 1051 | + "slug": "piaget-ref612773-a-yellow-gold-dual-time-bracelet-watch-circa-1970", | |
| 1052 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25903281-6-1.jpg", | |
| 1053 | + "estimateLow": 40000, | |
| 1054 | + "estimateHigh": 80000, | |
| 1055 | + "hammerPrice": 90000, | |
| 1056 | + "hammerPremium": 115200, | |
| 1057 | + "startingBid": 36000, | |
| 1058 | + "currency": "HKD", | |
| 1059 | + "status": "SOLD", | |
| 1060 | + "hammerTime": "2026-09-03T08:46:00+00:00", | |
| 1061 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 1062 | + "department": "Watches", | |
| 1063 | + "categories": [], | |
| 1064 | + "isEnded": false, | |
| 1065 | + "isWithoutReserve": false | |
| 1066 | + }, | |
| 1067 | + { | |
| 1068 | + "lotId": "1048", | |
| 1069 | + "lotUniqueId": "6184049", | |
| 1070 | + "lotNo": "1048", | |
| 1071 | + "title": "JAEGER-LECOULTRE | MASTER CONTROL GEOGRAPHIC, REF.142.8.92, A STAINLESS STEEL WORLD TIME BRACELET WATCH WITH DATE, DAY/NIGHT AND POWER RESERVE INDICATOR, CIRCA 2010", | |
| 1072 | + "heading": null, | |
| 1073 | + "slug": "jaeger-lecoultre-master-control-geographic-ref142892-a-stainless-steel-world-time-bracelet-watch-with-date-daynight-and-power-reserve-indicator-circa-2010", | |
| 1074 | + "imageUrl": "https://images3.bonhams.com/image?src=Images/live/2026-08/20/25903281-1-1.jpg", | |
| 1075 | + "estimateLow": 30000, | |
| 1076 | + "estimateHigh": 60000, | |
| 1077 | + "hammerPrice": 32000, | |
| 1078 | + "hammerPremium": 40960, | |
| 1079 | + "startingBid": 26000, | |
| 1080 | + "currency": "HKD", | |
| 1081 | + "status": "SOLD", | |
| 1082 | + "hammerTime": "2026-09-03T08:47:00+00:00", | |
| 1083 | + "endDate": "2026-09-03T08:00:00+00:00", | |
| 1084 | + "department": "Watches", | |
| 1085 | + "categories": [], | |
| 1086 | + "isEnded": false, | |
| 1087 | + "isWithoutReserve": false | |
| 1088 | + } | |
| 1089 | + ] | |
| 1090 | + }, | |
| 1091 | + "fetchedAt": "2026-09-07T06:06:01.837Z" | |
| 1092 | + }, | |
| 1093 | + "expect": { | |
| 1094 | + "minCount": 1, | |
| 1095 | + "kinds": [ | |
| 1096 | + "sale" | |
| 1097 | + ], | |
| 1098 | + "first": { | |
| 1099 | + "kind": "sale", | |
| 1100 | + "auctionHouse": "Bonhams", | |
| 1101 | + "currency": "HKD" | |
| 1102 | + } | |
| 1103 | + }, | |
| 1104 | + "note": "Captured live by connectors/api/_auction-lib/smoke.ts on 2026-09-07 (48 records from this raw page).", | |
| 1105 | + "capturedAt": "2026-09-07T06:06:01.850Z" | |
| 1106 | +} | |
| \ No newline at end of file | ||
added
data/fixtures/catawiki/seeded-1.json
+110 −0
@@ -0,0 +1,110 @@ | ||
| 1 | +{ | |
| 2 | + "raw": { | |
| 3 | + "url": "https://www.catawiki.com/en/l/106351561", | |
| 4 | + "externalId": "106351561", | |
| 5 | + "kind": "sale", | |
| 6 | + "engine": "scrapfly", | |
| 7 | + "httpStatus": 200, | |
| 8 | + "payload": { | |
| 9 | + "kind": "lot", | |
| 10 | + "seedHint": "unknown", | |
| 11 | + "id": 106351561, | |
| 12 | + "url": "https://www.catawiki.com/en/l/106351561", | |
| 13 | + "title": "Figure - An antique devotional figure - 29 cm - Wood", | |
| 14 | + "subtitle": "South America - 1750-1800 - Fair condition - heavily used & with possibly minor parts missing", | |
| 15 | + "description": "This item is an antique hand-carved wooden santo (devotional figure), characteristic of Latin American or Spanish colonial folk art featuring weathered polychrome paint and a distinct headdress. The item is beautifully designed and made with great care and detail. We feel that the piece is in overall fair unrestored condition with great original patina Dimensions 29cm height 11cm width 8cm depth Item will be shipped with registered shipping ", | |
| 16 | + "images": [ | |
| 17 | + "https://assets.catawiki.nl/assets/2026/8/25/7/1/f/71f84eeb-ccb7-4a5d-aba7-169e2bd38403.jpg", | |
| 18 | + "https://assets.catawiki.nl/assets/2026/8/25/7/f/0/7f002a45-dc06-4117-80fa-ecaee5bcf741.jpg", | |
| 19 | + "https://assets.catawiki.nl/assets/2026/8/25/9/6/8/96893860-8591-4306-be24-3fc7c308c0bd.jpg" | |
| 20 | + ], | |
| 21 | + "categoryId": 481, | |
| 22 | + "categoryUrl": "https://www.catawiki.com/en/c/481-antique-religious-decor", | |
| 23 | + "auction": { | |
| 24 | + "id": 1244222, | |
| 25 | + "title": "Private Chapel Auction", | |
| 26 | + "url": "https://www.catawiki.com/en/a/1244222-private-chapel-auction", | |
| 27 | + "status": "closed", | |
| 28 | + "startAt": "2026-08-27T16:00:00Z", | |
| 29 | + "closeAt": "2026-09-03T18:00:00Z", | |
| 30 | + "closedAt": "2026-09-03T19:21:11Z", | |
| 31 | + "categories": [ | |
| 32 | + "Interiors & Decorations", | |
| 33 | + "Antiques & Classic Furniture", | |
| 34 | + "Antique Religious Decor" | |
| 35 | + ], | |
| 36 | + "lotCount": 75 | |
| 37 | + }, | |
| 38 | + "specs": [ | |
| 39 | + { | |
| 40 | + "name": "Era", | |
| 41 | + "value": "1400-1900" | |
| 42 | + }, | |
| 43 | + { | |
| 44 | + "name": "Number of objects", | |
| 45 | + "value": "1" | |
| 46 | + }, | |
| 47 | + { | |
| 48 | + "name": "Title", | |
| 49 | + "value": "An antique devotional figure - 29 cm" | |
| 50 | + }, | |
| 51 | + { | |
| 52 | + "name": "Country of origin", | |
| 53 | + "value": "South America" | |
| 54 | + }, | |
| 55 | + { | |
| 56 | + "name": "Material", | |
| 57 | + "value": "Wood" | |
| 58 | + }, | |
| 59 | + { | |
| 60 | + "name": "Condition", | |
| 61 | + "value": "Fair condition - heavily used & with possibly minor parts missing" | |
| 62 | + }, | |
| 63 | + { | |
| 64 | + "name": "Height", | |
| 65 | + "value": "29 cm" | |
| 66 | + }, | |
| 67 | + { | |
| 68 | + "name": "Width", | |
| 69 | + "value": "11 cm" | |
| 70 | + }, | |
| 71 | + { | |
| 72 | + "name": "Depth", | |
| 73 | + "value": "8 cm" | |
| 74 | + }, | |
| 75 | + { | |
| 76 | + "name": "Estimated period", | |
| 77 | + "value": "1750-1800" | |
| 78 | + } | |
| 79 | + ], | |
| 80 | + "estimateMinEur": 200, | |
| 81 | + "estimateMaxEur": 250, | |
| 82 | + "sellerCountry": "NL", | |
| 83 | + "sellerName": "Artichoke Art & Antique", | |
| 84 | + "sellerIsPro": true, | |
| 85 | + "bidding": { | |
| 86 | + "closed": true, | |
| 87 | + "sold": true, | |
| 88 | + "finalBidEur": 60, | |
| 89 | + "biddingStartTime": 1787846400000, | |
| 90 | + "biddingEndTime": 1788459500000, | |
| 91 | + "bidCount": 525, | |
| 92 | + "reservePriceMet": null | |
| 93 | + } | |
| 94 | + }, | |
| 95 | + "fetchedAt": "2026-09-07T06:02:42.001Z" | |
| 96 | + }, | |
| 97 | + "expect": { | |
| 98 | + "minCount": 1, | |
| 99 | + "kinds": [ | |
| 100 | + "sale" | |
| 101 | + ], | |
| 102 | + "first": { | |
| 103 | + "kind": "sale", | |
| 104 | + "auctionHouse": "Catawiki", | |
| 105 | + "currency": "EUR" | |
| 106 | + } | |
| 107 | + }, | |
| 108 | + "note": "Captured live by connectors/api/_auction-lib/smoke.ts on 2026-09-07 (1 records from this raw page).", | |
| 109 | + "capturedAt": "2026-09-07T06:02:42.007Z" | |
| 110 | +} | |
| \ No newline at end of file | ||
added
data/fixtures/catawiki/seeded-2.json
+674 −0
@@ -0,0 +1,674 @@ | ||
| 1 | +{ | |
| 2 | + "raw": { | |
| 3 | + "url": "https://www.catawiki.com/en/a/1263062-vintage-watches-auction", | |
| 4 | + "externalId": "a1263062", | |
| 5 | + "kind": "auction_lot", | |
| 6 | + "engine": "scrapfly", | |
| 7 | + "httpStatus": 200, | |
| 8 | + "payload": { | |
| 9 | + "kind": "auction_lots", | |
| 10 | + "seedHint": "unknown", | |
| 11 | + "auction": { | |
| 12 | + "id": 1263062, | |
| 13 | + "title": "Vintage Watches Auction", | |
| 14 | + "url": "https://www.catawiki.com/en/a/1263062-vintage-watches-auction", | |
| 15 | + "status": "open_now", | |
| 16 | + "startAt": "2026-09-01T16:00:00Z", | |
| 17 | + "closeAt": "2026-09-08T17:00:00Z", | |
| 18 | + "closedAt": null, | |
| 19 | + "categories": [ | |
| 20 | + "Watches, Pens & Lighters", | |
| 21 | + "Watches", | |
| 22 | + "Vintage Watches" | |
| 23 | + ], | |
| 24 | + "lotCount": 59 | |
| 25 | + }, | |
| 26 | + "lots": [ | |
| 27 | + { | |
| 28 | + "id": 106431494, | |
| 29 | + "title": "Lanco - Swiss - Mechanical - mens - gold plated - Dress Watch – 1960s - No reserve price - Men - 1960-1969 ", | |
| 30 | + "subtitle": "Manual winding - Gold-plated", | |
| 31 | + "url": "https://www.catawiki.com/en/l/106431494-lanco-swiss-mechanical-mens-gold-plated-dress-watch-1960s-no-reserve-price-men-1960-1969", | |
| 32 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/9/c/5/9c501190-df47-477a-b73c-8e64f4c93e43.jpg", | |
| 33 | + "reservePriceSet": false, | |
| 34 | + "biddingStartTime": null | |
| 35 | + }, | |
| 36 | + { | |
| 37 | + "id": 106448188, | |
| 38 | + "title": "Sicura - Submarine 200 - [cal. EB 8021] - No reserve price - 23 Jewels - Men - 1960", | |
| 39 | + "subtitle": "Manual winding - Chromed", | |
| 40 | + "url": "https://www.catawiki.com/en/l/106448188-sicura-submarine-200-cal-eb-8021-no-reserve-price-23-jewels-men-1960", | |
| 41 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/4/f/c/4fc26c71-c774-4141-bc3d-cacaa60b2be2.jpg", | |
| 42 | + "reservePriceSet": false, | |
| 43 | + "biddingStartTime": null | |
| 44 | + }, | |
| 45 | + { | |
| 46 | + "id": 106429428, | |
| 47 | + "title": "Unitas Extra - Small Second - No reserve price - Men - 1950-1959 ", | |
| 48 | + "subtitle": "Manual winding - Stainless steel", | |
| 49 | + "url": "https://www.catawiki.com/en/l/106429428-unitas-extra-small-second-no-reserve-price-men-1950-1959", | |
| 50 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/9/9/d/99d73527-babf-4025-a9fa-535fc8449850.jpg", | |
| 51 | + "reservePriceSet": false, | |
| 52 | + "biddingStartTime": null | |
| 53 | + }, | |
| 54 | + { | |
| 55 | + "id": 106431311, | |
| 56 | + "title": "Jivana - Swiss - Mechanical - mens - gold plated - Dress Watch – 1960s - No reserve price - Men - 1960-1969 ", | |
| 57 | + "subtitle": "Manual winding - Gold-plated", | |
| 58 | + "url": "https://www.catawiki.com/en/l/106431311-jivana-swiss-mechanical-mens-gold-plated-dress-watch-1960s-no-reserve-price-men-1960-1969", | |
| 59 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/f/7/0/f707131b-4f4a-4f34-b1fe-56775e71c1a8.jpg", | |
| 60 | + "reservePriceSet": false, | |
| 61 | + "biddingStartTime": null | |
| 62 | + }, | |
| 63 | + { | |
| 64 | + "id": 106402795, | |
| 65 | + "title": "Arctos Elite - Classic Calendar 21Jewels - No reserve price - 2187 - Men - 1960-1969 ", | |
| 66 | + "subtitle": "Manual winding - Stainless steel, Metal, Gold-plated", | |
| 67 | + "url": "https://www.catawiki.com/en/l/106402795-arctos-elite-classic-calendar-21jewels-no-reserve-price-2187-men-1960-1969", | |
| 68 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/27/f/2/7/f27ba240-df0c-4f80-9c52-29a14c42ffde.jpg", | |
| 69 | + "reservePriceSet": false, | |
| 70 | + "biddingStartTime": null | |
| 71 | + }, | |
| 72 | + { | |
| 73 | + "id": 106431922, | |
| 74 | + "title": "Cimex - Ebauche Suisse - Mechanical - mens - gold plated - Dress Watch – 1960s - No reserve price - Men - 1960-1969 ", | |
| 75 | + "subtitle": "Manual winding - Gold-plated", | |
| 76 | + "url": "https://www.catawiki.com/en/l/106431922-cimex-ebauche-suisse-mechanical-mens-gold-plated-dress-watch-1960s-no-reserve-price-men-1960-1969", | |
| 77 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/6/e/b/6eba85e7-bc46-4bf1-965a-d130aa862c21.jpg", | |
| 78 | + "reservePriceSet": false, | |
| 79 | + "biddingStartTime": null | |
| 80 | + }, | |
| 81 | + { | |
| 82 | + "id": 106433826, | |
| 83 | + "title": "Sicura - Signal - No reserve price - Men - 1970-1979 ", | |
| 84 | + "subtitle": "Manual winding - Stainless steel", | |
| 85 | + "url": "https://www.catawiki.com/en/l/106433826-sicura-signal-no-reserve-price-men-1970-1979", | |
| 86 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/1/7/0/17077cdd-1e6f-47ab-8513-3e7816c73dee.jpg", | |
| 87 | + "reservePriceSet": false, | |
| 88 | + "biddingStartTime": null | |
| 89 | + }, | |
| 90 | + { | |
| 91 | + "id": 106425009, | |
| 92 | + "title": "Richard - Automatic “Bumper” – Cal. AS 1398 – 40-Micron Gold-Plated - No reserve price - Unisex - 1950-1959 ", | |
| 93 | + "subtitle": "Automatic - Gold-plated", | |
| 94 | + "url": "https://www.catawiki.com/en/l/106425009-richard-automatic-bumper-cal-as-1398-40-micron-gold-plated-no-reserve-price-unisex-1950-1959", | |
| 95 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/27/e/a/8/ea8e3dfb-48df-451a-81bb-fe7929b5d70c.jpg", | |
| 96 | + "reservePriceSet": false, | |
| 97 | + "biddingStartTime": null | |
| 98 | + }, | |
| 99 | + { | |
| 100 | + "id": 106433154, | |
| 101 | + "title": "Rado - Purple Horse - No reserve price - 636.3476.4 - Men - 1970-1979 ", | |
| 102 | + "subtitle": "Automatic - Gold/Steel, Stainless steel", | |
| 103 | + "url": "https://www.catawiki.com/en/l/106433154-rado-purple-horse-no-reserve-price-636-3476-4-men-1970-1979", | |
| 104 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/4/d/d/4ddd7350-1ad5-429d-a5ba-71d5d9ba3095.jpg", | |
| 105 | + "reservePriceSet": false, | |
| 106 | + "biddingStartTime": null | |
| 107 | + }, | |
| 108 | + { | |
| 109 | + "id": 106433667, | |
| 110 | + "title": "Atlantic - Worldmaster Original - No reserve price - 614/10 - Men - 1950-1959 ", | |
| 111 | + "subtitle": "Manual winding - Stainless steel", | |
| 112 | + "url": "https://www.catawiki.com/en/l/106433667-atlantic-worldmaster-original-no-reserve-price-614-10-men-1950-1959", | |
| 113 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/0/3/3/033ada34-13f9-480d-bda4-59f9336d804f.jpg", | |
| 114 | + "reservePriceSet": false, | |
| 115 | + "biddingStartTime": null | |
| 116 | + }, | |
| 117 | + { | |
| 118 | + "id": 106431856, | |
| 119 | + "title": "J. Chevalier - Swiss - Mechanical - mens - gold plated - Dress Watch – 1970s - No reserve price - Men - 1970-1979 ", | |
| 120 | + "subtitle": "Manual winding - Gold-plated", | |
| 121 | + "url": "https://www.catawiki.com/en/l/106431856-j-chevalier-swiss-mechanical-mens-gold-plated-dress-watch-1970s-no-reserve-price-men-1970-1979", | |
| 122 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/8/1/c/81cf5a9c-946f-4c81-b1f5-c696bad3de1a.jpg", | |
| 123 | + "reservePriceSet": false, | |
| 124 | + "biddingStartTime": null | |
| 125 | + }, | |
| 126 | + { | |
| 127 | + "id": 106425076, | |
| 128 | + "title": "Mondia - orbitron red automatic vintage swiss made - No reserve price - 97-1003-20 - Unisex - 1960-1969 ", | |
| 129 | + "subtitle": "Automatic - Steel, Gold-plated", | |
| 130 | + "url": "https://www.catawiki.com/en/l/106425076-mondia-orbitron-red-automatic-vintage-swiss-made-no-reserve-price-97-1003-20-unisex-1960-1969", | |
| 131 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/27/d/9/c/d9cce048-e4bc-43ac-af66-90dcb87af078.jpg", | |
| 132 | + "reservePriceSet": false, | |
| 133 | + "biddingStartTime": null | |
| 134 | + }, | |
| 135 | + { | |
| 136 | + "id": 106431599, | |
| 137 | + "title": "Juwel Genéve - Swiss - NOS - unused - Mechanical - mens - gold plated - Dress Watch – 1960s - No reserve price - Men - 1960-1969 ", | |
| 138 | + "subtitle": "Manual winding - Gold-plated", | |
| 139 | + "url": "https://www.catawiki.com/en/l/106431599-juwel-geneve-swiss-nos-unused-mechanical-mens-gold-plated-dress-watch-1960s-no-reserve-price-men-1960-1969", | |
| 140 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/d/b/6/db62eae6-d612-49af-95c2-93140b6f5751.jpg", | |
| 141 | + "reservePriceSet": false, | |
| 142 | + "biddingStartTime": null | |
| 143 | + }, | |
| 144 | + { | |
| 145 | + "id": 106430055, | |
| 146 | + "title": "Silvana - Military Design - No reserve price - Men - 1950-1959 ", | |
| 147 | + "subtitle": "Manual winding - Gold-plated", | |
| 148 | + "url": "https://www.catawiki.com/en/l/106430055-silvana-military-design-no-reserve-price-men-1950-1959", | |
| 149 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/2/1/a/21a2adc9-e2e4-43b1-a94f-5aef9c028d4f.jpg", | |
| 150 | + "reservePriceSet": false, | |
| 151 | + "biddingStartTime": null | |
| 152 | + }, | |
| 153 | + { | |
| 154 | + "id": 106425191, | |
| 155 | + "title": "Moulinet - Mechanical - Cal. AS 1187 – Stainless Steel - Concentric guilloché dial - No reserve price - Unisex - 1900-1949 ", | |
| 156 | + "subtitle": "Manual winding - Stainless steel", | |
| 157 | + "url": "https://www.catawiki.com/en/l/106425191-moulinet-mechanical-cal-as-1187-stainless-steel-concentric-guilloche-dial-no-reserve-price-unisex-1900-1949", | |
| 158 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/27/0/4/e/04e00a7b-127c-42f7-a8d2-1ae1cf386d03.jpg", | |
| 159 | + "reservePriceSet": false, | |
| 160 | + "biddingStartTime": null | |
| 161 | + }, | |
| 162 | + { | |
| 163 | + "id": 106425021, | |
| 164 | + "title": "Silvana - 60 Skin Diver Black Dial 38mm Steel 20 Atm Sub - No reserve price - Unisex - 1960-1969 ", | |
| 165 | + "subtitle": "Automatic - Steel", | |
| 166 | + "url": "https://www.catawiki.com/en/l/106425021-silvana-60-skin-diver-black-dial-38mm-steel-20-atm-sub-no-reserve-price-unisex-1960-1969", | |
| 167 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/27/5/e/c/5ec3466b-8874-4210-856f-301b5d1edbb7.jpg", | |
| 168 | + "reservePriceSet": false, | |
| 169 | + "biddingStartTime": null | |
| 170 | + }, | |
| 171 | + { | |
| 172 | + "id": 106429906, | |
| 173 | + "title": "Tissot - Carrousel - No reserve price - Men - 1970-1979 ", | |
| 174 | + "subtitle": "Manual winding - Gold-plated", | |
| 175 | + "url": "https://www.catawiki.com/en/l/106429906-tissot-carrousel-no-reserve-price-men-1970-1979", | |
| 176 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/9/e/e/9eeaa851-b200-44aa-a9bb-b47f268c135b.jpg", | |
| 177 | + "reservePriceSet": false, | |
| 178 | + "biddingStartTime": null | |
| 179 | + }, | |
| 180 | + { | |
| 181 | + "id": 106432218, | |
| 182 | + "title": "Saintis - France - Mechanical - mens - gold plated - Dress Watch – 1970s - No reserve price - Men - 1970-1979 ", | |
| 183 | + "subtitle": "Manual winding - Gold-plated", | |
| 184 | + "url": "https://www.catawiki.com/en/l/106432218-saintis-france-mechanical-mens-gold-plated-dress-watch-1970s-no-reserve-price-men-1970-1979", | |
| 185 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/0/2/d/02dfb7bd-a8a6-4471-9e99-50110aa72525.jpg", | |
| 186 | + "reservePriceSet": false, | |
| 187 | + "biddingStartTime": null | |
| 188 | + }, | |
| 189 | + { | |
| 190 | + "id": 106429645, | |
| 191 | + "title": "Nisus - Jubilé - No reserve price - Men - 1950-1959 ", | |
| 192 | + "subtitle": "Manual winding - Gold-plated", | |
| 193 | + "url": "https://www.catawiki.com/en/l/106429645-nisus-jubile-no-reserve-price-men-1950-1959", | |
| 194 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/3/b/9/3b9f5a21-421d-494e-9996-1437834b42fc.jpg", | |
| 195 | + "reservePriceSet": false, | |
| 196 | + "biddingStartTime": null | |
| 197 | + }, | |
| 198 | + { | |
| 199 | + "id": 106431309, | |
| 200 | + "title": "Rado - Golden Horse - No reserve price - 623 3001 4 - Men - 1970-1979 ", | |
| 201 | + "subtitle": "Automatic - Stainless steel", | |
| 202 | + "url": "https://www.catawiki.com/en/l/106431309-rado-golden-horse-no-reserve-price-623-3001-4-men-1970-1979", | |
| 203 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/7/29/2/2/b/22b2fd35-6323-433c-8dfe-5bcd6642d8a0.jpg", | |
| 204 | + "reservePriceSet": false, | |
| 205 | + "biddingStartTime": null | |
| 206 | + }, | |
| 207 | + { | |
| 208 | + "id": 106429752, | |
| 209 | + "title": "Stenis Calatrava - Small Second - No reserve price - Men - 1960-1969 ", | |
| 210 | + "subtitle": "Manual winding - Stainless steel", | |
| 211 | + "url": "https://www.catawiki.com/en/l/106429752-stenis-calatrava-small-second-no-reserve-price-men-1960-1969", | |
| 212 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/c/5/6/c56a0f92-a46d-4064-adf3-559089677dfe.jpg", | |
| 213 | + "reservePriceSet": false, | |
| 214 | + "biddingStartTime": null | |
| 215 | + }, | |
| 216 | + { | |
| 217 | + "id": 106432131, | |
| 218 | + "title": "Bulova - No reserve price - 3784181 - Men - 1974", | |
| 219 | + "subtitle": "Other - Gold-plated", | |
| 220 | + "url": "https://www.catawiki.com/en/l/106432131-bulova-no-reserve-price-3784181-men-1974", | |
| 221 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/3/5/f/35f93330-d3ff-4cb4-bb4d-d4ec7c338a30.jpg", | |
| 222 | + "reservePriceSet": false, | |
| 223 | + "biddingStartTime": null | |
| 224 | + }, | |
| 225 | + { | |
| 226 | + "id": 106431815, | |
| 227 | + "title": "Citizen - Seven Star - No reserve price - APSS 2803-Y - Men - 1960-1969 ", | |
| 228 | + "subtitle": "Automatic - Stainless steel", | |
| 229 | + "url": "https://www.catawiki.com/en/l/106431815-citizen-seven-star-no-reserve-price-apss-2803-y-men-1960-1969", | |
| 230 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/5/1/0/5100439b-91d4-4348-badf-d550e5f93519.jpg", | |
| 231 | + "reservePriceSet": false, | |
| 232 | + "biddingStartTime": null | |
| 233 | + }, | |
| 234 | + { | |
| 235 | + "id": 106440038, | |
| 236 | + "title": "horus - diver vintage swiss made automatic steel 10atm - No reserve price - Unisex - 1970-1979 ", | |
| 237 | + "subtitle": "Automatic - Steel", | |
| 238 | + "url": "https://www.catawiki.com/en/l/106440038-horus-diver-vintage-swiss-made-automatic-steel-10atm-no-reserve-price-unisex-1970-1979", | |
| 239 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/1/b/7/1b7542bc-bfb9-45c5-955d-da5f187a123d.jpg", | |
| 240 | + "reservePriceSet": false, | |
| 241 | + "biddingStartTime": null | |
| 242 | + }, | |
| 243 | + { | |
| 244 | + "id": 106434995, | |
| 245 | + "title": "Pryngeps - special - No reserve price - Men - 1960-1969 ", | |
| 246 | + "subtitle": "Automatic - golden", | |
| 247 | + "url": "https://www.catawiki.com/en/l/106434995-pryngeps-special-no-reserve-price-men-1960-1969", | |
| 248 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/9/9/5/9955f822-69d2-42f1-8641-60b804e87342.jpg", | |
| 249 | + "reservePriceSet": false, | |
| 250 | + "biddingStartTime": null | |
| 251 | + }, | |
| 252 | + { | |
| 253 | + "id": 106444844, | |
| 254 | + "title": "Pryngeps - restige swiss made vintage gold plated - No reserve price - Unisex - 1970-1979 ", | |
| 255 | + "subtitle": "Manual winding - Steel, Gold-plated", | |
| 256 | + "url": "https://www.catawiki.com/en/l/106444844-pryngeps-restige-swiss-made-vintage-gold-plated-no-reserve-price-unisex-1970-1979", | |
| 257 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/27/b/d/4/bd4347ec-2c16-4303-a484-f7a8fa9c0839.jpg", | |
| 258 | + "reservePriceSet": false, | |
| 259 | + "biddingStartTime": null | |
| 260 | + }, | |
| 261 | + { | |
| 262 | + "id": 106397315, | |
| 263 | + "title": "Certina - Ref 5206 148 - No reserve price - Men - 1971", | |
| 264 | + "subtitle": "Manual winding - Gold-plated", | |
| 265 | + "url": "https://www.catawiki.com/en/l/106397315-certina-ref-5206-148-no-reserve-price-men-1971", | |
| 266 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/26/2/8/8/28837709-a64f-49b0-ab97-9f847e9055fe.jpg", | |
| 267 | + "reservePriceSet": false, | |
| 268 | + "biddingStartTime": null | |
| 269 | + }, | |
| 270 | + { | |
| 271 | + "id": 106442428, | |
| 272 | + "title": "Lip - Vintage - No reserve price - 542563 - Unisex - 1950-1959 ", | |
| 273 | + "subtitle": "Manual winding - Gold-plated, Stainless steel", | |
| 274 | + "url": "https://www.catawiki.com/en/l/106442428-lip-vintage-no-reserve-price-542563-unisex-1950-1959", | |
| 275 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/6/1/3/61363042-4db8-4a82-97b0-76a78bdd0686.jpg", | |
| 276 | + "reservePriceSet": false, | |
| 277 | + "biddingStartTime": null | |
| 278 | + }, | |
| 279 | + { | |
| 280 | + "id": 106444923, | |
| 281 | + "title": "capri - racing team swiss made NOS model deposè - No reserve price - Unisex - 1970-1979 ", | |
| 282 | + "subtitle": "Manual winding - Bakelite", | |
| 283 | + "url": "https://www.catawiki.com/en/l/106444923-capri-racing-team-swiss-made-nos-model-depose-no-reserve-price-unisex-1970-1979", | |
| 284 | + "imageUrl": "https://assets.catawiki.nl/assets/2025/12/16/7/5/a/75abfd38-687a-4f71-9a4f-dacfee9a2b44.jpg", | |
| 285 | + "reservePriceSet": false, | |
| 286 | + "biddingStartTime": null | |
| 287 | + }, | |
| 288 | + { | |
| 289 | + "id": 106443145, | |
| 290 | + "title": "Alpina - Tresor – Cal. 762 - No reserve price - Men - 1930", | |
| 291 | + "subtitle": "Manual winding - Stainless steel", | |
| 292 | + "url": "https://www.catawiki.com/en/l/106443145-alpina-tresor-cal-762-no-reserve-price-men-1930", | |
| 293 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/4/d/c/4dcedda8-08de-4167-bef7-577a4c61eed8.jpg", | |
| 294 | + "reservePriceSet": false, | |
| 295 | + "biddingStartTime": null | |
| 296 | + }, | |
| 297 | + { | |
| 298 | + "id": 106363526, | |
| 299 | + "title": "Louvic DeLux-Mistery Dial Diamonds,Vintage'60. - No reserve price - Women - 1960-1969 ", | |
| 300 | + "subtitle": "Manual winding - Steel, Chrome-plated steel", | |
| 301 | + "url": "https://www.catawiki.com/en/l/106363526-louvic-delux-mistery-dial-diamonds-vintage-60-no-reserve-price-women-1960-1969", | |
| 302 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/27/f/e/6/fe620622-eba3-4aa1-b4ca-1d7c5d8f81ce.jpg", | |
| 303 | + "reservePriceSet": false, | |
| 304 | + "biddingStartTime": null | |
| 305 | + }, | |
| 306 | + { | |
| 307 | + "id": 106434347, | |
| 308 | + "title": "Roamer - No reserve price - 5907 - Men - 1950-1959 ", | |
| 309 | + "subtitle": "Manual winding - Gold-plated, Stainless steel", | |
| 310 | + "url": "https://www.catawiki.com/en/l/106434347-roamer-no-reserve-price-5907-men-1950-1959", | |
| 311 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/5/f/4/5f4b0cbd-9438-424a-afa5-668d38cf60bb.jpg", | |
| 312 | + "reservePriceSet": false, | |
| 313 | + "biddingStartTime": null | |
| 314 | + }, | |
| 315 | + { | |
| 316 | + "id": 106437054, | |
| 317 | + "title": "Junghans - Cal 687 vor Max Bill Era - No reserve price - Men - 1960-1969 ", | |
| 318 | + "subtitle": "Manual winding - Steel", | |
| 319 | + "url": "https://www.catawiki.com/en/l/106437054-junghans-cal-687-vor-max-bill-era-no-reserve-price-men-1960-1969", | |
| 320 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/c/5/3/c530b6a9-ac68-4b0b-ba6f-5d9657e99bbf.jpg", | |
| 321 | + "reservePriceSet": false, | |
| 322 | + "biddingStartTime": null | |
| 323 | + }, | |
| 324 | + { | |
| 325 | + "id": 106438848, | |
| 326 | + "title": "Stowa - Parat - No reserve price - Art Déco \"Tank\" Black Dial - Kal. Osco 42 - Men - 1900-1949 ", | |
| 327 | + "subtitle": "Manual winding - Gold-plated", | |
| 328 | + "url": "https://www.catawiki.com/en/l/106438848-stowa-parat-no-reserve-price-art-deco-tank-black-dial-kal-osco-42-men-1900-1949", | |
| 329 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/8/4/b/84bd1018-0218-4193-b428-ae6569334470.jpg", | |
| 330 | + "reservePriceSet": false, | |
| 331 | + "biddingStartTime": null | |
| 332 | + }, | |
| 333 | + { | |
| 334 | + "id": 106441082, | |
| 335 | + "title": "kirovskie - k43 - No reserve price - Men - 1900-1949 ", | |
| 336 | + "subtitle": "Manual winding - Steel", | |
| 337 | + "url": "https://www.catawiki.com/en/l/106441082-kirovskie-k43-no-reserve-price-men-1900-1949", | |
| 338 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/8/4/0/840d51f3-21ef-4434-bb48-7c00e467785a.jpg", | |
| 339 | + "reservePriceSet": false, | |
| 340 | + "biddingStartTime": null | |
| 341 | + }, | |
| 342 | + { | |
| 343 | + "id": 106442847, | |
| 344 | + "title": "Aero-Matic - No reserve price - 732 698205 - Men - 1965", | |
| 345 | + "subtitle": "Automatic - Stainless steel", | |
| 346 | + "url": "https://www.catawiki.com/en/l/106442847-aero-matic-no-reserve-price-732-698205-men-1965", | |
| 347 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/7/1/0/7107d5ee-0f48-42fc-a693-bd3e473244a8.jpg", | |
| 348 | + "reservePriceSet": false, | |
| 349 | + "biddingStartTime": null | |
| 350 | + }, | |
| 351 | + { | |
| 352 | + "id": 106423037, | |
| 353 | + "title": "Certina - Waterking - No reserve price - 25-66 - Unisex - 1960", | |
| 354 | + "subtitle": "Manual winding - Gold-plated", | |
| 355 | + "url": "https://www.catawiki.com/en/l/106423037-certina-waterking-no-reserve-price-25-66-unisex-1960", | |
| 356 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/27/4/9/1/491c4cd7-7e8d-442d-ab83-97e2f2beaa10.jpg", | |
| 357 | + "reservePriceSet": false, | |
| 358 | + "biddingStartTime": null | |
| 359 | + }, | |
| 360 | + { | |
| 361 | + "id": 106430124, | |
| 362 | + "title": "Rodos - No reserve price - 5145 RG - Men - 1960-1969 ", | |
| 363 | + "subtitle": "Manual winding - Gold-plated, Stainless steel", | |
| 364 | + "url": "https://www.catawiki.com/en/l/106430124-rodos-no-reserve-price-5145-rg-men-1960-1969", | |
| 365 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/9/b/b/9bb69e0e-3d77-4535-94cc-a3f568e50689.jpg", | |
| 366 | + "reservePriceSet": false, | |
| 367 | + "biddingStartTime": null | |
| 368 | + }, | |
| 369 | + { | |
| 370 | + "id": 106439475, | |
| 371 | + "title": "Baume & Mercier - Vintage Genève Ultra-Slim Dress Watch - Men - 1960-1969 ", | |
| 372 | + "subtitle": "Manual winding - Stainless steel", | |
| 373 | + "url": "https://www.catawiki.com/en/l/106439475-baume-mercier-vintage-geneve-ultra-slim-dress-watch-men-1960-1969", | |
| 374 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/6/c/4/5/c45f376f-5ab2-434f-a86e-161caaec878f.jpg", | |
| 375 | + "reservePriceSet": true, | |
| 376 | + "biddingStartTime": null | |
| 377 | + }, | |
| 378 | + { | |
| 379 | + "id": 106118127, | |
| 380 | + "title": "IWC - R810A - Unisex - 1960-1969 ", | |
| 381 | + "subtitle": "Automatic - Steel, Stainless steel", | |
| 382 | + "url": "https://www.catawiki.com/en/l/106118127-iwc-r810a-unisex-1960-1969", | |
| 383 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/15/0/4/c/04c434b7-3880-461d-acdb-71614b83a0b6.jpg", | |
| 384 | + "reservePriceSet": true, | |
| 385 | + "biddingStartTime": null | |
| 386 | + }, | |
| 387 | + { | |
| 388 | + "id": 106435355, | |
| 389 | + "title": "Cauny - prima - No reserve price - 192 757 - Men - 1950-1959 ", | |
| 390 | + "subtitle": "Manual winding - Stainless steel", | |
| 391 | + "url": "https://www.catawiki.com/en/l/106435355-cauny-prima-no-reserve-price-192-757-men-1950-1959", | |
| 392 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/8/8/e/88e29b9a-d8f1-45bf-914d-8cf354b0c50a.jpg", | |
| 393 | + "reservePriceSet": false, | |
| 394 | + "biddingStartTime": null | |
| 395 | + }, | |
| 396 | + { | |
| 397 | + "id": 106438115, | |
| 398 | + "title": "Citizen - Vintage - No reserve price - 4-520075 Y - Men - 1970-1979 ", | |
| 399 | + "subtitle": "Automatic - Stainless steel", | |
| 400 | + "url": "https://www.catawiki.com/en/l/106438115-citizen-vintage-no-reserve-price-4-520075-y-men-1970-1979", | |
| 401 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/a/9/c/a9c1d2d7-cfde-4537-8372-f2dae4ce576b.jpg", | |
| 402 | + "reservePriceSet": false, | |
| 403 | + "biddingStartTime": null | |
| 404 | + }, | |
| 405 | + { | |
| 406 | + "id": 106436212, | |
| 407 | + "title": "Caravelle ( Bulova ) Swiss - Classic Skeleton 21Rubis - No reserve price - N-8 - Men - 1970-1979 ", | |
| 408 | + "subtitle": "Manual winding - Stainless steel, Metal, Gold-plated", | |
| 409 | + "url": "https://www.catawiki.com/en/l/106436212-caravelle-bulova-swiss-classic-skeleton-21rubis-no-reserve-price-n-8-men-1970-1979", | |
| 410 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/f/f/1/ff1cfcac-a2dd-4846-860a-57c781b63b3f.jpg", | |
| 411 | + "reservePriceSet": false, | |
| 412 | + "biddingStartTime": null | |
| 413 | + }, | |
| 414 | + { | |
| 415 | + "id": 106438180, | |
| 416 | + "title": "Citizen - Seven Star Deluxe - No reserve price - Men - 1970-1979 ", | |
| 417 | + "subtitle": "Automatic - Stainless steel", | |
| 418 | + "url": "https://www.catawiki.com/en/l/106438180-citizen-seven-star-deluxe-no-reserve-price-men-1970-1979", | |
| 419 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/e/d/e/ede13b96-18ff-4758-ad10-aab08ad95a1a.jpg", | |
| 420 | + "reservePriceSet": false, | |
| 421 | + "biddingStartTime": null | |
| 422 | + }, | |
| 423 | + { | |
| 424 | + "id": 106437184, | |
| 425 | + "title": "Koha ( Hans Kohnen ) - Classic Calendar 17Rubis - No reserve price - 6821 - Men - 1960-1969 ", | |
| 426 | + "subtitle": "Manual winding - Stainless steel, Metal, Gold-plated", | |
| 427 | + "url": "https://www.catawiki.com/en/l/106437184-koha-hans-kohnen-classic-calendar-17rubis-no-reserve-price-6821-men-1960-1969", | |
| 428 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/7/8/c/78c3fc1c-55ef-4406-85ea-ee98e6688b5d.jpg", | |
| 429 | + "reservePriceSet": false, | |
| 430 | + "biddingStartTime": null | |
| 431 | + }, | |
| 432 | + { | |
| 433 | + "id": 106283105, | |
| 434 | + "title": "Sicura (Breitling) - Day-Date Automatic - No reserve price - Men - 1975", | |
| 435 | + "subtitle": "Automatic - Steel, Gold-plated", | |
| 436 | + "url": "https://www.catawiki.com/en/l/106283105-sicura-breitling-day-date-automatic-no-reserve-price-men-1975", | |
| 437 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/7/f/5/7f5e7d6a-f7ca-4c6d-bf41-972e31ad704f.jpg", | |
| 438 | + "reservePriceSet": false, | |
| 439 | + "biddingStartTime": null | |
| 440 | + }, | |
| 441 | + { | |
| 442 | + "id": 106325270, | |
| 443 | + "title": "Diehl Junghans - Compact - No reserve price - Men - 1970", | |
| 444 | + "subtitle": "Manual winding - Gold-plated", | |
| 445 | + "url": "https://www.catawiki.com/en/l/106325270-diehl-junghans-compact-no-reserve-price-men-1970", | |
| 446 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/a/8/e/a8e4b6a1-8295-4847-86ec-b2883c37bf82.jpg", | |
| 447 | + "reservePriceSet": false, | |
| 448 | + "biddingStartTime": null | |
| 449 | + }, | |
| 450 | + { | |
| 451 | + "id": 106445380, | |
| 452 | + "title": "Glashütte Spezimatic - cal. 75 - No reserve price - Men - 1980-1989 ", | |
| 453 | + "subtitle": "Automatic - Steel", | |
| 454 | + "url": "https://www.catawiki.com/en/l/106445380-glashutte-spezimatic-cal-75-no-reserve-price-men-1980-1989", | |
| 455 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/c/3/4/c3460011-f640-40f8-87a9-b021848602bf.jpg", | |
| 456 | + "reservePriceSet": false, | |
| 457 | + "biddingStartTime": null | |
| 458 | + }, | |
| 459 | + { | |
| 460 | + "id": 106445129, | |
| 461 | + "title": "Festa - Alpina Cal. 843 / Venus 130 - No reserve price - Men - 1930", | |
| 462 | + "subtitle": "Manual winding - Stainless steel, Gold-plated", | |
| 463 | + "url": "https://www.catawiki.com/en/l/106445129-festa-alpina-cal-843-venus-130-no-reserve-price-men-1930", | |
| 464 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/d/2/b/d2b936df-24cc-430e-83de-f8660098ceb2.jpg", | |
| 465 | + "reservePriceSet": false, | |
| 466 | + "biddingStartTime": null | |
| 467 | + }, | |
| 468 | + { | |
| 469 | + "id": 106446881, | |
| 470 | + "title": "StopWatch Tip - Chonostop - No reserve price - Men - 1950-1959 ", | |
| 471 | + "subtitle": "Manual winding - Gold-plated", | |
| 472 | + "url": "https://www.catawiki.com/en/l/106446881-stopwatch-tip-chonostop-no-reserve-price-men-1950-1959", | |
| 473 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/b/9/3/b93974c9-31a0-4e60-88cd-807513850983.jpg", | |
| 474 | + "reservePriceSet": false, | |
| 475 | + "biddingStartTime": null | |
| 476 | + }, | |
| 477 | + { | |
| 478 | + "id": 105875599, | |
| 479 | + "title": "Lusina Geneve Pointerdate - Genève - No reserve price - 114050 - Men - 1948", | |
| 480 | + "subtitle": "Manual winding - Gold-plated", | |
| 481 | + "url": "https://www.catawiki.com/en/l/105875599-lusina-geneve-pointerdate-geneve-no-reserve-price-114050-men-1948", | |
| 482 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/4/c/7/4/c74ed459-fee3-447b-b0f4-0b1eee87df73.jpg", | |
| 483 | + "reservePriceSet": false, | |
| 484 | + "biddingStartTime": null | |
| 485 | + }, | |
| 486 | + { | |
| 487 | + "id": 106339788, | |
| 488 | + "title": "Universal Genève - No reserve price - Cal. 1-42 Ref. 542109 - Men - 1970-1979 ", | |
| 489 | + "subtitle": "Manual winding - Stainless steel", | |
| 490 | + "url": "https://www.catawiki.com/en/l/106339788-universal-geneve-no-reserve-price-cal-1-42-ref-542109-men-1970-1979", | |
| 491 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/9/8/3/98341c59-bf47-47ee-b99b-bdd3e6fe62ab.jpg", | |
| 492 | + "reservePriceSet": false, | |
| 493 | + "biddingStartTime": null | |
| 494 | + }, | |
| 495 | + { | |
| 496 | + "id": 106448764, | |
| 497 | + "title": "Certina - Sub-second | Cal. 320 - No reserve price - 81101 - Men - 1954", | |
| 498 | + "subtitle": "Manual winding - Stainless steel", | |
| 499 | + "url": "https://www.catawiki.com/en/l/106448764-certina-sub-second-cal-320-no-reserve-price-81101-men-1954", | |
| 500 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/7/9/3/79312041-6fc5-42bf-974e-c91ad3d3531a.jpg", | |
| 501 | + "reservePriceSet": false, | |
| 502 | + "biddingStartTime": null | |
| 503 | + }, | |
| 504 | + { | |
| 505 | + "id": 106385554, | |
| 506 | + "title": "Richard Geneve - Automatic - No reserve price - Men - 1970-1979 ", | |
| 507 | + "subtitle": "Automatic - Steel", | |
| 508 | + "url": "https://www.catawiki.com/en/l/106385554-richard-geneve-automatic-no-reserve-price-men-1970-1979", | |
| 509 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/26/3/b/b/3bbf80d2-13d2-4b0f-a7a1-a0e444bf65b3.jpg", | |
| 510 | + "reservePriceSet": false, | |
| 511 | + "biddingStartTime": null | |
| 512 | + }, | |
| 513 | + { | |
| 514 | + "id": 106450800, | |
| 515 | + "title": "Rado - Companion III - No reserve price - 12122 - Men - 1970-1979 ", | |
| 516 | + "subtitle": "Automatic - Stainless steel", | |
| 517 | + "url": "https://www.catawiki.com/en/l/106450800-rado-companion-iii-no-reserve-price-12122-men-1970-1979", | |
| 518 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/6/26/c/b/3/cb3824d8-0349-4a54-a4cd-594e46820bb3.jpg", | |
| 519 | + "reservePriceSet": false, | |
| 520 | + "biddingStartTime": null | |
| 521 | + }, | |
| 522 | + { | |
| 523 | + "id": 106450804, | |
| 524 | + "title": "Junghans - Trilastic - No reserve price - Men - 1950-1959 ", | |
| 525 | + "subtitle": "Manual winding - Gold-plated", | |
| 526 | + "url": "https://www.catawiki.com/en/l/106450804-junghans-trilastic-no-reserve-price-men-1950-1959", | |
| 527 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/7/23/6/1/7/617f3bc8-76d6-4f2a-b410-844bc599694f.jpg", | |
| 528 | + "reservePriceSet": false, | |
| 529 | + "biddingStartTime": null | |
| 530 | + }, | |
| 531 | + { | |
| 532 | + "id": 106450806, | |
| 533 | + "title": "Bulova - Squadron - No reserve price - 6828659 - Men - 1943", | |
| 534 | + "subtitle": "Manual winding - Gold-plated", | |
| 535 | + "url": "https://www.catawiki.com/en/l/106450806-bulova-squadron-no-reserve-price-6828659-men-1943", | |
| 536 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/8/f/3/c/f3cf563f-8e6b-44e4-a82b-94fb43b460f5.jpg", | |
| 537 | + "reservePriceSet": false, | |
| 538 | + "biddingStartTime": null | |
| 539 | + }, | |
| 540 | + { | |
| 541 | + "id": 106450961, | |
| 542 | + "title": "Rado - Lepordeluxe - No reserve price - N0650538 - Women - 1970-1979 ", | |
| 543 | + "subtitle": "Manual winding - Silver", | |
| 544 | + "url": "https://www.catawiki.com/en/l/106450961-rado-lepordeluxe-no-reserve-price-n0650538-women-1970-1979", | |
| 545 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/13/5/d/f/5df404df-4d7a-4b32-9ef4-7fc58bebadfd.jpg", | |
| 546 | + "reservePriceSet": false, | |
| 547 | + "biddingStartTime": null | |
| 548 | + }, | |
| 549 | + { | |
| 550 | + "id": 106448949, | |
| 551 | + "title": "Certina - Certina Revelation Automatic + Crystal Tool - No reserve price - 8308170 - Unisex - 1971", | |
| 552 | + "subtitle": "Automatic - Stainless steel", | |
| 553 | + "url": "https://www.catawiki.com/en/l/106448949-certina-certina-revelation-automatic-crystal-tool-no-reserve-price-8308170-unisex-1971", | |
| 554 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/1/b/c/1bcd32ff-dfc4-44f1-8574-5ac1fa616d92.jpg", | |
| 555 | + "reservePriceSet": false, | |
| 556 | + "biddingStartTime": null | |
| 557 | + }, | |
| 558 | + { | |
| 559 | + "id": 106452821, | |
| 560 | + "title": "Citizen - ADOREX Automatic Hi-Beat 1970-1979 Men", | |
| 561 | + "subtitle": "Worn & in very good condition", | |
| 562 | + "url": "https://www.catawiki.com/en/l/106452821-citizen-adorex-automatic-hi-beat-1970-1979-men", | |
| 563 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/28/c/3/d/c3d1dafd-d906-4404-a4b3-b07eace42f6b.jpg", | |
| 564 | + "reservePriceSet": false, | |
| 565 | + "biddingStartTime": null | |
| 566 | + }, | |
| 567 | + { | |
| 568 | + "id": 106456952, | |
| 569 | + "title": "Phigied - oro giallo 18 carati - Women - 1900-1949 ", | |
| 570 | + "subtitle": "Manual winding - Yellow gold", | |
| 571 | + "url": "https://www.catawiki.com/en/l/106456952-phigied-oro-giallo-18-carati-women-1900-1949", | |
| 572 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/7/11/a/e/e/aee8b0a7-bad9-49e2-bb62-d71d8258b0c1.jpg", | |
| 573 | + "reservePriceSet": true, | |
| 574 | + "biddingStartTime": null | |
| 575 | + }, | |
| 576 | + { | |
| 577 | + "id": 106459197, | |
| 578 | + "title": "Nacar - AS 1130 / 17 Jewels – Manual Wind – Textured Dial - No reserve price - Men - 1950-1959 ", | |
| 579 | + "subtitle": "Manual winding - Gold-plated", | |
| 580 | + "url": "https://www.catawiki.com/en/l/106459197-nacar-as-1130-17-jewels-manual-wind-textured-dial-no-reserve-price-men-1950-1959", | |
| 581 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/29/e/1/b/e1b2df91-6b67-416e-94ec-ca8d5747c820.jpg", | |
| 582 | + "reservePriceSet": false, | |
| 583 | + "biddingStartTime": null | |
| 584 | + }, | |
| 585 | + { | |
| 586 | + "id": 106459697, | |
| 587 | + "title": "Nacar - Auto Dater Rookie “Jet” – 17 Jewels – Para Water – Vintage - No reserve price - Men - 1960-1969 ", | |
| 588 | + "subtitle": "Automatic - Gold-plated", | |
| 589 | + "url": "https://www.catawiki.com/en/l/106459697-nacar-auto-dater-rookie-jet-17-jewels-para-water-vintage-no-reserve-price-men-1960-1969", | |
| 590 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/29/8/1/b/81b95f7f-0fc9-42c5-b10f-865677f18d09.jpg", | |
| 591 | + "reservePriceSet": false, | |
| 592 | + "biddingStartTime": null | |
| 593 | + }, | |
| 594 | + { | |
| 595 | + "id": 106456147, | |
| 596 | + "title": "Mortima - Mayerling - vintage classic France - 17 Jewels - No reserve price - Men - 1970", | |
| 597 | + "subtitle": "Manual winding - Chromed", | |
| 598 | + "url": "https://www.catawiki.com/en/l/106456147-mortima-mayerling-vintage-classic-france-17-jewels-no-reserve-price-men-1970", | |
| 599 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/29/7/5/3/7534c060-e671-477a-ba5e-821770713727.jpg", | |
| 600 | + "reservePriceSet": false, | |
| 601 | + "biddingStartTime": null | |
| 602 | + }, | |
| 603 | + { | |
| 604 | + "id": 106453982, | |
| 605 | + "title": "Yema - Sous - Marine - vintage diver France - 330 Feet - No reserve price - Men - 1960", | |
| 606 | + "subtitle": "Manual winding - Steel", | |
| 607 | + "url": "https://www.catawiki.com/en/l/106453982-yema-sous-marine-vintage-diver-france-330-feet-no-reserve-price-men-1960", | |
| 608 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/29/7/8/d/78d9fb99-6c3e-4722-9801-cb7167fd489a.jpg", | |
| 609 | + "reservePriceSet": false, | |
| 610 | + "biddingStartTime": null | |
| 611 | + }, | |
| 612 | + { | |
| 613 | + "id": 106467638, | |
| 614 | + "title": "Maty - MATY Besancon Calendar – Vintage Manual-Wind Triple Calendar – 17 Jewels - No reserve price - Men - 1970", | |
| 615 | + "subtitle": "Manual winding - Gold-plated", | |
| 616 | + "url": "https://www.catawiki.com/en/l/106467638-maty-maty-besancon-calendar-vintage-manual-wind-triple-calendar-17-jewels-no-reserve-price-men-1970", | |
| 617 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/30/0/f/d/0fd5b397-984a-4aba-8056-a75ba6fe54a0.jpg", | |
| 618 | + "reservePriceSet": false, | |
| 619 | + "biddingStartTime": null | |
| 620 | + }, | |
| 621 | + { | |
| 622 | + "id": 106469806, | |
| 623 | + "title": "Vetta - Automatic Date - Oversize - Cal.472 - No reserve price - Ref.10282 - Men - 1970-1979 ", | |
| 624 | + "subtitle": "Automatic - Gold-plated", | |
| 625 | + "url": "https://www.catawiki.com/en/l/106469806-vetta-automatic-date-oversize-cal-472-no-reserve-price-ref-10282-men-1970-1979", | |
| 626 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/5/10/8/8/4/884bdf6a-e178-4834-a22f-5636c7dac9c7.jpg", | |
| 627 | + "reservePriceSet": false, | |
| 628 | + "biddingStartTime": null | |
| 629 | + }, | |
| 630 | + { | |
| 631 | + "id": 106468243, | |
| 632 | + "title": "Rado - DiaStar - No reserve price - Men - 1970-1979 ", | |
| 633 | + "subtitle": "Automatic - Gold-plated", | |
| 634 | + "url": "https://www.catawiki.com/en/l/106468243-rado-diastar-no-reserve-price-men-1970-1979", | |
| 635 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/30/8/7/4/874a40e9-e23c-454b-b9b4-9135c34979f1.jpg", | |
| 636 | + "reservePriceSet": false, | |
| 637 | + "biddingStartTime": null | |
| 638 | + }, | |
| 639 | + { | |
| 640 | + "id": 106471016, | |
| 641 | + "title": "Incalblock - Antimagnetique - No reserve price - Men - 1950", | |
| 642 | + "subtitle": "Manual winding - Gold-plated", | |
| 643 | + "url": "https://www.catawiki.com/en/l/106471016-incalblock-antimagnetique-no-reserve-price-men-1950", | |
| 644 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/30/3/8/0/3805d386-67a2-434c-b414-c8d490f28c72.jpg", | |
| 645 | + "reservePriceSet": false, | |
| 646 | + "biddingStartTime": null | |
| 647 | + }, | |
| 648 | + { | |
| 649 | + "id": 106468239, | |
| 650 | + "title": "Oris - Big Crown Pointer Date - No reserve price - Cal 704 Military Swiss Watch - Men - 1950-1959 ", | |
| 651 | + "subtitle": "Manual winding - Stainless steel", | |
| 652 | + "url": "https://www.catawiki.com/en/l/106468239-oris-big-crown-pointer-date-no-reserve-price-cal-704-military-swiss-watch-men-1950-1959", | |
| 653 | + "imageUrl": "https://assets.catawiki.nl/assets/2026/8/30/1/6/4/164738a3-4683-411b-8eb1-ce2e24b63680.jpg", | |
| 654 | + "reservePriceSet": false, | |
| 655 | + "biddingStartTime": null | |
| 656 | + } | |
| 657 | + ] | |
| 658 | + }, | |
| 659 | + "fetchedAt": "2026-09-07T06:02:44.097Z" | |
| 660 | + }, | |
| 661 | + "expect": { | |
| 662 | + "minCount": 1, | |
| 663 | + "kinds": [ | |
| 664 | + "auction_lot" | |
| 665 | + ], | |
| 666 | + "first": { | |
| 667 | + "kind": "auction_lot", | |
| 668 | + "auctionHouse": "Catawiki", | |
| 669 | + "currency": "EUR" | |
| 670 | + } | |
| 671 | + }, | |
| 672 | + "note": "Captured live by connectors/api/_auction-lib/smoke.ts on 2026-09-07 (70 records from this raw page).", | |
| 673 | + "capturedAt": "2026-09-07T06:02:44.106Z" | |
| 674 | +} | |
| \ No newline at end of file | ||
added
data/fixtures/christies/results-1.json
+1432 −0
@@ -0,0 +1,1432 @@ | ||
| 1 | +{ | |
| 2 | + "raw": { | |
| 3 | + "url": "https://www.christies.com/api/discoverywebsite/auctionpages/lotsearch?language=en&SaleNumber=24637&SaleId=31276&page=1&pageSize=20&sortby=lotnumber", | |
| 4 | + "externalId": "24637#1", | |
| 5 | + "kind": "sale", | |
| 6 | + "engine": "api", | |
| 7 | + "httpStatus": 200, | |
| 8 | + "payload": { | |
| 9 | + "kind": "sale_lots", | |
| 10 | + "sale": { | |
| 11 | + "saleId": "31276", | |
| 12 | + "saleNumber": "24637", | |
| 13 | + "title": "Studio 1766: Christie's London Staff Art Show", | |
| 14 | + "subtitle": "Online Auction 24637 | CLOSED", | |
| 15 | + "eventType": "Online", | |
| 16 | + "location": "London", | |
| 17 | + "startDate": "2026-08-20T00:00:00", | |
| 18 | + "endDate": "2026-09-03T00:00:00", | |
| 19 | + "landingUrl": "https://onlineonly.christies.com/sso?SaleID=31276&SaleNumber=24637", | |
| 20 | + "categoryLabels": [ | |
| 21 | + "Fine Art" | |
| 22 | + ], | |
| 23 | + "saleTotalText": "GBP 16,637" | |
| 24 | + }, | |
| 25 | + "page": 1, | |
| 26 | + "totalHits": 73, | |
| 27 | + "lots": [ | |
| 28 | + { | |
| 29 | + "objectId": "6598241", | |
| 30 | + "lotNumber": "1", | |
| 31 | + "titlePrimary": "UMIT ZEYTINCIOGLU", | |
| 32 | + "titleSecondary": "City of Villages, Revisited, 2025", | |
| 33 | + "titleTertiary": null, | |
| 34 | + "description": "UMIT ZEYTINCIOGLU City of Villages, Revisited, 2025 photographic print on aluminium 20 cm. high x 25 cm. wide", | |
| 35 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.1&LotNumber=1&ldp_breadcrumb=back", | |
| 36 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0001_000(umit_zeytincioglu_city_of_villages_revisited_2025054107).jpg?mode=max", | |
| 37 | + "estimateLow": 100, | |
| 38 | + "estimateHigh": 200, | |
| 39 | + "estimateText": "GBP 100 - 200", | |
| 40 | + "priceRealised": null, | |
| 41 | + "priceRealisedText": null, | |
| 42 | + "startDate": "2026-08-20T00:00Z", | |
| 43 | + "endDate": "2026-09-02T23:00Z", | |
| 44 | + "withdrawn": false, | |
| 45 | + "isOver": true | |
| 46 | + }, | |
| 47 | + { | |
| 48 | + "objectId": "6598242", | |
| 49 | + "lotNumber": "2", | |
| 50 | + "titlePrimary": "UMIT ZEYTINCIOGLU", | |
| 51 | + "titleSecondary": "Impetious, 2024", | |
| 52 | + "titleTertiary": null, | |
| 53 | + "description": "UMIT ZEYTINCIOGLU Impetious, 2024 photographic print, semi matte paper framed: 31.5 cm. high x 41.5 cm. wide", | |
| 54 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.2&LotNumber=2&ldp_breadcrumb=back", | |
| 55 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0002_000(umit_zeytincioglu_impetious_2024054119).jpg?mode=max", | |
| 56 | + "estimateLow": 100, | |
| 57 | + "estimateHigh": 200, | |
| 58 | + "estimateText": "GBP 100 - 200", | |
| 59 | + "priceRealised": 127, | |
| 60 | + "priceRealisedText": "GBP 127", | |
| 61 | + "startDate": "2026-08-20T00:00Z", | |
| 62 | + "endDate": "2026-09-02T23:00Z", | |
| 63 | + "withdrawn": false, | |
| 64 | + "isOver": true | |
| 65 | + }, | |
| 66 | + { | |
| 67 | + "objectId": "6598243", | |
| 68 | + "lotNumber": "3", | |
| 69 | + "titlePrimary": "UMIT ZEYTINCIOGLU", | |
| 70 | + "titleSecondary": "Look About You, 2025", | |
| 71 | + "titleTertiary": null, | |
| 72 | + "description": "UMIT ZEYTINCIOGLU Look About You, 2025 photographic print, on Fuji Velvet Paper image: 39 cm. high x 30 cm. wide framed: 57 cm. high x 47 cm. wide", | |
| 73 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.3&LotNumber=3&ldp_breadcrumb=back", | |
| 74 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0003_000(umit_zeytincioglu_look_about_you_2025054132).jpg?mode=max", | |
| 75 | + "estimateLow": 100, | |
| 76 | + "estimateHigh": 200, | |
| 77 | + "estimateText": "GBP 100 - 200", | |
| 78 | + "priceRealised": null, | |
| 79 | + "priceRealisedText": null, | |
| 80 | + "startDate": "2026-08-20T00:00Z", | |
| 81 | + "endDate": "2026-09-02T23:00Z", | |
| 82 | + "withdrawn": false, | |
| 83 | + "isOver": true | |
| 84 | + }, | |
| 85 | + { | |
| 86 | + "objectId": "6598244", | |
| 87 | + "lotNumber": "4", | |
| 88 | + "titlePrimary": "ABIGAIL DEAKIN", | |
| 89 | + "titleSecondary": "Spur, 2026", | |
| 90 | + "titleTertiary": null, | |
| 91 | + "description": "ABIGAIL DEAKIN Spur, 2026 signed 'A.Deakin' (lower right) oil on canvas 50 cm. high x 40 cm. wide", | |
| 92 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.4&LotNumber=4&ldp_breadcrumb=back", | |
| 93 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0004_000(abigail_deakin_spur_2026054138).jpg?mode=max", | |
| 94 | + "estimateLow": 1500, | |
| 95 | + "estimateHigh": 2500, | |
| 96 | + "estimateText": "GBP 1,500 - 2,500", | |
| 97 | + "priceRealised": null, | |
| 98 | + "priceRealisedText": null, | |
| 99 | + "startDate": "2026-08-20T00:00Z", | |
| 100 | + "endDate": "2026-09-02T23:00Z", | |
| 101 | + "withdrawn": false, | |
| 102 | + "isOver": true | |
| 103 | + }, | |
| 104 | + { | |
| 105 | + "objectId": "6598245", | |
| 106 | + "lotNumber": "5", | |
| 107 | + "titlePrimary": "ABIGAIL DEAKIN", | |
| 108 | + "titleSecondary": "Passing, 2026", | |
| 109 | + "titleTertiary": null, | |
| 110 | + "description": "ABIGAIL DEAKIN Passing, 2026 signed 'A. Deakin' (lower right) oil on canvas 100 cm. high x 70 cm. wide", | |
| 111 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.5&LotNumber=5&ldp_breadcrumb=back", | |
| 112 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0005_000(abigail_deakin_passing_2026054146).jpg?mode=max", | |
| 113 | + "estimateLow": 3000, | |
| 114 | + "estimateHigh": 4000, | |
| 115 | + "estimateText": "GBP 3,000 - 4,000", | |
| 116 | + "priceRealised": 3048, | |
| 117 | + "priceRealisedText": "GBP 3,048", | |
| 118 | + "startDate": "2026-08-20T00:00Z", | |
| 119 | + "endDate": "2026-09-02T23:00Z", | |
| 120 | + "withdrawn": false, | |
| 121 | + "isOver": true | |
| 122 | + }, | |
| 123 | + { | |
| 124 | + "objectId": "6598246", | |
| 125 | + "lotNumber": "6", | |
| 126 | + "titlePrimary": "ABIGAIL DEAKIN", | |
| 127 | + "titleSecondary": "Arena, 2026", | |
| 128 | + "titleTertiary": null, | |
| 129 | + "description": "ABIGAIL DEAKIN Arena, 2026 signed 'A. Deakin' (lower right) oil on canvas 50 cm. high x 40 cm. wide", | |
| 130 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.6&LotNumber=6&ldp_breadcrumb=back", | |
| 131 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0006_000(abigail_deakin_arena_2026054159).jpg?mode=max", | |
| 132 | + "estimateLow": 2500, | |
| 133 | + "estimateHigh": 3500, | |
| 134 | + "estimateText": "GBP 2,500 - 3,500", | |
| 135 | + "priceRealised": 2794, | |
| 136 | + "priceRealisedText": "GBP 2,794", | |
| 137 | + "startDate": "2026-08-20T00:00Z", | |
| 138 | + "endDate": "2026-09-02T23:00Z", | |
| 139 | + "withdrawn": false, | |
| 140 | + "isOver": true | |
| 141 | + }, | |
| 142 | + { | |
| 143 | + "objectId": "6598247", | |
| 144 | + "lotNumber": "7", | |
| 145 | + "titlePrimary": "LUZ MARIA OSORIO", | |
| 146 | + "titleSecondary": "Untitled, 2025", | |
| 147 | + "titleTertiary": null, | |
| 148 | + "description": "LUZ MARIA OSORIO Untitled, 2025 signed and dated (on the reverse) archival c-type print, acrylic face mounted framed: 68 cm. high x 101.5 cm. wide", | |
| 149 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.7&LotNumber=7&ldp_breadcrumb=back", | |
| 150 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0007_000(luz_maria_osorio_untitled_2025054205).jpg?mode=max", | |
| 151 | + "estimateLow": 600, | |
| 152 | + "estimateHigh": 800, | |
| 153 | + "estimateText": "GBP 600 - 800", | |
| 154 | + "priceRealised": null, | |
| 155 | + "priceRealisedText": null, | |
| 156 | + "startDate": "2026-08-20T00:00Z", | |
| 157 | + "endDate": "2026-09-02T23:00Z", | |
| 158 | + "withdrawn": false, | |
| 159 | + "isOver": true | |
| 160 | + }, | |
| 161 | + { | |
| 162 | + "objectId": "6598248", | |
| 163 | + "lotNumber": "8", | |
| 164 | + "titlePrimary": "LUZ MARIA OSORIO", | |
| 165 | + "titleSecondary": "Untitled, 2023", | |
| 166 | + "titleTertiary": null, | |
| 167 | + "description": "LUZ MARIA OSORIO Untitled, 2023 signed and dated (on reverse) archival c-type print, acrylic face mounted framed: 68 cm. high x 101.5 cm. wide", | |
| 168 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.8&LotNumber=8&ldp_breadcrumb=back", | |
| 169 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0008_000(luz_maria_osorio_untitled_2023055041).jpg?mode=max", | |
| 170 | + "estimateLow": 600, | |
| 171 | + "estimateHigh": 800, | |
| 172 | + "estimateText": "GBP 600 - 800", | |
| 173 | + "priceRealised": null, | |
| 174 | + "priceRealisedText": null, | |
| 175 | + "startDate": "2026-08-20T00:00Z", | |
| 176 | + "endDate": "2026-09-02T23:00Z", | |
| 177 | + "withdrawn": false, | |
| 178 | + "isOver": true | |
| 179 | + }, | |
| 180 | + { | |
| 181 | + "objectId": "6598249", | |
| 182 | + "lotNumber": "9", | |
| 183 | + "titlePrimary": "MARIA FALCO", | |
| 184 | + "titleSecondary": "Zero Hour Series - Creature, 2025", | |
| 185 | + "titleTertiary": null, | |
| 186 | + "description": "MARIA FALCO Zero Hour Series - Creature, 2025 numbered, titled and signed '1⁄5 \"Creature\" Maria Falco' (centre) giclee print of a graphite drawing image: 7.7 cm. high x 10 cm. wide framed: 20.5 cm. high x 25.4 cm. wide", | |
| 187 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.9&LotNumber=9&ldp_breadcrumb=back", | |
| 188 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0009_000(maria_falco_zero_hour_series_-_creature_2025_d6598249055047).jpg?mode=max", | |
| 189 | + "estimateLow": 50, | |
| 190 | + "estimateHigh": 100, | |
| 191 | + "estimateText": "GBP 50 - 100", | |
| 192 | + "priceRealised": 254, | |
| 193 | + "priceRealisedText": "GBP 254", | |
| 194 | + "startDate": "2026-08-20T00:00Z", | |
| 195 | + "endDate": "2026-09-02T23:00Z", | |
| 196 | + "withdrawn": false, | |
| 197 | + "isOver": true | |
| 198 | + }, | |
| 199 | + { | |
| 200 | + "objectId": "6598250", | |
| 201 | + "lotNumber": "10", | |
| 202 | + "titlePrimary": "MARIA FALCO", | |
| 203 | + "titleSecondary": "Zero Hour Series - Partner at Night, 2025", | |
| 204 | + "titleTertiary": null, | |
| 205 | + "description": "MARIA FALCO Zero Hour Series - Partner at Night, 2025 numbered, titled and signed '1⁄5 \"Partner At Night\" Maria Falco' (centre) giclee print of a graphite drawing image: 7.7 cm. high x 10 cm. wide framed: 20.5 cm. high x 25.4 cm. wide", | |
| 206 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.10&LotNumber=10&ldp_breadcrumb=back", | |
| 207 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0010_000(maria_falco_zero_hour_series_-_partner_at_night_2025054219).jpg?mode=max", | |
| 208 | + "estimateLow": 50, | |
| 209 | + "estimateHigh": 100, | |
| 210 | + "estimateText": "GBP 50 - 100", | |
| 211 | + "priceRealised": null, | |
| 212 | + "priceRealisedText": null, | |
| 213 | + "startDate": "2026-08-20T00:00Z", | |
| 214 | + "endDate": "2026-09-02T23:00Z", | |
| 215 | + "withdrawn": false, | |
| 216 | + "isOver": true | |
| 217 | + }, | |
| 218 | + { | |
| 219 | + "objectId": "6598251", | |
| 220 | + "lotNumber": "11", | |
| 221 | + "titlePrimary": "MARIA FALCO", | |
| 222 | + "titleSecondary": "Zero Hour Series - The End, 2025", | |
| 223 | + "titleTertiary": null, | |
| 224 | + "description": "MARIA FALCO Zero Hour Series - The End, 2025 numbered, titled and signed '1⁄5 \"The End\" Maria Falco' (centre) giclee print of a graphite drawing image: 7.7 cm. high x 10 cm. wide framed: 20.5 cm. high x 25.4 cm. wide", | |
| 225 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.11&LotNumber=11&ldp_breadcrumb=back", | |
| 226 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0011_000(maria_falco_zero_hour_series_-_the_end_2025054233).jpg?mode=max", | |
| 227 | + "estimateLow": 50, | |
| 228 | + "estimateHigh": 100, | |
| 229 | + "estimateText": "GBP 50 - 100", | |
| 230 | + "priceRealised": 64, | |
| 231 | + "priceRealisedText": "GBP 64", | |
| 232 | + "startDate": "2026-08-20T00:00Z", | |
| 233 | + "endDate": "2026-09-02T23:00Z", | |
| 234 | + "withdrawn": false, | |
| 235 | + "isOver": true | |
| 236 | + }, | |
| 237 | + { | |
| 238 | + "objectId": "6598252", | |
| 239 | + "lotNumber": "12", | |
| 240 | + "titlePrimary": "SOPHIE TAYLOR", | |
| 241 | + "titleSecondary": "Study of Fish Bone, 2026", | |
| 242 | + "titleTertiary": null, | |
| 243 | + "description": "SOPHIE TAYLOR Study of Fish Bone, 2026 signed 'SST' (lower right) pencil on paper 20.3 cm. high x 25.4 cm. wide", | |
| 244 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.12&LotNumber=12&ldp_breadcrumb=back", | |
| 245 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0012_000(sophie_taylor_study_of_fish_bone_2026054247).jpg?mode=max", | |
| 246 | + "estimateLow": 100, | |
| 247 | + "estimateHigh": 200, | |
| 248 | + "estimateText": "GBP 100 - 200", | |
| 249 | + "priceRealised": null, | |
| 250 | + "priceRealisedText": null, | |
| 251 | + "startDate": "2026-08-20T00:00Z", | |
| 252 | + "endDate": "2026-09-02T23:00Z", | |
| 253 | + "withdrawn": false, | |
| 254 | + "isOver": true | |
| 255 | + }, | |
| 256 | + { | |
| 257 | + "objectId": "6598253", | |
| 258 | + "lotNumber": "13", | |
| 259 | + "titlePrimary": "EVIE JOHNSON", | |
| 260 | + "titleSecondary": "3 Funky Fish, 2026", | |
| 261 | + "titleTertiary": null, | |
| 262 | + "description": "EVIE JOHNSON 3 Funky Fish, 2026 acrylic on canvas 55.6 cm. high x 45.7 cm. wide", | |
| 263 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.13&LotNumber=13&ldp_breadcrumb=back", | |
| 264 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0013_000(evie_johnson_3_funky_fish_2026054259).jpg?mode=max", | |
| 265 | + "estimateLow": 300, | |
| 266 | + "estimateHigh": 400, | |
| 267 | + "estimateText": "GBP 300 - 400", | |
| 268 | + "priceRealised": 254, | |
| 269 | + "priceRealisedText": "GBP 254", | |
| 270 | + "startDate": "2026-08-20T00:00Z", | |
| 271 | + "endDate": "2026-09-02T23:00Z", | |
| 272 | + "withdrawn": false, | |
| 273 | + "isOver": true | |
| 274 | + }, | |
| 275 | + { | |
| 276 | + "objectId": "6598254", | |
| 277 | + "lotNumber": "14", | |
| 278 | + "titlePrimary": "MARGUERITE KNOWLES", | |
| 279 | + "titleSecondary": "Fox, 2026", | |
| 280 | + "titleTertiary": null, | |
| 281 | + "description": "MARGUERITE KNOWLES Fox, 2026 signed 'Marguerite Knowles 2026' (on reverse) watercolour, pencil and ink on paper 21 cm. high x 14.8 cm. wide", | |
| 282 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.14&LotNumber=14&ldp_breadcrumb=back", | |
| 283 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0014_000(marguerite_knowles_fox_2026054312).jpg?mode=max", | |
| 284 | + "estimateLow": 100, | |
| 285 | + "estimateHigh": 200, | |
| 286 | + "estimateText": "GBP 100 - 200", | |
| 287 | + "priceRealised": 254, | |
| 288 | + "priceRealisedText": "GBP 254", | |
| 289 | + "startDate": "2026-08-20T00:00Z", | |
| 290 | + "endDate": "2026-09-02T23:00Z", | |
| 291 | + "withdrawn": false, | |
| 292 | + "isOver": true | |
| 293 | + }, | |
| 294 | + { | |
| 295 | + "objectId": "6598255", | |
| 296 | + "lotNumber": "15", | |
| 297 | + "titlePrimary": "MARGUERITE KNOWLES", | |
| 298 | + "titleSecondary": "Three Pigeons, 2026", | |
| 299 | + "titleTertiary": null, | |
| 300 | + "description": "MARGUERITE KNOWLES Three Pigeons, 2026 signed 'Marguerite Knowles 2026' (on reverse) watercolour, pencil and ink on paper 21 cm. high x 14.8 cm. wide", | |
| 301 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.15&LotNumber=15&ldp_breadcrumb=back", | |
| 302 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0015_000(marguerite_knowles_three_pigeons_2026054318).jpg?mode=max", | |
| 303 | + "estimateLow": 100, | |
| 304 | + "estimateHigh": 200, | |
| 305 | + "estimateText": "GBP 100 - 200", | |
| 306 | + "priceRealised": 190, | |
| 307 | + "priceRealisedText": "GBP 190", | |
| 308 | + "startDate": "2026-08-20T00:00Z", | |
| 309 | + "endDate": "2026-09-02T23:00Z", | |
| 310 | + "withdrawn": false, | |
| 311 | + "isOver": true | |
| 312 | + }, | |
| 313 | + { | |
| 314 | + "objectId": "6598256", | |
| 315 | + "lotNumber": "16", | |
| 316 | + "titlePrimary": "MARGUERITE KNOWLES", | |
| 317 | + "titleSecondary": "Tulip, 2026", | |
| 318 | + "titleTertiary": null, | |
| 319 | + "description": "MARGUERITE KNOWLES Tulip, 2026 signed 'Marguerite Knowles 2026' (on reverse) watercolour, pencil and ink on paper 21 cm. high x 14.8 cm. wide", | |
| 320 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.16&LotNumber=16&ldp_breadcrumb=back", | |
| 321 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0016_000(marguerite_knowles_tulip_2026054328).jpg?mode=max", | |
| 322 | + "estimateLow": 100, | |
| 323 | + "estimateHigh": 200, | |
| 324 | + "estimateText": "GBP 100 - 200", | |
| 325 | + "priceRealised": null, | |
| 326 | + "priceRealisedText": null, | |
| 327 | + "startDate": "2026-08-20T00:00Z", | |
| 328 | + "endDate": "2026-09-02T23:00Z", | |
| 329 | + "withdrawn": false, | |
| 330 | + "isOver": true | |
| 331 | + }, | |
| 332 | + { | |
| 333 | + "objectId": "6598257", | |
| 334 | + "lotNumber": "17", | |
| 335 | + "titlePrimary": "NICHOLA JONES", | |
| 336 | + "titleSecondary": "Tulip I, 2026", | |
| 337 | + "titleTertiary": null, | |
| 338 | + "description": "NICHOLA JONES Tulip I, 2026 watercolour and pencil on paper 22.5 cm. high x 17.5 cm. wide", | |
| 339 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.17&LotNumber=17&ldp_breadcrumb=back", | |
| 340 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0017_000(nichola_jones_tulip_i_2026054334).jpg?mode=max", | |
| 341 | + "estimateLow": 50, | |
| 342 | + "estimateHigh": 100, | |
| 343 | + "estimateText": "GBP 50 - 100", | |
| 344 | + "priceRealised": 64, | |
| 345 | + "priceRealisedText": "GBP 64", | |
| 346 | + "startDate": "2026-08-20T00:00Z", | |
| 347 | + "endDate": "2026-09-02T23:00Z", | |
| 348 | + "withdrawn": false, | |
| 349 | + "isOver": true | |
| 350 | + }, | |
| 351 | + { | |
| 352 | + "objectId": "6598258", | |
| 353 | + "lotNumber": "18", | |
| 354 | + "titlePrimary": "ANNIE FOLEY", | |
| 355 | + "titleSecondary": "Two Lilies", | |
| 356 | + "titleTertiary": null, | |
| 357 | + "description": "ANNIE FOLEY Two Lilies signed 'Annie 2023 \"TWO LILIES\"' (on reverse) oil on canvas 91 cm. high x 61 cm. wide", | |
| 358 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.18&LotNumber=18&ldp_breadcrumb=back", | |
| 359 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0018_000(annie_foley_two_lilies_d6598258055118).jpg?mode=max", | |
| 360 | + "estimateLow": 700, | |
| 361 | + "estimateHigh": 1000, | |
| 362 | + "estimateText": "GBP 700 - 1,000", | |
| 363 | + "priceRealised": null, | |
| 364 | + "priceRealisedText": null, | |
| 365 | + "startDate": "2026-08-20T00:00Z", | |
| 366 | + "endDate": "2026-09-02T23:00Z", | |
| 367 | + "withdrawn": false, | |
| 368 | + "isOver": true | |
| 369 | + }, | |
| 370 | + { | |
| 371 | + "objectId": "6598259", | |
| 372 | + "lotNumber": "19", | |
| 373 | + "titlePrimary": "ISA LEUNG", | |
| 374 | + "titleSecondary": "Vibrant Tulip Garden, 2026", | |
| 375 | + "titleTertiary": null, | |
| 376 | + "description": "ISA LEUNG Vibrant Tulip Garden, 2026 signed 'Isa' (lower right) oil on canvas 37.7 cm. high x 29 cm. wide", | |
| 377 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.19&LotNumber=19&ldp_breadcrumb=back", | |
| 378 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0019_000(isa_leung_vibrant_tulip_garden_2026_d6598259055124).jpg?mode=max", | |
| 379 | + "estimateLow": 100, | |
| 380 | + "estimateHigh": 200, | |
| 381 | + "estimateText": "GBP 100 - 200", | |
| 382 | + "priceRealised": null, | |
| 383 | + "priceRealisedText": null, | |
| 384 | + "startDate": "2026-08-20T00:00Z", | |
| 385 | + "endDate": "2026-09-02T23:00Z", | |
| 386 | + "withdrawn": false, | |
| 387 | + "isOver": true | |
| 388 | + }, | |
| 389 | + { | |
| 390 | + "objectId": "6598260", | |
| 391 | + "lotNumber": "20", | |
| 392 | + "titlePrimary": "ANASTASIA LEBEDEV", | |
| 393 | + "titleSecondary": "Coming Up Roses, 2026", | |
| 394 | + "titleTertiary": null, | |
| 395 | + "description": "ANASTASIA LEBEDEV Coming Up Roses, 2026 framed, signed, titled and dated 'Anastasia Lebedev / Coming Up Roses / 2026' (on the reverse). cyanotype print on handmade cotton paper image: 59.4 cm. high x 42 cm. wide framed: 67.4 cm. high x 50 cm. wide", | |
| 396 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.20&LotNumber=20&ldp_breadcrumb=back", | |
| 397 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0020_000(anastasia_lebedev_coming_up_roses_2026113705).jpg?mode=max", | |
| 398 | + "estimateLow": 200, | |
| 399 | + "estimateHigh": 400, | |
| 400 | + "estimateText": "GBP 200 - 400", | |
| 401 | + "priceRealised": null, | |
| 402 | + "priceRealisedText": null, | |
| 403 | + "startDate": "2026-08-20T00:00Z", | |
| 404 | + "endDate": "2026-09-02T23:00Z", | |
| 405 | + "withdrawn": false, | |
| 406 | + "isOver": true | |
| 407 | + }, | |
| 408 | + { | |
| 409 | + "objectId": "6598261", | |
| 410 | + "lotNumber": "21", | |
| 411 | + "titlePrimary": "ANASTASIA LEBEDEV", | |
| 412 | + "titleSecondary": "A Year of Bloom, 2026", | |
| 413 | + "titleTertiary": null, | |
| 414 | + "description": "ANASTASIA LEBEDEV A Year of Bloom, 2026 framed, signed, titled and dated 'Anastasia Lebedev / A Year of Bloom / 2026' (on reverse). cyanotype print on handmade cotton paper image: 42 cm. high x 59.5 cm. wide framed: 50 cm. high x 67.4 cm. wide", | |
| 415 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.21&LotNumber=21&ldp_breadcrumb=back", | |
| 416 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0021_000(anastasia_lebedev_a_year_of_bloom_2026061910).jpg?mode=max", | |
| 417 | + "estimateLow": 200, | |
| 418 | + "estimateHigh": 400, | |
| 419 | + "estimateText": "GBP 200 - 400", | |
| 420 | + "priceRealised": null, | |
| 421 | + "priceRealisedText": null, | |
| 422 | + "startDate": "2026-08-20T00:00Z", | |
| 423 | + "endDate": "2026-09-02T23:00Z", | |
| 424 | + "withdrawn": false, | |
| 425 | + "isOver": true | |
| 426 | + }, | |
| 427 | + { | |
| 428 | + "objectId": "6598262", | |
| 429 | + "lotNumber": "22", | |
| 430 | + "titlePrimary": "ANASTASIA LEBEDEV", | |
| 431 | + "titleSecondary": "Duallium, 2026", | |
| 432 | + "titleTertiary": null, | |
| 433 | + "description": "ANASTASIA LEBEDEV Duallium, 2026 diptych, framed, each print signed, titled and dated 'Anastasia Lebedev / Duallium / 2026' (on the reverse). cyanotype print on handmade cotton paper each image: 59.4 cm. high x 42 cm. wide each framed: 67.4 cm. high x 50 cm. wide", | |
| 434 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.22&LotNumber=22&ldp_breadcrumb=back", | |
| 435 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0022_000(anastasia_lebedev_duallium_2026062944).jpg?mode=max", | |
| 436 | + "estimateLow": 300, | |
| 437 | + "estimateHigh": 500, | |
| 438 | + "estimateText": "GBP 300 - 500", | |
| 439 | + "priceRealised": null, | |
| 440 | + "priceRealisedText": null, | |
| 441 | + "startDate": "2026-08-20T00:00Z", | |
| 442 | + "endDate": "2026-09-02T23:00Z", | |
| 443 | + "withdrawn": false, | |
| 444 | + "isOver": true | |
| 445 | + }, | |
| 446 | + { | |
| 447 | + "objectId": "6598263", | |
| 448 | + "lotNumber": "23", | |
| 449 | + "titlePrimary": "ANASTASIA LEBEDEV", | |
| 450 | + "titleSecondary": "Fall’s fall, 2026", | |
| 451 | + "titleTertiary": null, | |
| 452 | + "description": "ANASTASIA LEBEDEV Fall’s fall, 2026 framed, signed, titled and dated 'Anastasia Lebedev / Fall's fall / 2026' (on reverse). cyanotype print on handmade cotton paper image: 42 cm. high x 59.5 cm. wide framed: 86.5 cm. high x 62.2 cm. wide", | |
| 453 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.23&LotNumber=23&ldp_breadcrumb=back", | |
| 454 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0023_000(anastasia_lebedev_fall8217s_fall_2026_d6598263063041).jpg?mode=max", | |
| 455 | + "estimateLow": 200, | |
| 456 | + "estimateHigh": 400, | |
| 457 | + "estimateText": "GBP 200 - 400", | |
| 458 | + "priceRealised": 254, | |
| 459 | + "priceRealisedText": "GBP 254", | |
| 460 | + "startDate": "2026-08-20T00:00Z", | |
| 461 | + "endDate": "2026-09-02T23:00Z", | |
| 462 | + "withdrawn": false, | |
| 463 | + "isOver": true | |
| 464 | + }, | |
| 465 | + { | |
| 466 | + "objectId": "6598264", | |
| 467 | + "lotNumber": "24", | |
| 468 | + "titlePrimary": "ANASTASIA LEBEDEV", | |
| 469 | + "titleSecondary": "From Eden, 2026", | |
| 470 | + "titleTertiary": null, | |
| 471 | + "description": "ANASTASIA LEBEDEV From Eden, 2026 diptych, framed, each print signed, titled and dated 'Anastasia Lebedev / From Eden / 2026' (on reverse). cyanotype print on handmade cotton paper each image: 59.4 cm. high x 42 cm. wide each framed: 67.4 cm. high x 50 cm. wide", | |
| 472 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.24&LotNumber=24&ldp_breadcrumb=back", | |
| 473 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0024_000(anastasia_levedev_from_eden_d6598264063058).jpg?mode=max", | |
| 474 | + "estimateLow": 300, | |
| 475 | + "estimateHigh": 500, | |
| 476 | + "estimateText": "GBP 300 - 500", | |
| 477 | + "priceRealised": null, | |
| 478 | + "priceRealisedText": null, | |
| 479 | + "startDate": "2026-08-20T00:00Z", | |
| 480 | + "endDate": "2026-09-02T23:00Z", | |
| 481 | + "withdrawn": false, | |
| 482 | + "isOver": true | |
| 483 | + }, | |
| 484 | + { | |
| 485 | + "objectId": "6598265", | |
| 486 | + "lotNumber": "25", | |
| 487 | + "titlePrimary": "RAFFAELE COLETTA", | |
| 488 | + "titleSecondary": "Piera, 2024", | |
| 489 | + "titleTertiary": null, | |
| 490 | + "description": "RAFFAELE COLETTA Piera, 2024 signed 'R.Coletta' (on reverse) oil on canvas 76 cm. high x 60 cm. wide", | |
| 491 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.25&LotNumber=25&ldp_breadcrumb=back", | |
| 492 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0025_000(raffaele_coletta_piera_2024_d6598265055235).jpg?mode=max", | |
| 493 | + "estimateLow": 400, | |
| 494 | + "estimateHigh": 600, | |
| 495 | + "estimateText": "GBP 400 - 600", | |
| 496 | + "priceRealised": 64, | |
| 497 | + "priceRealisedText": "GBP 64", | |
| 498 | + "startDate": "2026-08-20T00:00Z", | |
| 499 | + "endDate": "2026-09-02T23:00Z", | |
| 500 | + "withdrawn": false, | |
| 501 | + "isOver": true | |
| 502 | + }, | |
| 503 | + { | |
| 504 | + "objectId": "6598266", | |
| 505 | + "lotNumber": "26", | |
| 506 | + "titlePrimary": "RAFFAELE COLETTA", | |
| 507 | + "titleSecondary": "Miranda, 2025", | |
| 508 | + "titleTertiary": null, | |
| 509 | + "description": "RAFFAELE COLETTA Miranda, 2025 signed 'R.Coletta' (on reverse) oil on canvas 76 cm. high x 60 cm. wide", | |
| 510 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.26&LotNumber=26&ldp_breadcrumb=back", | |
| 511 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0026_000(raffaele_coletta_miranda_2025_d6598266055243).jpg?mode=max", | |
| 512 | + "estimateLow": 400, | |
| 513 | + "estimateHigh": 600, | |
| 514 | + "estimateText": "GBP 400 - 600", | |
| 515 | + "priceRealised": 64, | |
| 516 | + "priceRealisedText": "GBP 64", | |
| 517 | + "startDate": "2026-08-20T00:00Z", | |
| 518 | + "endDate": "2026-09-02T23:00Z", | |
| 519 | + "withdrawn": false, | |
| 520 | + "isOver": true | |
| 521 | + }, | |
| 522 | + { | |
| 523 | + "objectId": "6598267", | |
| 524 | + "lotNumber": "27", | |
| 525 | + "titlePrimary": "RAFFAELE COLETTA", | |
| 526 | + "titleSecondary": "Yu-Ge, 2025", | |
| 527 | + "titleTertiary": null, | |
| 528 | + "description": "RAFFAELE COLETTA Yu-Ge, 2025 signed 'R. Coletta' (on reverse) oil on canvas 76 cm. high x 60 cm. wide", | |
| 529 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.27&LotNumber=27&ldp_breadcrumb=back", | |
| 530 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0027_000(raffaele_coletta_yu-ge_2025_d6598267055251).jpg?mode=max", | |
| 531 | + "estimateLow": 400, | |
| 532 | + "estimateHigh": 600, | |
| 533 | + "estimateText": "GBP 400 - 600", | |
| 534 | + "priceRealised": 318, | |
| 535 | + "priceRealisedText": "GBP 318", | |
| 536 | + "startDate": "2026-08-20T00:00Z", | |
| 537 | + "endDate": "2026-09-02T23:00Z", | |
| 538 | + "withdrawn": false, | |
| 539 | + "isOver": true | |
| 540 | + }, | |
| 541 | + { | |
| 542 | + "objectId": "6598268", | |
| 543 | + "lotNumber": "28", | |
| 544 | + "titlePrimary": "GUILLEM MATALLANAS", | |
| 545 | + "titleSecondary": "GENERATION C2, 2019", | |
| 546 | + "titleTertiary": null, | |
| 547 | + "description": "GUILLEM MATALLANAS GENERATION C2, 2019 screenprint on paper 42 cm. high x 59.4 cm. wide", | |
| 548 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.28&LotNumber=28&ldp_breadcrumb=back", | |
| 549 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0028_000(guillem_matallanas_generation_c2_2019054438).jpg?mode=max", | |
| 550 | + "estimateLow": 400, | |
| 551 | + "estimateHigh": 500, | |
| 552 | + "estimateText": "GBP 400 - 500", | |
| 553 | + "priceRealised": 254, | |
| 554 | + "priceRealisedText": "GBP 254", | |
| 555 | + "startDate": "2026-08-20T00:00Z", | |
| 556 | + "endDate": "2026-09-02T23:00Z", | |
| 557 | + "withdrawn": false, | |
| 558 | + "isOver": true | |
| 559 | + }, | |
| 560 | + { | |
| 561 | + "objectId": "6598269", | |
| 562 | + "lotNumber": "29", | |
| 563 | + "titlePrimary": "GRAEME DUDDRIDGE", | |
| 564 | + "titleSecondary": "Stargazer, 2024", | |
| 565 | + "titleTertiary": null, | |
| 566 | + "description": "GRAEME DUDDRIDGE Stargazer, 2024 pencil, watercolour, collage & metal leaf on paper framed: 50.6 cm. high x 70.6 cm. wide", | |
| 567 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.29&LotNumber=29&ldp_breadcrumb=back", | |
| 568 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0029_000(graeme_duddridge_stargazer_2024054445).jpg?mode=max", | |
| 569 | + "estimateLow": 500, | |
| 570 | + "estimateHigh": 800, | |
| 571 | + "estimateText": "GBP 500 - 800", | |
| 572 | + "priceRealised": null, | |
| 573 | + "priceRealisedText": null, | |
| 574 | + "startDate": "2026-08-20T00:00Z", | |
| 575 | + "endDate": "2026-09-02T23:00Z", | |
| 576 | + "withdrawn": false, | |
| 577 | + "isOver": true | |
| 578 | + }, | |
| 579 | + { | |
| 580 | + "objectId": "6598270", | |
| 581 | + "lotNumber": "30", | |
| 582 | + "titlePrimary": "GRAEME DUDDRIDGE", | |
| 583 | + "titleSecondary": "Ellie in Stripes, 2025", | |
| 584 | + "titleTertiary": null, | |
| 585 | + "description": "GRAEME DUDDRIDGE Ellie in Stripes, 2025 oil on board, artist frame in walnut, corian inlay and vintage buttons framed: 65.1 cm. high x 55.5 cm. wide", | |
| 586 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.30&LotNumber=30&ldp_breadcrumb=back", | |
| 587 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0030_000(graeme_duddridge_ellie_in_stripes_2025055306).jpg?mode=max", | |
| 588 | + "estimateLow": 800, | |
| 589 | + "estimateHigh": 1000, | |
| 590 | + "estimateText": "GBP 800 - 1,000", | |
| 591 | + "priceRealised": null, | |
| 592 | + "priceRealisedText": null, | |
| 593 | + "startDate": "2026-08-20T00:00Z", | |
| 594 | + "endDate": "2026-09-02T23:00Z", | |
| 595 | + "withdrawn": false, | |
| 596 | + "isOver": true | |
| 597 | + }, | |
| 598 | + { | |
| 599 | + "objectId": "6598271", | |
| 600 | + "lotNumber": "31", | |
| 601 | + "titlePrimary": "GRAEME DUDDRIDGE", | |
| 602 | + "titleSecondary": "Serving Fish, 2019", | |
| 603 | + "titleTertiary": null, | |
| 604 | + "description": "GRAEME DUDDRIDGE Serving Fish, 2019 signed 'GD' 19 Serving Fish' (on reverse) oil on board 40 cm. high x 28 cm. wide x 3.5 cm. deep", | |
| 605 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.31&LotNumber=31&ldp_breadcrumb=back", | |
| 606 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0031_000(graeme_duddridge_serving_fish_2019055322).jpg?mode=max", | |
| 607 | + "estimateLow": 500, | |
| 608 | + "estimateHigh": 800, | |
| 609 | + "estimateText": "GBP 500 - 800", | |
| 610 | + "priceRealised": 635, | |
| 611 | + "priceRealisedText": "GBP 635", | |
| 612 | + "startDate": "2026-08-20T00:00Z", | |
| 613 | + "endDate": "2026-09-02T23:00Z", | |
| 614 | + "withdrawn": false, | |
| 615 | + "isOver": true | |
| 616 | + }, | |
| 617 | + { | |
| 618 | + "objectId": "6598272", | |
| 619 | + "lotNumber": "32", | |
| 620 | + "titlePrimary": "ALICE GELDENHUYS", | |
| 621 | + "titleSecondary": "Embrace, 2025", | |
| 622 | + "titleTertiary": null, | |
| 623 | + "description": "ALICE GELDENHUYS Embrace, 2025 signed 'ALICE G'25' (on reverse) acrylic on canvas 42 cm. high x 29.5 cm. wide", | |
| 624 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.32&LotNumber=32&ldp_breadcrumb=back", | |
| 625 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0032_000(alice_geldenhuys_embrace_2025055334).jpg?mode=max", | |
| 626 | + "estimateLow": 200, | |
| 627 | + "estimateHigh": 300, | |
| 628 | + "estimateText": "GBP 200 - 300", | |
| 629 | + "priceRealised": null, | |
| 630 | + "priceRealisedText": null, | |
| 631 | + "startDate": "2026-08-20T00:00Z", | |
| 632 | + "endDate": "2026-09-02T23:00Z", | |
| 633 | + "withdrawn": false, | |
| 634 | + "isOver": true | |
| 635 | + }, | |
| 636 | + { | |
| 637 | + "objectId": "6598273", | |
| 638 | + "lotNumber": "33", | |
| 639 | + "titlePrimary": "ALICE GELDENHUYS", | |
| 640 | + "titleSecondary": "Stretch, 2025", | |
| 641 | + "titleTertiary": null, | |
| 642 | + "description": "ALICE GELDENHUYS Stretch, 2025 signed 'ALICE G'25' (on reverse) acrylic on canvas 30.5 cm. high x 41 cm. wide", | |
| 643 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.33&LotNumber=33&ldp_breadcrumb=back", | |
| 644 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0033_000(alice_geldenhuys_stretch_2025_d6598273055347).jpg?mode=max", | |
| 645 | + "estimateLow": 200, | |
| 646 | + "estimateHigh": 300, | |
| 647 | + "estimateText": "GBP 200 - 300", | |
| 648 | + "priceRealised": null, | |
| 649 | + "priceRealisedText": null, | |
| 650 | + "startDate": "2026-08-20T00:00Z", | |
| 651 | + "endDate": "2026-09-02T23:00Z", | |
| 652 | + "withdrawn": false, | |
| 653 | + "isOver": true | |
| 654 | + }, | |
| 655 | + { | |
| 656 | + "objectId": "6598274", | |
| 657 | + "lotNumber": "34", | |
| 658 | + "titlePrimary": "ALICE KIM", | |
| 659 | + "titleSecondary": "O-mi, 2026", | |
| 660 | + "titleTertiary": null, | |
| 661 | + "description": "ALICE KIM O-mi, 2026 Korean traditional organza (ramie and hemp) 21 cm. high x 40 cm. wide", | |
| 662 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.34&LotNumber=34&ldp_breadcrumb=back", | |
| 663 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0034_000(alice_kim_o-mi_2026055354).jpg?mode=max", | |
| 664 | + "estimateLow": 700, | |
| 665 | + "estimateHigh": 900, | |
| 666 | + "estimateText": "GBP 700 - 900", | |
| 667 | + "priceRealised": 508, | |
| 668 | + "priceRealisedText": "GBP 508", | |
| 669 | + "startDate": "2026-08-20T00:00Z", | |
| 670 | + "endDate": "2026-09-02T23:00Z", | |
| 671 | + "withdrawn": false, | |
| 672 | + "isOver": true | |
| 673 | + }, | |
| 674 | + { | |
| 675 | + "objectId": "6598275", | |
| 676 | + "lotNumber": "35", | |
| 677 | + "titlePrimary": "JAMES CAMPION", | |
| 678 | + "titleSecondary": "After Mondrian, 2019", | |
| 679 | + "titleTertiary": null, | |
| 680 | + "description": "JAMES CAMPION After Mondrian, 2019 signed 'Campion 2019' (on reverse) oil on canvas 30 cm. high x 30 cm. wide", | |
| 681 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.35&LotNumber=35&ldp_breadcrumb=back", | |
| 682 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0035_000(james_campion_after_mondrian_2019_d6598275055400).jpg?mode=max", | |
| 683 | + "estimateLow": 600, | |
| 684 | + "estimateHigh": 800, | |
| 685 | + "estimateText": "GBP 600 - 800", | |
| 686 | + "priceRealised": null, | |
| 687 | + "priceRealisedText": null, | |
| 688 | + "startDate": "2026-08-20T00:00Z", | |
| 689 | + "endDate": "2026-09-02T23:00Z", | |
| 690 | + "withdrawn": false, | |
| 691 | + "isOver": true | |
| 692 | + }, | |
| 693 | + { | |
| 694 | + "objectId": "6598276", | |
| 695 | + "lotNumber": "36", | |
| 696 | + "titlePrimary": "JAMES CAMPION", | |
| 697 | + "titleSecondary": "Towel Painting, 2026", | |
| 698 | + "titleTertiary": null, | |
| 699 | + "description": "JAMES CAMPION Towel Painting, 2026 signed 'TOWEL PAINTING I/James Campion 2026' (on reverse) oil on canvas 50 cm. high x 60 cm. wide", | |
| 700 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.36&LotNumber=36&ldp_breadcrumb=back", | |
| 701 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0036_000(james_campion_towel_painting_2026_d6598276055410).jpg?mode=max", | |
| 702 | + "estimateLow": 800, | |
| 703 | + "estimateHigh": 1000, | |
| 704 | + "estimateText": "GBP 800 - 1,000", | |
| 705 | + "priceRealised": null, | |
| 706 | + "priceRealisedText": null, | |
| 707 | + "startDate": "2026-08-20T00:00Z", | |
| 708 | + "endDate": "2026-09-02T23:00Z", | |
| 709 | + "withdrawn": false, | |
| 710 | + "isOver": true | |
| 711 | + }, | |
| 712 | + { | |
| 713 | + "objectId": "6598277", | |
| 714 | + "lotNumber": "37", | |
| 715 | + "titlePrimary": "JAMES CAMPION", | |
| 716 | + "titleSecondary": "Towel Painting II, 2026", | |
| 717 | + "titleTertiary": null, | |
| 718 | + "description": "JAMES CAMPION Towel Painting II, 2026 signed 'TOWEL PAINTING II/ James Campion 2026' (on reverse) oil on canvas 60 cm. high x 50 cm. wide", | |
| 719 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.37&LotNumber=37&ldp_breadcrumb=back", | |
| 720 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0037_000(james_campion_towel_painting_ii_2026_d6598277055417).jpg?mode=max", | |
| 721 | + "estimateLow": 800, | |
| 722 | + "estimateHigh": 1000, | |
| 723 | + "estimateText": "GBP 800 - 1,000", | |
| 724 | + "priceRealised": null, | |
| 725 | + "priceRealisedText": null, | |
| 726 | + "startDate": "2026-08-20T00:00Z", | |
| 727 | + "endDate": "2026-09-02T23:00Z", | |
| 728 | + "withdrawn": false, | |
| 729 | + "isOver": true | |
| 730 | + }, | |
| 731 | + { | |
| 732 | + "objectId": "6598278", | |
| 733 | + "lotNumber": "38", | |
| 734 | + "titlePrimary": "BRONWEN HARRISON", | |
| 735 | + "titleSecondary": "Tidal Vessel", | |
| 736 | + "titleTertiary": null, | |
| 737 | + "description": "BRONWEN HARRISON Tidal Vessel glazed stonewear 18 cm. high x 13 cm. wide x 6 cm. deep", | |
| 738 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.38&LotNumber=38&ldp_breadcrumb=back", | |
| 739 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0038_000(bronwen_harrison_tidal_vessel054518).jpg?mode=max", | |
| 740 | + "estimateLow": 100, | |
| 741 | + "estimateHigh": 200, | |
| 742 | + "estimateText": "GBP 100 - 200", | |
| 743 | + "priceRealised": 127, | |
| 744 | + "priceRealisedText": "GBP 127", | |
| 745 | + "startDate": "2026-08-20T00:00Z", | |
| 746 | + "endDate": "2026-09-02T23:00Z", | |
| 747 | + "withdrawn": false, | |
| 748 | + "isOver": true | |
| 749 | + }, | |
| 750 | + { | |
| 751 | + "objectId": "6598279", | |
| 752 | + "lotNumber": "39", | |
| 753 | + "titlePrimary": "BRONWEN HARRISON", | |
| 754 | + "titleSecondary": "Tidal Vessel II", | |
| 755 | + "titleTertiary": null, | |
| 756 | + "description": "BRONWEN HARRISON Tidal Vessel II glazed stoneware 13 cm. high x 14 cm. wide x 13 cm. deep", | |
| 757 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.39&LotNumber=39&ldp_breadcrumb=back", | |
| 758 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0039_000(bronwen_harrison_tidal_vessel_ii054524).jpg?mode=max", | |
| 759 | + "estimateLow": 100, | |
| 760 | + "estimateHigh": 200, | |
| 761 | + "estimateText": "GBP 100 - 200", | |
| 762 | + "priceRealised": 254, | |
| 763 | + "priceRealisedText": "GBP 254", | |
| 764 | + "startDate": "2026-08-20T00:00Z", | |
| 765 | + "endDate": "2026-09-02T23:00Z", | |
| 766 | + "withdrawn": false, | |
| 767 | + "isOver": true | |
| 768 | + }, | |
| 769 | + { | |
| 770 | + "objectId": "6598280", | |
| 771 | + "lotNumber": "40", | |
| 772 | + "titlePrimary": "BRONWEN HARRISON", | |
| 773 | + "titleSecondary": "Upside-down Bowl", | |
| 774 | + "titleTertiary": null, | |
| 775 | + "description": "BRONWEN HARRISON Upside-down Bowl glazed stoneware 19 cm. high x 38 cm. wide x 13 cm. deep", | |
| 776 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.40&LotNumber=40&ldp_breadcrumb=back", | |
| 777 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0040_000(bronwen_harrison_upside-down_bowl054530).jpg?mode=max", | |
| 778 | + "estimateLow": 100, | |
| 779 | + "estimateHigh": 200, | |
| 780 | + "estimateText": "GBP 100 - 200", | |
| 781 | + "priceRealised": 127, | |
| 782 | + "priceRealisedText": "GBP 127", | |
| 783 | + "startDate": "2026-08-20T00:00Z", | |
| 784 | + "endDate": "2026-09-02T23:00Z", | |
| 785 | + "withdrawn": false, | |
| 786 | + "isOver": true | |
| 787 | + }, | |
| 788 | + { | |
| 789 | + "objectId": "6598281", | |
| 790 | + "lotNumber": "41", | |
| 791 | + "titlePrimary": "SANDRA ROMITO", | |
| 792 | + "titleSecondary": "Toto's Vases", | |
| 793 | + "titleTertiary": null, | |
| 794 | + "description": "SANDRA ROMITO Toto's Vases ceramic 30 cm. high x 20 cm. wide x 20 cm. deep(3)", | |
| 795 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.41&LotNumber=41&ldp_breadcrumb=back", | |
| 796 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0041_000(sandra_romito_totos_vases054547).jpg?mode=max", | |
| 797 | + "estimateLow": 400, | |
| 798 | + "estimateHigh": 600, | |
| 799 | + "estimateText": "GBP 400 - 600", | |
| 800 | + "priceRealised": 508, | |
| 801 | + "priceRealisedText": "GBP 508", | |
| 802 | + "startDate": "2026-08-20T00:00Z", | |
| 803 | + "endDate": "2026-09-02T23:00Z", | |
| 804 | + "withdrawn": false, | |
| 805 | + "isOver": true | |
| 806 | + }, | |
| 807 | + { | |
| 808 | + "objectId": "6598282", | |
| 809 | + "lotNumber": "42", | |
| 810 | + "titlePrimary": "PRAPASRI SUWANNAKHOT", | |
| 811 | + "titleSecondary": "Experimental - Ripley, 2026", | |
| 812 | + "titleTertiary": null, | |
| 813 | + "description": "PRAPASRI SUWANNAKHOT Experimental - Ripley, 2026 pendant, charm freshwater baroque pearl, silver, cubic zirconia 2 cm. high x 2.7 cm. wide x 0.5 cm. deep", | |
| 814 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.42&LotNumber=42&ldp_breadcrumb=back", | |
| 815 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0042_000(prapasri_suwannakhot_experimental_-_ripley_2026055534).jpg?mode=max", | |
| 816 | + "estimateLow": 50, | |
| 817 | + "estimateHigh": 100, | |
| 818 | + "estimateText": "GBP 50 - 100", | |
| 819 | + "priceRealised": 64, | |
| 820 | + "priceRealisedText": "GBP 64", | |
| 821 | + "startDate": "2026-08-20T00:00Z", | |
| 822 | + "endDate": "2026-09-02T23:00Z", | |
| 823 | + "withdrawn": false, | |
| 824 | + "isOver": true | |
| 825 | + }, | |
| 826 | + { | |
| 827 | + "objectId": "6598283", | |
| 828 | + "lotNumber": "43", | |
| 829 | + "titlePrimary": "PRAPASRI SUWANNAKHOT", | |
| 830 | + "titleSecondary": "RGB Chameleon Pendant Necklace, 2022", | |
| 831 | + "titleTertiary": null, | |
| 832 | + "description": "PRAPASRI SUWANNAKHOT RGB Chameleon Pendant Necklace, 2022 made in 2022, UK hallmarked 2026 diamond, colourless sapphire, garnet, mystic topaz, cold enamel pendant on foxtail chain mystic topaz is a natural colourless topaz stone enhanced with a thin metallic coating pendant: 2.6 cm. high x 1.8 cm. wide x 1.1 cm. deep chain: 51.4 cm. lengh", | |
| 833 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.43&LotNumber=43&ldp_breadcrumb=back", | |
| 834 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0043_000(prapasri_suwannakhot_rgb_chameleon_pendant_necklace_2022054617).jpg?mode=max", | |
| 835 | + "estimateLow": 700, | |
| 836 | + "estimateHigh": 900, | |
| 837 | + "estimateText": "GBP 700 - 900", | |
| 838 | + "priceRealised": 1143, | |
| 839 | + "priceRealisedText": "GBP 1,143", | |
| 840 | + "startDate": "2026-08-20T00:00Z", | |
| 841 | + "endDate": "2026-09-02T23:00Z", | |
| 842 | + "withdrawn": false, | |
| 843 | + "isOver": true | |
| 844 | + }, | |
| 845 | + { | |
| 846 | + "objectId": "6598284", | |
| 847 | + "lotNumber": "44", | |
| 848 | + "titlePrimary": "PRAPASRI SUWANNAKHOT", | |
| 849 | + "titleSecondary": "Mystic Ring - Chameleon Ring, 2022", | |
| 850 | + "titleTertiary": null, | |
| 851 | + "description": "PRAPASRI SUWANNAKHOT Mystic Ring - Chameleon Ring, 2022 made in 2022, UK hallmarked 2026 mystic topaz, silver, sapphires mystic topaz is a natural colourless topaz stone enhanced with a thin metallic coating 2.7 cm. high x 2.5 cm. wide x 5.2 cm. deep ring size: EU 60, UK S, US 9 not recommend for resizing due to stone settings", | |
| 852 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.44&LotNumber=44&ldp_breadcrumb=back", | |
| 853 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0044_000(prapasri_suwannakhot_mystic_ring_-_chameleon_ring_2022_d6598284055608).jpg?mode=max", | |
| 854 | + "estimateLow": 700, | |
| 855 | + "estimateHigh": 900, | |
| 856 | + "estimateText": "GBP 700 - 900", | |
| 857 | + "priceRealised": 762, | |
| 858 | + "priceRealisedText": "GBP 762", | |
| 859 | + "startDate": "2026-08-20T00:00Z", | |
| 860 | + "endDate": "2026-09-02T23:00Z", | |
| 861 | + "withdrawn": false, | |
| 862 | + "isOver": true | |
| 863 | + }, | |
| 864 | + { | |
| 865 | + "objectId": "6598285", | |
| 866 | + "lotNumber": "45", | |
| 867 | + "titlePrimary": "PRAPASRI SUWANNAKHOT", | |
| 868 | + "titleSecondary": "Half Eternity Orange Sapphire, 2023", | |
| 869 | + "titleTertiary": null, | |
| 870 | + "description": "PRAPASRI SUWANNAKHOT Half Eternity Orange Sapphire, 2023 UK hallmarked, 2023 coloured diamonds, orange sapphire, silver, yellow gold plating 2 cm. high x 0.56 cm. wide x 2.2 cm. deep ring size: EU 57, UK Q, US 8 not recommend for resizing due to stone settings", | |
| 871 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.45&LotNumber=45&ldp_breadcrumb=back", | |
| 872 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0045_000(prapasri_suwannakhot_half_eternity_orange_sapphire_2023_d6598285055614).jpg?mode=max", | |
| 873 | + "estimateLow": 300, | |
| 874 | + "estimateHigh": 500, | |
| 875 | + "estimateText": "GBP 300 - 500", | |
| 876 | + "priceRealised": 318, | |
| 877 | + "priceRealisedText": "GBP 318", | |
| 878 | + "startDate": "2026-08-20T00:00Z", | |
| 879 | + "endDate": "2026-09-02T23:00Z", | |
| 880 | + "withdrawn": false, | |
| 881 | + "isOver": true | |
| 882 | + }, | |
| 883 | + { | |
| 884 | + "objectId": "6598286", | |
| 885 | + "lotNumber": "46", | |
| 886 | + "titlePrimary": "PRAPASRI SUWANNAKHOT", | |
| 887 | + "titleSecondary": "TzTs ring, 2023", | |
| 888 | + "titleTertiary": null, | |
| 889 | + "description": "PRAPASRI SUWANNAKHOT TzTs ring, 2023 UK hallmarked, 2023 silver, tanzanite, tsavorite 2.37 cm. high x 1.0 cm. wide x 2.31 cm. deep ring size: EU 57, UK Q, US 8 not recommend for resizing due to stone settings", | |
| 890 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.46&LotNumber=46&ldp_breadcrumb=back", | |
| 891 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0046_000(prapasri_suwannakhot_tzts_ring_2023_d6598286055620).jpg?mode=max", | |
| 892 | + "estimateLow": 400, | |
| 893 | + "estimateHigh": 600, | |
| 894 | + "estimateText": "GBP 400 - 600", | |
| 895 | + "priceRealised": 254, | |
| 896 | + "priceRealisedText": "GBP 254", | |
| 897 | + "startDate": "2026-08-20T00:00Z", | |
| 898 | + "endDate": "2026-09-02T23:00Z", | |
| 899 | + "withdrawn": false, | |
| 900 | + "isOver": true | |
| 901 | + }, | |
| 902 | + { | |
| 903 | + "objectId": "6598287", | |
| 904 | + "lotNumber": "47", | |
| 905 | + "titlePrimary": "LUCIA ALONSO-LASHERAS SMITH", | |
| 906 | + "titleSecondary": "Chez Richard, 2026", | |
| 907 | + "titleTertiary": null, | |
| 908 | + "description": "LUCIA ALONSO-LASHERAS SMITH Chez Richard, 2026 oil on canvas board 32.8 cm. high x 24.4 cm. wide", | |
| 909 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.47&LotNumber=47&ldp_breadcrumb=back", | |
| 910 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0047_000(lucia_alonso-lasheras_smith_chez_richard_2026_d6598287055628).jpg?mode=max", | |
| 911 | + "estimateLow": 100, | |
| 912 | + "estimateHigh": 200, | |
| 913 | + "estimateText": "GBP 100 - 200", | |
| 914 | + "priceRealised": 381, | |
| 915 | + "priceRealisedText": "GBP 381", | |
| 916 | + "startDate": "2026-08-20T00:00Z", | |
| 917 | + "endDate": "2026-09-02T23:00Z", | |
| 918 | + "withdrawn": false, | |
| 919 | + "isOver": true | |
| 920 | + }, | |
| 921 | + { | |
| 922 | + "objectId": "6598288", | |
| 923 | + "lotNumber": "48", | |
| 924 | + "titlePrimary": "RUTH ANDERTON", | |
| 925 | + "titleSecondary": "In the Noodle Bar, 2026", | |
| 926 | + "titleTertiary": null, | |
| 927 | + "description": "RUTH ANDERTON In the Noodle Bar, 2026 signed 'Ruth S. Anderton 2026' (on reverse) oil on canvas 30 cm. high x 30 cm. wide", | |
| 928 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.48&LotNumber=48&ldp_breadcrumb=back", | |
| 929 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0048_000(ruth_anderton_in_the_noodle_bar_2026054717).jpg?mode=max", | |
| 930 | + "estimateLow": 400, | |
| 931 | + "estimateHigh": 600, | |
| 932 | + "estimateText": "GBP 400 - 600", | |
| 933 | + "priceRealised": 381, | |
| 934 | + "priceRealisedText": "GBP 381", | |
| 935 | + "startDate": "2026-08-20T00:00Z", | |
| 936 | + "endDate": "2026-09-02T23:00Z", | |
| 937 | + "withdrawn": false, | |
| 938 | + "isOver": true | |
| 939 | + }, | |
| 940 | + { | |
| 941 | + "objectId": "6598289", | |
| 942 | + "lotNumber": "49", | |
| 943 | + "titlePrimary": "SOPHIE KHAN", | |
| 944 | + "titleSecondary": "Anonymous, 2026", | |
| 945 | + "titleTertiary": null, | |
| 946 | + "description": "SOPHIE KHAN Anonymous, 2026 35mm photograph on hahnemühle paper framed: 32.6 cm. high x 23.9 cm. wide", | |
| 947 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.49&LotNumber=49&ldp_breadcrumb=back", | |
| 948 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0049_000(sophie_khan_anonymous_2026054731).jpg?mode=max", | |
| 949 | + "estimateLow": 100, | |
| 950 | + "estimateHigh": 200, | |
| 951 | + "estimateText": "GBP 100 - 200", | |
| 952 | + "priceRealised": 64, | |
| 953 | + "priceRealisedText": "GBP 64", | |
| 954 | + "startDate": "2026-08-20T00:00Z", | |
| 955 | + "endDate": "2026-09-02T23:00Z", | |
| 956 | + "withdrawn": false, | |
| 957 | + "isOver": true | |
| 958 | + }, | |
| 959 | + { | |
| 960 | + "objectId": "6598290", | |
| 961 | + "lotNumber": "50", | |
| 962 | + "titlePrimary": "SOPHIE KHAN", | |
| 963 | + "titleSecondary": "Path, 2026", | |
| 964 | + "titleTertiary": null, | |
| 965 | + "description": "SOPHIE KHAN Path, 2026 35mm photograph on hahnemühle paper framed: 44.6 cm. high x 32.5 cm. wide", | |
| 966 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.50&LotNumber=50&ldp_breadcrumb=back", | |
| 967 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0050_000(sophie_khan_path_2026055642).jpg?mode=max", | |
| 968 | + "estimateLow": 100, | |
| 969 | + "estimateHigh": 200, | |
| 970 | + "estimateText": "GBP 100 - 200", | |
| 971 | + "priceRealised": 64, | |
| 972 | + "priceRealisedText": "GBP 64", | |
| 973 | + "startDate": "2026-08-20T00:00Z", | |
| 974 | + "endDate": "2026-09-02T23:00Z", | |
| 975 | + "withdrawn": false, | |
| 976 | + "isOver": true | |
| 977 | + }, | |
| 978 | + { | |
| 979 | + "objectId": "6598291", | |
| 980 | + "lotNumber": "51", | |
| 981 | + "titlePrimary": "SOPHIE KHAN", | |
| 982 | + "titleSecondary": "Moke, 2026", | |
| 983 | + "titleTertiary": null, | |
| 984 | + "description": "SOPHIE KHAN Moke, 2026 35mm photograph on hahnemühle paper framed: 44.6 cm. high x 32.5 cm. wide", | |
| 985 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.51&LotNumber=51&ldp_breadcrumb=back", | |
| 986 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0051_000(sophie_khan_moke_2026_d6598291055657).jpg?mode=max", | |
| 987 | + "estimateLow": 100, | |
| 988 | + "estimateHigh": 200, | |
| 989 | + "estimateText": "GBP 100 - 200", | |
| 990 | + "priceRealised": 127, | |
| 991 | + "priceRealisedText": "GBP 127", | |
| 992 | + "startDate": "2026-08-20T00:00Z", | |
| 993 | + "endDate": "2026-09-02T23:00Z", | |
| 994 | + "withdrawn": false, | |
| 995 | + "isOver": true | |
| 996 | + }, | |
| 997 | + { | |
| 998 | + "objectId": "6598292", | |
| 999 | + "lotNumber": "52", | |
| 1000 | + "titlePrimary": "NATASHA WILCOCKSON", | |
| 1001 | + "titleSecondary": "Fallow Year, 2026", | |
| 1002 | + "titleTertiary": null, | |
| 1003 | + "description": "NATASHA WILCOCKSON Fallow Year, 2026 signed 'NW' (lower right) and '\"Fallow Year\" July 2026 Natasha Wilcockson' (on reverse) acrylic on canvas 50 cm. high x 40 cm. wide", | |
| 1004 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.52&LotNumber=52&ldp_breadcrumb=back", | |
| 1005 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0052_000(natasha_wilcockson_fallow_year_2026055705).jpg?mode=max", | |
| 1006 | + "estimateLow": 100, | |
| 1007 | + "estimateHigh": 200, | |
| 1008 | + "estimateText": "GBP 100 - 200", | |
| 1009 | + "priceRealised": 190, | |
| 1010 | + "priceRealisedText": "GBP 190", | |
| 1011 | + "startDate": "2026-08-20T00:00Z", | |
| 1012 | + "endDate": "2026-09-02T23:00Z", | |
| 1013 | + "withdrawn": false, | |
| 1014 | + "isOver": true | |
| 1015 | + }, | |
| 1016 | + { | |
| 1017 | + "objectId": "6598293", | |
| 1018 | + "lotNumber": "53", | |
| 1019 | + "titlePrimary": "NJALL MILLEN", | |
| 1020 | + "titleSecondary": "Clifton Nurseries, Maida Vale (Saturn glimpsed at pink dawn)", | |
| 1021 | + "titleTertiary": null, | |
| 1022 | + "description": "NJALL MILLEN Clifton Nurseries, Maida Vale (Saturn glimpsed at pink dawn) signed 'Njall Millen 2026' (on reverse) oil on canvas 50 cm. high x 40 cm. wide", | |
| 1023 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.53&LotNumber=53&ldp_breadcrumb=back", | |
| 1024 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0053_000(neil_millen_clifton_nurseries_maida_vale055719).jpg?mode=max", | |
| 1025 | + "estimateLow": 500, | |
| 1026 | + "estimateHigh": 800, | |
| 1027 | + "estimateText": "GBP 500 - 800", | |
| 1028 | + "priceRealised": 635, | |
| 1029 | + "priceRealisedText": "GBP 635", | |
| 1030 | + "startDate": "2026-08-20T00:00Z", | |
| 1031 | + "endDate": "2026-09-02T23:00Z", | |
| 1032 | + "withdrawn": false, | |
| 1033 | + "isOver": true | |
| 1034 | + }, | |
| 1035 | + { | |
| 1036 | + "objectId": "6598294", | |
| 1037 | + "lotNumber": "54", | |
| 1038 | + "titlePrimary": "NJALL MILLEN", | |
| 1039 | + "titleSecondary": "Dawn from the Artist's Window (A Clatter of Jackdaws, Cornwall), 2026", | |
| 1040 | + "titleTertiary": null, | |
| 1041 | + "description": "NJALL MILLEN Dawn from the Artist's Window (A Clatter of Jackdaws, Cornwall), 2026 signed 'Njall Millen 2026' (on reverse) oil on canvas 40 cm. high x 30 cm. wide", | |
| 1042 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.54&LotNumber=54&ldp_breadcrumb=back", | |
| 1043 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0054_000(neil_millen_duallium_2026054744).jpg?mode=max", | |
| 1044 | + "estimateLow": 400, | |
| 1045 | + "estimateHigh": 700, | |
| 1046 | + "estimateText": "GBP 400 - 700", | |
| 1047 | + "priceRealised": 508, | |
| 1048 | + "priceRealisedText": "GBP 508", | |
| 1049 | + "startDate": "2026-08-20T00:00Z", | |
| 1050 | + "endDate": "2026-09-02T23:00Z", | |
| 1051 | + "withdrawn": false, | |
| 1052 | + "isOver": true | |
| 1053 | + }, | |
| 1054 | + { | |
| 1055 | + "objectId": "6598295", | |
| 1056 | + "lotNumber": "55", | |
| 1057 | + "titlePrimary": "NJALL MILLEN", | |
| 1058 | + "titleSecondary": "Lone Raven over Fields, St Agnes Beacon, with Copper Clouds, 2026", | |
| 1059 | + "titleTertiary": null, | |
| 1060 | + "description": "NJALL MILLEN Lone Raven over Fields, St Agnes Beacon, with Copper Clouds, 2026 signed 'Njall Millen 2026' (on reverse) oil on canvas 30 cm. high x 40 cm. wide", | |
| 1061 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.55&LotNumber=55&ldp_breadcrumb=back", | |
| 1062 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0055_000(neil_millen_lone_raven_over_fields_st_agnes_beacon_with_copper_clouds054751).jpg?mode=max", | |
| 1063 | + "estimateLow": 400, | |
| 1064 | + "estimateHigh": 700, | |
| 1065 | + "estimateText": "GBP 400 - 700", | |
| 1066 | + "priceRealised": null, | |
| 1067 | + "priceRealisedText": null, | |
| 1068 | + "startDate": "2026-08-20T00:00Z", | |
| 1069 | + "endDate": "2026-09-02T23:00Z", | |
| 1070 | + "withdrawn": false, | |
| 1071 | + "isOver": true | |
| 1072 | + }, | |
| 1073 | + { | |
| 1074 | + "objectId": "6598296", | |
| 1075 | + "lotNumber": "56", | |
| 1076 | + "titlePrimary": "COOKIE BERGMAN", | |
| 1077 | + "titleSecondary": "We Are Starstuff", | |
| 1078 | + "titleTertiary": null, | |
| 1079 | + "description": "COOKIE BERGMAN We Are Starstuff signed as edition 1⁄7 Print on Aluminium Dibond, Black Oak Artbox frame. Digital collage print size: 21 cm. high x 20 cm. wide framed: 21.8 high x 20.8 cm wide", | |
| 1080 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.56&LotNumber=56&ldp_breadcrumb=back", | |
| 1081 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0056_000(cookie_bergman_we_are_starstuff_d6598296055735).jpg?mode=max", | |
| 1082 | + "estimateLow": 300, | |
| 1083 | + "estimateHigh": 500, | |
| 1084 | + "estimateText": "GBP 300 - 500", | |
| 1085 | + "priceRealised": 254, | |
| 1086 | + "priceRealisedText": "GBP 254", | |
| 1087 | + "startDate": "2026-08-20T00:00Z", | |
| 1088 | + "endDate": "2026-09-02T23:00Z", | |
| 1089 | + "withdrawn": false, | |
| 1090 | + "isOver": true | |
| 1091 | + }, | |
| 1092 | + { | |
| 1093 | + "objectId": "6598297", | |
| 1094 | + "lotNumber": "57", | |
| 1095 | + "titlePrimary": "COOKIE BERGMAN", | |
| 1096 | + "titleSecondary": "Postcard from a Speculative Past", | |
| 1097 | + "titleTertiary": null, | |
| 1098 | + "description": "COOKIE BERGMAN Postcard from a Speculative Past signed as edition 1⁄7 framed, photography, giclée fine art print 17.8 cm. high x 29.7 cm. wide (print dimensions without frame)", | |
| 1099 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.57&LotNumber=57&ldp_breadcrumb=back", | |
| 1100 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0057_000(cookie_bergman_postcard_from_a_speculative_past054811).jpg?mode=max", | |
| 1101 | + "estimateLow": 300, | |
| 1102 | + "estimateHigh": 500, | |
| 1103 | + "estimateText": "GBP 300 - 500", | |
| 1104 | + "priceRealised": 254, | |
| 1105 | + "priceRealisedText": "GBP 254", | |
| 1106 | + "startDate": "2026-08-20T00:00Z", | |
| 1107 | + "endDate": "2026-09-02T23:00Z", | |
| 1108 | + "withdrawn": false, | |
| 1109 | + "isOver": true | |
| 1110 | + }, | |
| 1111 | + { | |
| 1112 | + "objectId": "6598298", | |
| 1113 | + "lotNumber": "58", | |
| 1114 | + "titlePrimary": "SHARON SMART", | |
| 1115 | + "titleSecondary": "Seascape I, 2019", | |
| 1116 | + "titleTertiary": null, | |
| 1117 | + "description": "SHARON SMART Seascape I, 2019 signed 'Smart '19' (lower right) pencil on paper framed: 22.5 cm. high x 26.5 cm. wide", | |
| 1118 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.58&LotNumber=58&ldp_breadcrumb=back", | |
| 1119 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0058_000(sharon_smart_seascape_i_2019054823).jpg?mode=max", | |
| 1120 | + "estimateLow": 100, | |
| 1121 | + "estimateHigh": 200, | |
| 1122 | + "estimateText": "GBP 100 - 200", | |
| 1123 | + "priceRealised": null, | |
| 1124 | + "priceRealisedText": null, | |
| 1125 | + "startDate": "2026-08-20T00:00Z", | |
| 1126 | + "endDate": "2026-09-02T23:00Z", | |
| 1127 | + "withdrawn": false, | |
| 1128 | + "isOver": true | |
| 1129 | + }, | |
| 1130 | + { | |
| 1131 | + "objectId": "6598299", | |
| 1132 | + "lotNumber": "59", | |
| 1133 | + "titlePrimary": "SHARON SMART", | |
| 1134 | + "titleSecondary": "Seascape IV, 2019", | |
| 1135 | + "titleTertiary": null, | |
| 1136 | + "description": "SHARON SMART Seascape IV, 2019 signed 'Smart '19' (lower right) pencil on paper framed: 22.5 cm. high x 26.5 cm. wide", | |
| 1137 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.59&LotNumber=59&ldp_breadcrumb=back", | |
| 1138 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0059_000(sharon_smart_seascape_iv_2019054830).jpg?mode=max", | |
| 1139 | + "estimateLow": 100, | |
| 1140 | + "estimateHigh": 200, | |
| 1141 | + "estimateText": "GBP 100 - 200", | |
| 1142 | + "priceRealised": null, | |
| 1143 | + "priceRealisedText": null, | |
| 1144 | + "startDate": "2026-08-20T00:00Z", | |
| 1145 | + "endDate": "2026-09-02T23:00Z", | |
| 1146 | + "withdrawn": false, | |
| 1147 | + "isOver": true | |
| 1148 | + }, | |
| 1149 | + { | |
| 1150 | + "objectId": "6598300", | |
| 1151 | + "lotNumber": "60", | |
| 1152 | + "titlePrimary": "SHARON SMART", | |
| 1153 | + "titleSecondary": "Seascape III, 2019", | |
| 1154 | + "titleTertiary": null, | |
| 1155 | + "description": "SHARON SMART Seascape III, 2019 signed 'Smart '19' (lower right) pencil on paper framed: 22.5 cm. high x 26.5 cm. wide", | |
| 1156 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.60&LotNumber=60&ldp_breadcrumb=back", | |
| 1157 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0060_000(sharon_smart_seascape_iii_2019054836).jpg?mode=max", | |
| 1158 | + "estimateLow": 100, | |
| 1159 | + "estimateHigh": 200, | |
| 1160 | + "estimateText": "GBP 100 - 200", | |
| 1161 | + "priceRealised": null, | |
| 1162 | + "priceRealisedText": null, | |
| 1163 | + "startDate": "2026-08-20T00:00Z", | |
| 1164 | + "endDate": "2026-09-02T23:00Z", | |
| 1165 | + "withdrawn": false, | |
| 1166 | + "isOver": true | |
| 1167 | + }, | |
| 1168 | + { | |
| 1169 | + "objectId": "6598301", | |
| 1170 | + "lotNumber": "61", | |
| 1171 | + "titlePrimary": "KEVIN FRAZER", | |
| 1172 | + "titleSecondary": "Combestone Tor, Dartmoor", | |
| 1173 | + "titleTertiary": null, | |
| 1174 | + "description": "KEVIN FRAZER Combestone Tor, Dartmoor hahnemühle fine art photographic 308 GSM print 61 cm. high x 46 cm. wide", | |
| 1175 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.61&LotNumber=61&ldp_breadcrumb=back", | |
| 1176 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0061_000(kevin_frazer_defenders_of_the_realm054843).jpg?mode=max", | |
| 1177 | + "estimateLow": 200, | |
| 1178 | + "estimateHigh": 300, | |
| 1179 | + "estimateText": "GBP 200 - 300", | |
| 1180 | + "priceRealised": null, | |
| 1181 | + "priceRealisedText": null, | |
| 1182 | + "startDate": "2026-08-20T00:00Z", | |
| 1183 | + "endDate": "2026-09-02T23:00Z", | |
| 1184 | + "withdrawn": false, | |
| 1185 | + "isOver": true | |
| 1186 | + }, | |
| 1187 | + { | |
| 1188 | + "objectId": "6598302", | |
| 1189 | + "lotNumber": "62", | |
| 1190 | + "titlePrimary": "KEVIN FRAZER", | |
| 1191 | + "titleSecondary": "Defenders of the Realm", | |
| 1192 | + "titleTertiary": null, | |
| 1193 | + "description": "KEVIN FRAZER Defenders of the Realm hahnemühle fine art photographic 308 GSM print 51 cm. high x 35.5 cm. wide", | |
| 1194 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.62&LotNumber=62&ldp_breadcrumb=back", | |
| 1195 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0062_000(kevin_frazer_combestone_tor_dartmoor054850).jpg?mode=max", | |
| 1196 | + "estimateLow": 200, | |
| 1197 | + "estimateHigh": 300, | |
| 1198 | + "estimateText": "GBP 200 - 300", | |
| 1199 | + "priceRealised": 127, | |
| 1200 | + "priceRealisedText": "GBP 127", | |
| 1201 | + "startDate": "2026-08-20T00:00Z", | |
| 1202 | + "endDate": "2026-09-02T23:00Z", | |
| 1203 | + "withdrawn": false, | |
| 1204 | + "isOver": true | |
| 1205 | + }, | |
| 1206 | + { | |
| 1207 | + "objectId": "6598303", | |
| 1208 | + "lotNumber": "63", | |
| 1209 | + "titlePrimary": "KEVIN FRAZER", | |
| 1210 | + "titleSecondary": "Synchro Pair", | |
| 1211 | + "titleTertiary": null, | |
| 1212 | + "description": "KEVIN FRAZER Synchro Pair hahnemühle fine art photographic 308 GSM print 46 cm. high x 30.5 cm. wide", | |
| 1213 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.63&LotNumber=63&ldp_breadcrumb=back", | |
| 1214 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0063_000(kevin_frazer_synchro_pair054855).jpg?mode=max", | |
| 1215 | + "estimateLow": 100, | |
| 1216 | + "estimateHigh": 200, | |
| 1217 | + "estimateText": "GBP 100 - 200", | |
| 1218 | + "priceRealised": 64, | |
| 1219 | + "priceRealisedText": "GBP 64", | |
| 1220 | + "startDate": "2026-08-20T00:00Z", | |
| 1221 | + "endDate": "2026-09-02T23:00Z", | |
| 1222 | + "withdrawn": false, | |
| 1223 | + "isOver": true | |
| 1224 | + }, | |
| 1225 | + { | |
| 1226 | + "objectId": "6598304", | |
| 1227 | + "lotNumber": "64", | |
| 1228 | + "titlePrimary": "FERNANDO LOBINA", | |
| 1229 | + "titleSecondary": "Iceland, 2022", | |
| 1230 | + "titleTertiary": null, | |
| 1231 | + "description": "FERNANDO LOBINA Iceland, 2022 photograpic print 22 cm. high x 30 cm. wide", | |
| 1232 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.64&LotNumber=64&ldp_breadcrumb=back", | |
| 1233 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0064_000(fernando_lobina_iceland_2022054901).jpg?mode=max", | |
| 1234 | + "estimateLow": 100, | |
| 1235 | + "estimateHigh": 200, | |
| 1236 | + "estimateText": "GBP 100 - 200", | |
| 1237 | + "priceRealised": 127, | |
| 1238 | + "priceRealisedText": "GBP 127", | |
| 1239 | + "startDate": "2026-08-20T00:00Z", | |
| 1240 | + "endDate": "2026-09-02T23:00Z", | |
| 1241 | + "withdrawn": false, | |
| 1242 | + "isOver": true | |
| 1243 | + }, | |
| 1244 | + { | |
| 1245 | + "objectId": "6598305", | |
| 1246 | + "lotNumber": "65", | |
| 1247 | + "titlePrimary": "CAMILLA ELLINGSEN WEBSTER", | |
| 1248 | + "titleSecondary": "Open, 2018", | |
| 1249 | + "titleTertiary": null, | |
| 1250 | + "description": "CAMILLA ELLINGSEN WEBSTER Open, 2018 signed 'A/P \"Open\" CW' photograph image: 12.7 cm. high x 12.7 cm. wide framed: 25.4 cm. high x 25.4 cm. wide", | |
| 1251 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.65&LotNumber=65&ldp_breadcrumb=back", | |
| 1252 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0065_000(camilla_ellingsen_webster_open_2018054907).jpg?mode=max", | |
| 1253 | + "estimateLow": 100, | |
| 1254 | + "estimateHigh": 200, | |
| 1255 | + "estimateText": "GBP 100 - 200", | |
| 1256 | + "priceRealised": 190, | |
| 1257 | + "priceRealisedText": "GBP 190", | |
| 1258 | + "startDate": "2026-08-20T00:00Z", | |
| 1259 | + "endDate": "2026-09-02T23:00Z", | |
| 1260 | + "withdrawn": false, | |
| 1261 | + "isOver": true | |
| 1262 | + }, | |
| 1263 | + { | |
| 1264 | + "objectId": "6598306", | |
| 1265 | + "lotNumber": "66", | |
| 1266 | + "titlePrimary": "CAMILLA ELLINGSEN WEBSTER", | |
| 1267 | + "titleSecondary": "Lolita, 2018", | |
| 1268 | + "titleTertiary": null, | |
| 1269 | + "description": "CAMILLA ELLINGSEN WEBSTER Lolita, 2018 signed 'A/P \"Lolita\"CW' (centre) photograph image: 25.4 cm. high × 25.4 cm. wide framed: 50.8 cm. high × 50.8 cm. wide", | |
| 1270 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.66&LotNumber=66&ldp_breadcrumb=back", | |
| 1271 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0066_000(camilla_ellingsen_webster_lolita_2018054914).jpg?mode=max", | |
| 1272 | + "estimateLow": 200, | |
| 1273 | + "estimateHigh": 300, | |
| 1274 | + "estimateText": "GBP 200 - 300", | |
| 1275 | + "priceRealised": 64, | |
| 1276 | + "priceRealisedText": "GBP 64", | |
| 1277 | + "startDate": "2026-08-20T00:00Z", | |
| 1278 | + "endDate": "2026-09-02T23:00Z", | |
| 1279 | + "withdrawn": false, | |
| 1280 | + "isOver": true | |
| 1281 | + }, | |
| 1282 | + { | |
| 1283 | + "objectId": "6598307", | |
| 1284 | + "lotNumber": "67", | |
| 1285 | + "titlePrimary": "CAMILLA ELLINGSEN WEBSTER", | |
| 1286 | + "titleSecondary": "Path, 2023", | |
| 1287 | + "titleTertiary": null, | |
| 1288 | + "description": "CAMILLA ELLINGSEN WEBSTER Path, 2023 signed 'A/P \"Path\" CW' (centre) photography 50.8 cm. high x 50.8 cm. wide", | |
| 1289 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.67&LotNumber=67&ldp_breadcrumb=back", | |
| 1290 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0067_000(camilla_ellingsen_webster_path_2023054921).jpg?mode=max", | |
| 1291 | + "estimateLow": 200, | |
| 1292 | + "estimateHigh": 300, | |
| 1293 | + "estimateText": "GBP 200 - 300", | |
| 1294 | + "priceRealised": null, | |
| 1295 | + "priceRealisedText": null, | |
| 1296 | + "startDate": "2026-08-20T00:00Z", | |
| 1297 | + "endDate": "2026-09-02T23:00Z", | |
| 1298 | + "withdrawn": false, | |
| 1299 | + "isOver": true | |
| 1300 | + }, | |
| 1301 | + { | |
| 1302 | + "objectId": "6598308", | |
| 1303 | + "lotNumber": "68", | |
| 1304 | + "titlePrimary": "BENJAMIN SMITH", | |
| 1305 | + "titleSecondary": "Glider", | |
| 1306 | + "titleTertiary": null, | |
| 1307 | + "description": "BENJAMIN SMITH Glider 35mm film on photo paper framed: 66 cm. high x 66 cm. wide", | |
| 1308 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.68&LotNumber=68&ldp_breadcrumb=back", | |
| 1309 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0068_000(benjamin_smith_glider054928).jpg?mode=max", | |
| 1310 | + "estimateLow": 50, | |
| 1311 | + "estimateHigh": 100, | |
| 1312 | + "estimateText": "GBP 50 - 100", | |
| 1313 | + "priceRealised": 190, | |
| 1314 | + "priceRealisedText": "GBP 190", | |
| 1315 | + "startDate": "2026-08-20T00:00Z", | |
| 1316 | + "endDate": "2026-09-02T23:00Z", | |
| 1317 | + "withdrawn": false, | |
| 1318 | + "isOver": true | |
| 1319 | + }, | |
| 1320 | + { | |
| 1321 | + "objectId": "6598309", | |
| 1322 | + "lotNumber": "69", | |
| 1323 | + "titlePrimary": "BENJAMIN SMITH", | |
| 1324 | + "titleSecondary": "Untitled #4", | |
| 1325 | + "titleTertiary": null, | |
| 1326 | + "description": "BENJAMIN SMITH Untitled #4 35mm film printed on rag paper framed: 56 cm. high x 42 cm. wide", | |
| 1327 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.69&LotNumber=69&ldp_breadcrumb=back", | |
| 1328 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0069_000(benjamin_smith_untitled_4054944).jpg?mode=max", | |
| 1329 | + "estimateLow": 100, | |
| 1330 | + "estimateHigh": 200, | |
| 1331 | + "estimateText": "GBP 100 - 200", | |
| 1332 | + "priceRealised": null, | |
| 1333 | + "priceRealisedText": null, | |
| 1334 | + "startDate": "2026-08-20T00:00Z", | |
| 1335 | + "endDate": "2026-09-02T23:00Z", | |
| 1336 | + "withdrawn": false, | |
| 1337 | + "isOver": true | |
| 1338 | + }, | |
| 1339 | + { | |
| 1340 | + "objectId": "6598310", | |
| 1341 | + "lotNumber": "70", | |
| 1342 | + "titlePrimary": "BENJAMIN SMITH", | |
| 1343 | + "titleSecondary": "Untitled #6", | |
| 1344 | + "titleTertiary": null, | |
| 1345 | + "description": "BENJAMIN SMITH Untitled #6 35mm film printed on rag paper framed: 56 cm. high x 42 cm. wide", | |
| 1346 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.70&LotNumber=70&ldp_breadcrumb=back", | |
| 1347 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0070_000(benjamin_smith_untitled_6054956).jpg?mode=max", | |
| 1348 | + "estimateLow": 50, | |
| 1349 | + "estimateHigh": 100, | |
| 1350 | + "estimateText": "GBP 50 - 100", | |
| 1351 | + "priceRealised": 64, | |
| 1352 | + "priceRealisedText": "GBP 64", | |
| 1353 | + "startDate": "2026-08-20T00:00Z", | |
| 1354 | + "endDate": "2026-09-02T23:00Z", | |
| 1355 | + "withdrawn": false, | |
| 1356 | + "isOver": true | |
| 1357 | + }, | |
| 1358 | + { | |
| 1359 | + "objectId": "6598311", | |
| 1360 | + "lotNumber": "71", | |
| 1361 | + "titlePrimary": "ALBA RODRÍGUEZ", | |
| 1362 | + "titleSecondary": "Rayo, 2026", | |
| 1363 | + "titleTertiary": null, | |
| 1364 | + "description": "ALBA RODRÍGUEZ Rayo, 2026 signed 'Rayo AlbaR'26' and numbered 1⁄10 in pencil photo etching 15 cm. high x 22.5 cm. wide", | |
| 1365 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.71&LotNumber=71&ldp_breadcrumb=back", | |
| 1366 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0071_000(alba_rodriguez_rayo_2026055007).jpg?mode=max", | |
| 1367 | + "estimateLow": 100, | |
| 1368 | + "estimateHigh": 200, | |
| 1369 | + "estimateText": "GBP 100 - 200", | |
| 1370 | + "priceRealised": null, | |
| 1371 | + "priceRealisedText": null, | |
| 1372 | + "startDate": "2026-08-20T00:00Z", | |
| 1373 | + "endDate": "2026-09-02T23:00Z", | |
| 1374 | + "withdrawn": false, | |
| 1375 | + "isOver": true | |
| 1376 | + }, | |
| 1377 | + { | |
| 1378 | + "objectId": "6598312", | |
| 1379 | + "lotNumber": "72", | |
| 1380 | + "titlePrimary": "ALBA RODRÍGUEZ", | |
| 1381 | + "titleSecondary": "Silhouettes, 2026", | |
| 1382 | + "titleTertiary": null, | |
| 1383 | + "description": "ALBA RODRÍGUEZ Silhouettes, 2026 signed 'Silhouettes AlbaR'26' and numbered edition 1⁄10 etching and aquatint 10 cm. high x 16 cm. wide", | |
| 1384 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.72&LotNumber=72&ldp_breadcrumb=back", | |
| 1385 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0072_000(alba_rodriguez_silhouettes_2026055013).jpg?mode=max", | |
| 1386 | + "estimateLow": 100, | |
| 1387 | + "estimateHigh": 200, | |
| 1388 | + "estimateText": "GBP 100 - 200", | |
| 1389 | + "priceRealised": 127, | |
| 1390 | + "priceRealisedText": "GBP 127", | |
| 1391 | + "startDate": "2026-08-20T00:00Z", | |
| 1392 | + "endDate": "2026-09-02T23:00Z", | |
| 1393 | + "withdrawn": false, | |
| 1394 | + "isOver": true | |
| 1395 | + }, | |
| 1396 | + { | |
| 1397 | + "objectId": "6598313", | |
| 1398 | + "lotNumber": "73", | |
| 1399 | + "titlePrimary": "ALBA RODRIGUEZ", | |
| 1400 | + "titleSecondary": "Tree house, 2026", | |
| 1401 | + "titleTertiary": null, | |
| 1402 | + "description": "ALBA RODRIGUEZ Tree house, 2026 signed 'Tree house AlbaR'26' and numbered edition 1⁄10 photo etching 22.5 cm. high x 15 cm. wide", | |
| 1403 | + "url": "https://www.christies.com/en/sso?ObjectID=24637.73&LotNumber=73&ldp_breadcrumb=back", | |
| 1404 | + "imageUrl": "https://www.christies.com/img/lotimages/2026/CKS/2026_CKS_24637_0073_000(alba_rodirguez_tree_house_2026055019).jpg?mode=max", | |
| 1405 | + "estimateLow": 100, | |
| 1406 | + "estimateHigh": 200, | |
| 1407 | + "estimateText": "GBP 100 - 200", | |
| 1408 | + "priceRealised": 127, | |
| 1409 | + "priceRealisedText": "GBP 127", | |
| 1410 | + "startDate": "2026-08-20T00:00Z", | |
| 1411 | + "endDate": "2026-09-02T23:00Z", | |
| 1412 | + "withdrawn": false, | |
| 1413 | + "isOver": true | |
| 1414 | + } | |
| 1415 | + ] | |
| 1416 | + }, | |
| 1417 | + "fetchedAt": "2026-09-07T06:06:26.771Z" | |
| 1418 | + }, | |
| 1419 | + "expect": { | |
| 1420 | + "minCount": 1, | |
| 1421 | + "kinds": [ | |
| 1422 | + "sale" | |
| 1423 | + ], | |
| 1424 | + "first": { | |
| 1425 | + "kind": "sale", | |
| 1426 | + "auctionHouse": "Christie's", | |
| 1427 | + "currency": "GBP" | |
| 1428 | + } | |
| 1429 | + }, | |
| 1430 | + "note": "Captured live by connectors/api/_auction-lib/smoke.ts on 2026-09-07 (44 records from this raw page).", | |
| 1431 | + "capturedAt": "2026-09-07T06:06:26.781Z" | |
| 1432 | +} | |
| \ No newline at end of file | ||
added
data/fixtures/sothebys/closed-1.json
+901 −0
@@ -0,0 +1,901 @@ | ||
| 1 | +{ | |
| 2 | + "raw": { | |
| 3 | + "url": "https://www.sothebys.com/en/buy/auction/2026/the-yang-zhendong-selection-kweichow-moutai-online", | |
| 4 | + "externalId": "43cea93e-fa73-4f1c-ad3e-6991756da236#0", | |
| 5 | + "kind": "sale", | |
| 6 | + "engine": "api", | |
| 7 | + "httpStatus": 200, | |
| 8 | + "payload": { | |
| 9 | + "kind": "auction_page", | |
| 10 | + "auction": { | |
| 11 | + "auctionId": "43cea93e-fa73-4f1c-ad3e-6991756da236", | |
| 12 | + "url": "https://www.sothebys.com/en/buy/auction/2026/the-yang-zhendong-selection-kweichow-moutai-online", | |
| 13 | + "title": "杨振东珍藏:贵州茅台网上专场 | The Yang Zhendong Selection: Kweichow Moutai Online", | |
| 14 | + "saleNumber": "CN0041", | |
| 15 | + "state": "Closed", | |
| 16 | + "type": "Timed", | |
| 17 | + "departments": [ | |
| 18 | + "Spirits" | |
| 19 | + ], | |
| 20 | + "currency": "CNY", | |
| 21 | + "location": "Shanghai Auction", | |
| 22 | + "startsAt": "2026-08-18T03:00Z", | |
| 23 | + "endsAt": "2026-08-28T03:00Z", | |
| 24 | + "closedAt": "2026-08-28T04:04:36.051959Z", | |
| 25 | + "totalLots": 45 | |
| 26 | + }, | |
| 27 | + "offset": 0, | |
| 28 | + "lots": [ | |
| 29 | + { | |
| 30 | + "lotId": "38acbdee-4f1a-4e19-825a-70a8b1a0dfc1", | |
| 31 | + "lotNumber": "1", | |
| 32 | + "title": "2009年产 “飞天牌”贵州茅台酒 Kweichow Flying Fairy Moutai 2009 (6 x 500ml)", | |
| 33 | + "creators": null, | |
| 34 | + "slug": "2009nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu", | |
| 35 | + "estimateLow": 17000, | |
| 36 | + "estimateHigh": 22000, | |
| 37 | + "isClosed": true, | |
| 38 | + "closingTime": "2026-08-28T03:01Z", | |
| 39 | + "currentBid": 17000, | |
| 40 | + "bidCurrency": "CNY", | |
| 41 | + "isSold": true, | |
| 42 | + "finalPrice": 21250, | |
| 43 | + "finalCurrency": "CNY", | |
| 44 | + "numberOfBids": 1, | |
| 45 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/2c75bb0/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F95%2F59%2F403e61dc4148a8937220c637c28f%2F032-a.jpg", | |
| 46 | + "withdrawn": false | |
| 47 | + }, | |
| 48 | + { | |
| 49 | + "lotId": "ed839d05-077b-4e24-a429-25c35311c52b", | |
| 50 | + "lotNumber": "2", | |
| 51 | + "title": "2009年产 “飞天牌”贵州茅台酒 Kweichow Flying Fairy Moutai 2009 (6 x 500ml)", | |
| 52 | + "creators": null, | |
| 53 | + "slug": "2009nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu-2", | |
| 54 | + "estimateLow": 17000, | |
| 55 | + "estimateHigh": 22000, | |
| 56 | + "isClosed": true, | |
| 57 | + "closingTime": "2026-08-28T03:02Z", | |
| 58 | + "currentBid": 17000, | |
| 59 | + "bidCurrency": "CNY", | |
| 60 | + "isSold": true, | |
| 61 | + "finalPrice": 21250, | |
| 62 | + "finalCurrency": "CNY", | |
| 63 | + "numberOfBids": 1, | |
| 64 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/994d926/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F0b%2F45%2F8b32668846a592410b00be27845e%2F033-a.jpg", | |
| 65 | + "withdrawn": false | |
| 66 | + }, | |
| 67 | + { | |
| 68 | + "lotId": "38463946-6b73-4a5b-9710-cacfcbef485c", | |
| 69 | + "lotNumber": "3", | |
| 70 | + "title": "2008年产 “飞天牌”贵州茅台酒 Kweichow Flying Fairy Moutai 2008 (6 x 500ml)", | |
| 71 | + "creators": null, | |
| 72 | + "slug": "2008nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu", | |
| 73 | + "estimateLow": 19000, | |
| 74 | + "estimateHigh": 24000, | |
| 75 | + "isClosed": true, | |
| 76 | + "closingTime": "2026-08-28T03:03Z", | |
| 77 | + "currentBid": 19000, | |
| 78 | + "bidCurrency": "CNY", | |
| 79 | + "isSold": true, | |
| 80 | + "finalPrice": 23750, | |
| 81 | + "finalCurrency": "CNY", | |
| 82 | + "numberOfBids": 1, | |
| 83 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/17ed172/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F71%2F4f%2F426046b54799a040479faccae37a%2F029-a.jpg", | |
| 84 | + "withdrawn": false | |
| 85 | + }, | |
| 86 | + { | |
| 87 | + "lotId": "be51ee7a-d6af-4237-a1f3-d3b36a62d92b", | |
| 88 | + "lotNumber": "4", | |
| 89 | + "title": "2008年产 “飞天牌”贵州茅台酒 Kweichow Flying Fairy Moutai 2008 (6 x 500ml)", | |
| 90 | + "creators": null, | |
| 91 | + "slug": "2008nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu-2", | |
| 92 | + "estimateLow": 19000, | |
| 93 | + "estimateHigh": 24000, | |
| 94 | + "isClosed": true, | |
| 95 | + "closingTime": "2026-08-28T03:04Z", | |
| 96 | + "currentBid": 19000, | |
| 97 | + "bidCurrency": "CNY", | |
| 98 | + "isSold": true, | |
| 99 | + "finalPrice": 23750, | |
| 100 | + "finalCurrency": "CNY", | |
| 101 | + "numberOfBids": 1, | |
| 102 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/95e42d4/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fdf%2F5c%2Fdc5808714722a1d4706f3c9f16af%2F030-a.jpg", | |
| 103 | + "withdrawn": false | |
| 104 | + }, | |
| 105 | + { | |
| 106 | + "lotId": "818dcfcf-b8d9-4a51-a3fe-68a29d80a3dc", | |
| 107 | + "lotNumber": "5", | |
| 108 | + "title": "2007年产 “五星牌”贵州茅台酒 Kweichow Five Star Moutai 2007 (6 x 500ml)", | |
| 109 | + "creators": null, | |
| 110 | + "slug": "2007nian-chan-wu-xing-pai-gui-zhou-mao-tai-jiu", | |
| 111 | + "estimateLow": 19000, | |
| 112 | + "estimateHigh": 24000, | |
| 113 | + "isClosed": true, | |
| 114 | + "closingTime": "2026-08-28T03:05Z", | |
| 115 | + "currentBid": 19000, | |
| 116 | + "bidCurrency": "CNY", | |
| 117 | + "isSold": true, | |
| 118 | + "finalPrice": 23750, | |
| 119 | + "finalCurrency": "CNY", | |
| 120 | + "numberOfBids": 1, | |
| 121 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/b300d0f/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F63%2Fa1%2Fcd9b6737485987b4cd5a93414bfc%2F007-a.jpg", | |
| 122 | + "withdrawn": false | |
| 123 | + }, | |
| 124 | + { | |
| 125 | + "lotId": "f6b7829b-54d9-47c0-929f-fe0a2afe8589", | |
| 126 | + "lotNumber": "6", | |
| 127 | + "title": "2007年产 “五星牌”贵州茅台酒 Kweichow Five Star Moutai 2007 (6 x 500ml)", | |
| 128 | + "creators": null, | |
| 129 | + "slug": "2007nian-chan-wu-xing-pai-gui-zhou-mao-tai-jiu-2", | |
| 130 | + "estimateLow": 19000, | |
| 131 | + "estimateHigh": 24000, | |
| 132 | + "isClosed": true, | |
| 133 | + "closingTime": "2026-08-28T03:06Z", | |
| 134 | + "currentBid": 19000, | |
| 135 | + "bidCurrency": "CNY", | |
| 136 | + "isSold": true, | |
| 137 | + "finalPrice": 23750, | |
| 138 | + "finalCurrency": "CNY", | |
| 139 | + "numberOfBids": 1, | |
| 140 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/b6b4129/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F79%2Ff8%2Fc05f27f74d2eaab097070bb93310%2F008-a.jpg", | |
| 141 | + "withdrawn": false | |
| 142 | + }, | |
| 143 | + { | |
| 144 | + "lotId": "9e899486-bda7-4c66-9b3f-9bec1f22182c", | |
| 145 | + "lotNumber": "7", | |
| 146 | + "title": "2007年产 “飞天牌”贵州茅台酒 Kweichow Flying Fairy Moutai 2007 (6 x 500ml)", | |
| 147 | + "creators": null, | |
| 148 | + "slug": "2007nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu", | |
| 149 | + "estimateLow": 19000, | |
| 150 | + "estimateHigh": 24000, | |
| 151 | + "isClosed": true, | |
| 152 | + "closingTime": "2026-08-28T03:07Z", | |
| 153 | + "currentBid": 19000, | |
| 154 | + "bidCurrency": "CNY", | |
| 155 | + "isSold": true, | |
| 156 | + "finalPrice": 23750, | |
| 157 | + "finalCurrency": "CNY", | |
| 158 | + "numberOfBids": 1, | |
| 159 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/2d2624c/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fd1%2Ffd%2Fdcfb566c45f499c098f0b7e26c1b%2F011-a.jpg", | |
| 160 | + "withdrawn": false | |
| 161 | + }, | |
| 162 | + { | |
| 163 | + "lotId": "47149e65-83e0-496e-a95f-b88b503f85b4", | |
| 164 | + "lotNumber": "8", | |
| 165 | + "title": "2007年产 “飞天牌”贵州茅台酒 Kweichow Flying Fairy Moutai 2007 (6 x 500ml)", | |
| 166 | + "creators": null, | |
| 167 | + "slug": "2007nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu-2", | |
| 168 | + "estimateLow": 19000, | |
| 169 | + "estimateHigh": 24000, | |
| 170 | + "isClosed": true, | |
| 171 | + "closingTime": "2026-08-28T03:08Z", | |
| 172 | + "currentBid": 19000, | |
| 173 | + "bidCurrency": "CNY", | |
| 174 | + "isSold": true, | |
| 175 | + "finalPrice": 23750, | |
| 176 | + "finalCurrency": "CNY", | |
| 177 | + "numberOfBids": 1, | |
| 178 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/9d03c31/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F09%2Fab%2F33ac8ccd4f90ba051f6a82f21935%2F025-a.jpg", | |
| 179 | + "withdrawn": false | |
| 180 | + }, | |
| 181 | + { | |
| 182 | + "lotId": "fdbee854-9733-45d9-ac6a-6a3795aa1d03", | |
| 183 | + "lotNumber": "9", | |
| 184 | + "title": "2006年产 “五星牌”贵州茅台酒 Kweichow Five Star Moutai 2006 (6 x 500ml)", | |
| 185 | + "creators": null, | |
| 186 | + "slug": "2006nian-chan-wu-xing-pai-gui-zhou-mao-tai-jiu", | |
| 187 | + "estimateLow": 20000, | |
| 188 | + "estimateHigh": 26000, | |
| 189 | + "isClosed": true, | |
| 190 | + "closingTime": "2026-08-28T03:09Z", | |
| 191 | + "currentBid": 20000, | |
| 192 | + "bidCurrency": "CNY", | |
| 193 | + "isSold": true, | |
| 194 | + "finalPrice": 25000, | |
| 195 | + "finalCurrency": "CNY", | |
| 196 | + "numberOfBids": 1, | |
| 197 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/2fe1026/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F11%2Faf%2Fd5f5a3e94f5abfa41b3ace0ed0d9%2F013-a.jpg", | |
| 198 | + "withdrawn": false | |
| 199 | + }, | |
| 200 | + { | |
| 201 | + "lotId": "d3d70cb7-eec1-4f75-b68d-c71482a4dcff", | |
| 202 | + "lotNumber": "10", | |
| 203 | + "title": "2006年产 “五星牌”贵州茅台酒 Kweichow Five Star Moutai 2006 (6 x 500ml)", | |
| 204 | + "creators": null, | |
| 205 | + "slug": "2006nian-chan-wu-xing-pai-gui-zhou-mao-tai-jiu-2", | |
| 206 | + "estimateLow": 20000, | |
| 207 | + "estimateHigh": 26000, | |
| 208 | + "isClosed": true, | |
| 209 | + "closingTime": "2026-08-28T03:10Z", | |
| 210 | + "currentBid": 20000, | |
| 211 | + "bidCurrency": "CNY", | |
| 212 | + "isSold": true, | |
| 213 | + "finalPrice": 25000, | |
| 214 | + "finalCurrency": "CNY", | |
| 215 | + "numberOfBids": 1, | |
| 216 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/05952bf/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F39%2F16%2F7946198c4322a1568cca7a81a911%2F014-a.jpg", | |
| 217 | + "withdrawn": false | |
| 218 | + }, | |
| 219 | + { | |
| 220 | + "lotId": "25aaeb3d-79fa-4cc6-a36a-4bb38a84df65", | |
| 221 | + "lotNumber": "11", | |
| 222 | + "title": "2004年产 “五星牌”贵州茅台酒 Kweichow Five Star Moutai 2004 (6 x 500ml)", | |
| 223 | + "creators": null, | |
| 224 | + "slug": "2004nian-chan-wu-xing-pai-gui-zhou-mao-tai-jiu", | |
| 225 | + "estimateLow": 20000, | |
| 226 | + "estimateHigh": 26000, | |
| 227 | + "isClosed": true, | |
| 228 | + "closingTime": "2026-08-28T03:11Z", | |
| 229 | + "currentBid": 20000, | |
| 230 | + "bidCurrency": "CNY", | |
| 231 | + "isSold": true, | |
| 232 | + "finalPrice": 25000, | |
| 233 | + "finalCurrency": "CNY", | |
| 234 | + "numberOfBids": 1, | |
| 235 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/487c678/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F62%2Fc8%2F9b80241649918a070b1994881a08%2F022-a.jpg", | |
| 236 | + "withdrawn": false | |
| 237 | + }, | |
| 238 | + { | |
| 239 | + "lotId": "1882d5e4-335e-4159-8a2f-d073b1478fd4", | |
| 240 | + "lotNumber": "12", | |
| 241 | + "title": "2004年产 “五星牌”贵州茅台酒 Kweichow Five Star Moutai 2004 (6 x 500ml)", | |
| 242 | + "creators": null, | |
| 243 | + "slug": "2004nian-chan-wu-xing-pai-gui-zhou-mao-tai-jiu-2", | |
| 244 | + "estimateLow": 20000, | |
| 245 | + "estimateHigh": 26000, | |
| 246 | + "isClosed": true, | |
| 247 | + "closingTime": "2026-08-28T03:12Z", | |
| 248 | + "currentBid": 20000, | |
| 249 | + "bidCurrency": "CNY", | |
| 250 | + "isSold": true, | |
| 251 | + "finalPrice": 25000, | |
| 252 | + "finalCurrency": "CNY", | |
| 253 | + "numberOfBids": 1, | |
| 254 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/1cc1d2e/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F5e%2F51%2F28898452468387ec72c3ce6a5157%2F028-a.jpg", | |
| 255 | + "withdrawn": false | |
| 256 | + }, | |
| 257 | + { | |
| 258 | + "lotId": "423e2021-f6d7-429a-8c4f-7ebb77c67f14", | |
| 259 | + "lotNumber": "13", | |
| 260 | + "title": "2004年产 “飞天牌”贵州茅台酒 Kweichow Flying Fairy Moutai 2004 (6 x 500ml)", | |
| 261 | + "creators": null, | |
| 262 | + "slug": "2004nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu", | |
| 263 | + "estimateLow": 20000, | |
| 264 | + "estimateHigh": 26000, | |
| 265 | + "isClosed": true, | |
| 266 | + "closingTime": "2026-08-28T03:14:57.173666Z", | |
| 267 | + "currentBid": 22000, | |
| 268 | + "bidCurrency": "CNY", | |
| 269 | + "isSold": true, | |
| 270 | + "finalPrice": 27500, | |
| 271 | + "finalCurrency": "CNY", | |
| 272 | + "numberOfBids": 2, | |
| 273 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/e8a4d9e/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F5f%2Fbb%2Fe93ffb79479ca3f63adc4590bffe%2F012-a.jpg", | |
| 274 | + "withdrawn": false | |
| 275 | + }, | |
| 276 | + { | |
| 277 | + "lotId": "cfceb1e2-951a-484b-97f7-50f69446869f", | |
| 278 | + "lotNumber": "14", | |
| 279 | + "title": "2004年产 “飞天牌”贵州茅台酒 Kweichow Flying Fairy Moutai 2004 (6 x 500ml)", | |
| 280 | + "creators": null, | |
| 281 | + "slug": "2004nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu-2", | |
| 282 | + "estimateLow": 20000, | |
| 283 | + "estimateHigh": 26000, | |
| 284 | + "isClosed": true, | |
| 285 | + "closingTime": "2026-08-28T03:14Z", | |
| 286 | + "currentBid": 22000, | |
| 287 | + "bidCurrency": "CNY", | |
| 288 | + "isSold": true, | |
| 289 | + "finalPrice": 27500, | |
| 290 | + "finalCurrency": "CNY", | |
| 291 | + "numberOfBids": 2, | |
| 292 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/9479dcb/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F71%2F4c%2Fabd090fc4257b157c35565a347f9%2F027-a.jpg", | |
| 293 | + "withdrawn": false | |
| 294 | + }, | |
| 295 | + { | |
| 296 | + "lotId": "a8d4cbbd-925a-4a4e-8b82-7203446a5eb9", | |
| 297 | + "lotNumber": "15", | |
| 298 | + "title": "2003年产 “五星牌”贵州茅台酒 Kweichow Five Star Moutai 2003 (6 x 500ml)", | |
| 299 | + "creators": null, | |
| 300 | + "slug": "2003nian-chan-wu-xing-pai-gui-zhou-mao-tai-jiu", | |
| 301 | + "estimateLow": 22000, | |
| 302 | + "estimateHigh": 30000, | |
| 303 | + "isClosed": true, | |
| 304 | + "closingTime": "2026-08-28T03:15Z", | |
| 305 | + "currentBid": 22000, | |
| 306 | + "bidCurrency": "CNY", | |
| 307 | + "isSold": true, | |
| 308 | + "finalPrice": 27500, | |
| 309 | + "finalCurrency": "CNY", | |
| 310 | + "numberOfBids": 1, | |
| 311 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/688dee7/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F66%2F36%2Fa0e6c9dd45dd843b1ef7bbccb428%2F015-a.jpg", | |
| 312 | + "withdrawn": false | |
| 313 | + }, | |
| 314 | + { | |
| 315 | + "lotId": "61e1e0e3-2a7b-411f-8acd-918d54e9c318", | |
| 316 | + "lotNumber": "16", | |
| 317 | + "title": "2003年产 “五星牌”贵州茅台酒 Kweichow Five Star Moutai 2003 (6 x 500ml)", | |
| 318 | + "creators": null, | |
| 319 | + "slug": "2003nian-chan-wu-xing-pai-gui-zhou-mao-tai-jiu-2", | |
| 320 | + "estimateLow": 22000, | |
| 321 | + "estimateHigh": 30000, | |
| 322 | + "isClosed": true, | |
| 323 | + "closingTime": "2026-08-28T03:16Z", | |
| 324 | + "currentBid": 22000, | |
| 325 | + "bidCurrency": "CNY", | |
| 326 | + "isSold": true, | |
| 327 | + "finalPrice": 27500, | |
| 328 | + "finalCurrency": "CNY", | |
| 329 | + "numberOfBids": 1, | |
| 330 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/d1874bc/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F03%2Fbb%2Faaa11b56470fbf081d3f30069032%2F016-a.jpg", | |
| 331 | + "withdrawn": false | |
| 332 | + }, | |
| 333 | + { | |
| 334 | + "lotId": "c0239655-9ccc-4173-a42e-d514984345a0", | |
| 335 | + "lotNumber": "17", | |
| 336 | + "title": "2003年产 “飞天牌”贵州茅台酒 Kweichow Flying Fairy Moutai 2003 (6 x 500ml)", | |
| 337 | + "creators": null, | |
| 338 | + "slug": "2003nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu", | |
| 339 | + "estimateLow": 22000, | |
| 340 | + "estimateHigh": 30000, | |
| 341 | + "isClosed": true, | |
| 342 | + "closingTime": "2026-08-28T03:17Z", | |
| 343 | + "currentBid": 22000, | |
| 344 | + "bidCurrency": "CNY", | |
| 345 | + "isSold": true, | |
| 346 | + "finalPrice": 27500, | |
| 347 | + "finalCurrency": "CNY", | |
| 348 | + "numberOfBids": 1, | |
| 349 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/e9fa076/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F40%2F95%2F80d62649485cb8e1b427d93b5ea9%2F024-a.jpg", | |
| 350 | + "withdrawn": false | |
| 351 | + }, | |
| 352 | + { | |
| 353 | + "lotId": "461f3b9c-bd4b-4dac-a4a0-dae79fe5ae5c", | |
| 354 | + "lotNumber": "18", | |
| 355 | + "title": "2003年产 “飞天牌”贵州茅台酒 Kweichow Flying Fairy Moutai 2003 (6 x 500ml)", | |
| 356 | + "creators": null, | |
| 357 | + "slug": "2003nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu-2", | |
| 358 | + "estimateLow": 22000, | |
| 359 | + "estimateHigh": 30000, | |
| 360 | + "isClosed": true, | |
| 361 | + "closingTime": "2026-08-28T03:18Z", | |
| 362 | + "currentBid": 22000, | |
| 363 | + "bidCurrency": "CNY", | |
| 364 | + "isSold": true, | |
| 365 | + "finalPrice": 27500, | |
| 366 | + "finalCurrency": "CNY", | |
| 367 | + "numberOfBids": 1, | |
| 368 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/9663ded/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fd6%2Fc8%2Fa3901b724616ac86f6817889b03a%2F026-a.jpg", | |
| 369 | + "withdrawn": false | |
| 370 | + }, | |
| 371 | + { | |
| 372 | + "lotId": "eee31fed-1b85-4085-bdeb-341847f5edb1", | |
| 373 | + "lotNumber": "19", | |
| 374 | + "title": "2002年产 “五星牌”贵州茅台酒 Kweichow Five Star Moutai 2002 (6 x 500ml)", | |
| 375 | + "creators": null, | |
| 376 | + "slug": "2002nian-chan-wu-xing-pai-gui-zhou-mao-tai-jiu", | |
| 377 | + "estimateLow": 24000, | |
| 378 | + "estimateHigh": 32000, | |
| 379 | + "isClosed": true, | |
| 380 | + "closingTime": "2026-08-28T03:19Z", | |
| 381 | + "currentBid": 24000, | |
| 382 | + "bidCurrency": "CNY", | |
| 383 | + "isSold": true, | |
| 384 | + "finalPrice": 30000, | |
| 385 | + "finalCurrency": "CNY", | |
| 386 | + "numberOfBids": 1, | |
| 387 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/b3d8b5d/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fc5%2F55%2Fd2e7368444e0b771fcf6b3b7a216%2F009-a.jpg", | |
| 388 | + "withdrawn": false | |
| 389 | + }, | |
| 390 | + { | |
| 391 | + "lotId": "26bc6348-4085-488b-914b-832ed154b6f3", | |
| 392 | + "lotNumber": "20", | |
| 393 | + "title": "2002年产 “五星牌”贵州茅台酒 Kweichow Five Star Moutai 2002 (6 x 500ml)", | |
| 394 | + "creators": null, | |
| 395 | + "slug": "2002nian-chan-wu-xing-pai-gui-zhou-mao-tai-jiu-2", | |
| 396 | + "estimateLow": 24000, | |
| 397 | + "estimateHigh": 32000, | |
| 398 | + "isClosed": true, | |
| 399 | + "closingTime": "2026-08-28T03:20Z", | |
| 400 | + "currentBid": 24000, | |
| 401 | + "bidCurrency": "CNY", | |
| 402 | + "isSold": true, | |
| 403 | + "finalPrice": 30000, | |
| 404 | + "finalCurrency": "CNY", | |
| 405 | + "numberOfBids": 1, | |
| 406 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/1b1076a/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F35%2F6d%2F2409b7764ba5800be392241e48ab%2F010-a.jpg", | |
| 407 | + "withdrawn": false | |
| 408 | + }, | |
| 409 | + { | |
| 410 | + "lotId": "ed4de8e9-11f1-4721-9c53-5309930ac924", | |
| 411 | + "lotNumber": "21", | |
| 412 | + "title": "2002年产 “飞天牌”贵州茅台酒 Kweichow Flying Fairy Moutai 2002 (6 x 500ml)", | |
| 413 | + "creators": null, | |
| 414 | + "slug": "2002nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu", | |
| 415 | + "estimateLow": 24000, | |
| 416 | + "estimateHigh": 32000, | |
| 417 | + "isClosed": true, | |
| 418 | + "closingTime": "2026-08-28T03:21Z", | |
| 419 | + "currentBid": 24000, | |
| 420 | + "bidCurrency": "CNY", | |
| 421 | + "isSold": true, | |
| 422 | + "finalPrice": 30000, | |
| 423 | + "finalCurrency": "CNY", | |
| 424 | + "numberOfBids": 1, | |
| 425 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/e4fe475/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F13%2Fd5%2F869681d34781bc67424c58b35b00%2F020-a.jpg", | |
| 426 | + "withdrawn": false | |
| 427 | + }, | |
| 428 | + { | |
| 429 | + "lotId": "c9b88183-ff36-4d70-afc7-6393dd1d238c", | |
| 430 | + "lotNumber": "22", | |
| 431 | + "title": "2002年产 “飞天牌”贵州茅台酒 Kweichow Flying Fairy Moutai 2002 (6 x 500ml)", | |
| 432 | + "creators": null, | |
| 433 | + "slug": "2002nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu-2", | |
| 434 | + "estimateLow": 24000, | |
| 435 | + "estimateHigh": 32000, | |
| 436 | + "isClosed": true, | |
| 437 | + "closingTime": "2026-08-28T03:22Z", | |
| 438 | + "currentBid": 24000, | |
| 439 | + "bidCurrency": "CNY", | |
| 440 | + "isSold": true, | |
| 441 | + "finalPrice": 30000, | |
| 442 | + "finalCurrency": "CNY", | |
| 443 | + "numberOfBids": 1, | |
| 444 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/3312497/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fc2%2F10%2Fea1df9f14c8b8690f99af80bc8a8%2F021-a.jpg", | |
| 445 | + "withdrawn": false | |
| 446 | + }, | |
| 447 | + { | |
| 448 | + "lotId": "5ac4dc52-f406-45d5-b760-e0b6bcf1f290", | |
| 449 | + "lotNumber": "23", | |
| 450 | + "title": "2001年产 “五星牌”贵州茅台酒 Kweichow Five Star Moutai 2001 (6 x 500ml)", | |
| 451 | + "creators": null, | |
| 452 | + "slug": "2001nian-chan-wu-xing-pai-gui-zhou-mao-tai-jiu", | |
| 453 | + "estimateLow": 24000, | |
| 454 | + "estimateHigh": 35000, | |
| 455 | + "isClosed": true, | |
| 456 | + "closingTime": "2026-08-28T03:23Z", | |
| 457 | + "currentBid": 24000, | |
| 458 | + "bidCurrency": "CNY", | |
| 459 | + "isSold": true, | |
| 460 | + "finalPrice": 30000, | |
| 461 | + "finalCurrency": "CNY", | |
| 462 | + "numberOfBids": 1, | |
| 463 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/5f2cba9/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F06%2Ff8%2Fc96367e149b7b632f058108767ab%2F005-a.jpg", | |
| 464 | + "withdrawn": false | |
| 465 | + }, | |
| 466 | + { | |
| 467 | + "lotId": "9e88d951-3a6e-43e9-b8a2-0e63a8ed7dee", | |
| 468 | + "lotNumber": "24", | |
| 469 | + "title": "2001年产 “五星牌”贵州茅台酒 Kweichow Five Star Moutai 2001 (6 x 500ml)", | |
| 470 | + "creators": null, | |
| 471 | + "slug": "2001nian-chan-wu-xing-pai-gui-zhou-mao-tai-jiu-2", | |
| 472 | + "estimateLow": 24000, | |
| 473 | + "estimateHigh": 35000, | |
| 474 | + "isClosed": true, | |
| 475 | + "closingTime": "2026-08-28T03:24Z", | |
| 476 | + "currentBid": 24000, | |
| 477 | + "bidCurrency": "CNY", | |
| 478 | + "isSold": true, | |
| 479 | + "finalPrice": 30000, | |
| 480 | + "finalCurrency": "CNY", | |
| 481 | + "numberOfBids": 1, | |
| 482 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/b559bfa/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fad%2F79%2Fbc00b0a246af91fc810dbf4c823a%2F023-a.jpg", | |
| 483 | + "withdrawn": false | |
| 484 | + }, | |
| 485 | + { | |
| 486 | + "lotId": "ba3fb029-998a-43d2-b4b4-ababb35001f9", | |
| 487 | + "lotNumber": "25", | |
| 488 | + "title": "2001年产 “飞天牌”贵州茅台酒 Kweichow Flying Fairy Moutai 2001 (6 x 500ml)", | |
| 489 | + "creators": null, | |
| 490 | + "slug": "2001nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu", | |
| 491 | + "estimateLow": 24000, | |
| 492 | + "estimateHigh": 35000, | |
| 493 | + "isClosed": true, | |
| 494 | + "closingTime": "2026-08-28T03:25Z", | |
| 495 | + "currentBid": 24000, | |
| 496 | + "bidCurrency": "CNY", | |
| 497 | + "isSold": true, | |
| 498 | + "finalPrice": 30000, | |
| 499 | + "finalCurrency": "CNY", | |
| 500 | + "numberOfBids": 1, | |
| 501 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/31cd061/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fb7%2F68%2F82d4008b4ae79f2490f555e1f0cc%2F017-a.jpg", | |
| 502 | + "withdrawn": false | |
| 503 | + }, | |
| 504 | + { | |
| 505 | + "lotId": "cba61b07-b388-49ca-bd8f-5a7d2db97c6b", | |
| 506 | + "lotNumber": "26", | |
| 507 | + "title": "2001年产 “飞天牌”贵州茅台酒 Kweichow Flying Fairy Moutai 2001 (6 x 500ml)", | |
| 508 | + "creators": null, | |
| 509 | + "slug": "2001nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu-2", | |
| 510 | + "estimateLow": 24000, | |
| 511 | + "estimateHigh": 35000, | |
| 512 | + "isClosed": true, | |
| 513 | + "closingTime": "2026-08-28T03:26Z", | |
| 514 | + "currentBid": 24000, | |
| 515 | + "bidCurrency": "CNY", | |
| 516 | + "isSold": true, | |
| 517 | + "finalPrice": 30000, | |
| 518 | + "finalCurrency": "CNY", | |
| 519 | + "numberOfBids": 1, | |
| 520 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/1fdc890/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fa2%2F79%2F546d2cba488587afa0ace93978cc%2F018-a.jpg", | |
| 521 | + "withdrawn": false | |
| 522 | + }, | |
| 523 | + { | |
| 524 | + "lotId": "43bff431-c2f7-4e83-9390-fc5fcd6f45b0", | |
| 525 | + "lotNumber": "27", | |
| 526 | + "title": "2000年产 “五星牌”贵州茅台酒 (太阳标) Kweichow Five Star Moutai 2000 (White sticker) (6 x 500ml)", | |
| 527 | + "creators": null, | |
| 528 | + "slug": "2000nian-chan-wu-xing-pai-gui-zhou-mao-tai-jiu-tai", | |
| 529 | + "estimateLow": 28000, | |
| 530 | + "estimateHigh": 38000, | |
| 531 | + "isClosed": true, | |
| 532 | + "closingTime": "2026-08-28T03:27Z", | |
| 533 | + "currentBid": 28000, | |
| 534 | + "bidCurrency": "CNY", | |
| 535 | + "isSold": true, | |
| 536 | + "finalPrice": 35000, | |
| 537 | + "finalCurrency": "CNY", | |
| 538 | + "numberOfBids": 1, | |
| 539 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/8acd881/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F2c%2Fda%2F91c4d2264263a18d5f6a4abe4e4b%2F003-a.jpg", | |
| 540 | + "withdrawn": false | |
| 541 | + }, | |
| 542 | + { | |
| 543 | + "lotId": "c1f62e53-7a65-479b-b5a3-7c8501f02f38", | |
| 544 | + "lotNumber": "28", | |
| 545 | + "title": "2000年产 “五星牌”贵州茅台酒 (太阳标) Kweichow Five Star Moutai 2000 (White sticker) (6 x 500ml)", | |
| 546 | + "creators": null, | |
| 547 | + "slug": "2000nian-chan-wu-xing-pai-gui-zhou-mao-tai-jiu-tai-2", | |
| 548 | + "estimateLow": 28000, | |
| 549 | + "estimateHigh": 38000, | |
| 550 | + "isClosed": true, | |
| 551 | + "closingTime": "2026-08-28T03:28Z", | |
| 552 | + "currentBid": 28000, | |
| 553 | + "bidCurrency": "CNY", | |
| 554 | + "isSold": true, | |
| 555 | + "finalPrice": 35000, | |
| 556 | + "finalCurrency": "CNY", | |
| 557 | + "numberOfBids": 1, | |
| 558 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/ab41aae/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F33%2F0d%2F24b346844fd295e9591452dbd939%2F037-a.jpg", | |
| 559 | + "withdrawn": false | |
| 560 | + }, | |
| 561 | + { | |
| 562 | + "lotId": "0954435f-be25-435b-aad4-f8de96d81d05", | |
| 563 | + "lotNumber": "29", | |
| 564 | + "title": "2000年产 “飞天牌”贵州茅台酒 (太阳标) Kweichow Flying Fairy Moutai 2000 (White sticker) (6 x 500ml)", | |
| 565 | + "creators": null, | |
| 566 | + "slug": "2000nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu", | |
| 567 | + "estimateLow": 28000, | |
| 568 | + "estimateHigh": 38000, | |
| 569 | + "isClosed": true, | |
| 570 | + "closingTime": "2026-08-28T03:29Z", | |
| 571 | + "currentBid": 28000, | |
| 572 | + "bidCurrency": "CNY", | |
| 573 | + "isSold": true, | |
| 574 | + "finalPrice": 35000, | |
| 575 | + "finalCurrency": "CNY", | |
| 576 | + "numberOfBids": 1, | |
| 577 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/5157b9a/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F18%2Fc4%2F9c5f6e5a4e0ab19baee44778a90a%2F004-a.jpg", | |
| 578 | + "withdrawn": false | |
| 579 | + }, | |
| 580 | + { | |
| 581 | + "lotId": "f32c44b3-c778-479a-8f52-c04ec867dc14", | |
| 582 | + "lotNumber": "30", | |
| 583 | + "title": "2000年产 “飞天牌”贵州茅台酒 (太阳标) Kweichow Flying Fairy Moutai 2000 (White sticker) (6 x 500ml)", | |
| 584 | + "creators": null, | |
| 585 | + "slug": "2000nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu-2", | |
| 586 | + "estimateLow": 28000, | |
| 587 | + "estimateHigh": 38000, | |
| 588 | + "isClosed": true, | |
| 589 | + "closingTime": "2026-08-28T03:30Z", | |
| 590 | + "currentBid": 28000, | |
| 591 | + "bidCurrency": "CNY", | |
| 592 | + "isSold": true, | |
| 593 | + "finalPrice": 35000, | |
| 594 | + "finalCurrency": "CNY", | |
| 595 | + "numberOfBids": 1, | |
| 596 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/8c4dab1/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F6d%2Fac%2F5c2cdc484346813a467cf2644136%2F042-a.jpg", | |
| 597 | + "withdrawn": false | |
| 598 | + }, | |
| 599 | + { | |
| 600 | + "lotId": "0bb90acf-44e8-43ee-b5db-2f9e2f97fc2c", | |
| 601 | + "lotNumber": "31", | |
| 602 | + "title": "2000年产 “五星牌”贵州茅台酒 (蓝标) Kweichow Five Star Moutai 2000 (Blue sticker) (6 x 500ml)", | |
| 603 | + "creators": null, | |
| 604 | + "slug": "2000nian-chan-wu-xing-pai-gui-zhou-mao-tai-jiu-lan", | |
| 605 | + "estimateLow": 28000, | |
| 606 | + "estimateHigh": 38000, | |
| 607 | + "isClosed": true, | |
| 608 | + "closingTime": "2026-08-28T03:31Z", | |
| 609 | + "currentBid": 28000, | |
| 610 | + "bidCurrency": "CNY", | |
| 611 | + "isSold": true, | |
| 612 | + "finalPrice": 35000, | |
| 613 | + "finalCurrency": "CNY", | |
| 614 | + "numberOfBids": 1, | |
| 615 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/335b202/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F81%2F18%2F2c9d68564a3c923c899be61e9df4%2F035-a.jpg", | |
| 616 | + "withdrawn": false | |
| 617 | + }, | |
| 618 | + { | |
| 619 | + "lotId": "b83c1afa-5236-486a-8893-47368254d6f8", | |
| 620 | + "lotNumber": "32", | |
| 621 | + "title": "2000年产 “五星牌”贵州茅台酒 (蓝标) Kweichow Five Star Moutai 2000 (Blue sticker) (6 x 500ml)", | |
| 622 | + "creators": null, | |
| 623 | + "slug": "2000nian-chan-wu-xing-pai-gui-zhou-mao-tai-jiu-lan-2", | |
| 624 | + "estimateLow": 28000, | |
| 625 | + "estimateHigh": 38000, | |
| 626 | + "isClosed": true, | |
| 627 | + "closingTime": "2026-08-28T03:32Z", | |
| 628 | + "currentBid": 32000, | |
| 629 | + "bidCurrency": "CNY", | |
| 630 | + "isSold": true, | |
| 631 | + "finalPrice": 40000, | |
| 632 | + "finalCurrency": "CNY", | |
| 633 | + "numberOfBids": 3, | |
| 634 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/028b6f4/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F8f%2F9b%2F0091e03f4209be648545ea055037%2F036-a.jpg", | |
| 635 | + "withdrawn": false | |
| 636 | + }, | |
| 637 | + { | |
| 638 | + "lotId": "b857c260-6e82-4525-8525-14d4c18dad24", | |
| 639 | + "lotNumber": "33", | |
| 640 | + "title": "2000年产 “飞天牌”贵州茅台酒 (蓝标) Kweichow Flying Fairy Moutai 2000 (Blue sticker) (6 x 500ml)", | |
| 641 | + "creators": null, | |
| 642 | + "slug": "2000nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu-3", | |
| 643 | + "estimateLow": 28000, | |
| 644 | + "estimateHigh": 38000, | |
| 645 | + "isClosed": true, | |
| 646 | + "closingTime": "2026-08-28T03:33Z", | |
| 647 | + "currentBid": 30000, | |
| 648 | + "bidCurrency": "CNY", | |
| 649 | + "isSold": true, | |
| 650 | + "finalPrice": 37500, | |
| 651 | + "finalCurrency": "CNY", | |
| 652 | + "numberOfBids": 2, | |
| 653 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/86968e7/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Ffa%2Fe4%2Fccd4fdee46a180defa48050af80d%2F002-a.jpg", | |
| 654 | + "withdrawn": false | |
| 655 | + }, | |
| 656 | + { | |
| 657 | + "lotId": "3cd7b277-244a-44be-a6a3-612f80187305", | |
| 658 | + "lotNumber": "34", | |
| 659 | + "title": " 2000年产 “飞天牌”贵州茅台酒 (蓝标) Kweichow Flying Fairy Moutai 2000 (Blue sticker) (6 x 500ml)", | |
| 660 | + "creators": null, | |
| 661 | + "slug": "2000nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu-4", | |
| 662 | + "estimateLow": 28000, | |
| 663 | + "estimateHigh": 38000, | |
| 664 | + "isClosed": true, | |
| 665 | + "closingTime": "2026-08-28T03:34Z", | |
| 666 | + "currentBid": 28000, | |
| 667 | + "bidCurrency": "CNY", | |
| 668 | + "isSold": true, | |
| 669 | + "finalPrice": 35000, | |
| 670 | + "finalCurrency": "CNY", | |
| 671 | + "numberOfBids": 1, | |
| 672 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/9ebf750/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F91%2F2b%2F96ec2ebe4b67a809b629c7553eeb%2F006-a.jpg", | |
| 673 | + "withdrawn": false | |
| 674 | + }, | |
| 675 | + { | |
| 676 | + "lotId": "f15473a1-c8a1-4e0d-839a-d63550a653ab", | |
| 677 | + "lotNumber": "35", | |
| 678 | + "title": "1994年产 “飞天牌”贵州茅台酒 (铁盖) Kweichow Flying Fairy Moutai 1994 (Iron Capsule) (6 x 375ml)", | |
| 679 | + "creators": null, | |
| 680 | + "slug": "1994nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu", | |
| 681 | + "estimateLow": 40000, | |
| 682 | + "estimateHigh": 55000, | |
| 683 | + "isClosed": true, | |
| 684 | + "closingTime": "2026-08-28T03:35Z", | |
| 685 | + "currentBid": 40000, | |
| 686 | + "bidCurrency": "CNY", | |
| 687 | + "isSold": true, | |
| 688 | + "finalPrice": 50000, | |
| 689 | + "finalCurrency": "CNY", | |
| 690 | + "numberOfBids": 1, | |
| 691 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/ceb6399/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F4f%2F21%2F395a3752442d9916bc9715184c59%2F038-a.jpg", | |
| 692 | + "withdrawn": false | |
| 693 | + }, | |
| 694 | + { | |
| 695 | + "lotId": "5e6e55ee-1e5d-415d-b46a-848c92505b52", | |
| 696 | + "lotNumber": "36", | |
| 697 | + "title": "1993年产 “飞天牌”贵州茅台酒 (铁盖) Kweichow Flying Fairy Moutai 1993 (Iron Capsule) (6 x 375ml)", | |
| 698 | + "creators": null, | |
| 699 | + "slug": "1993nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu", | |
| 700 | + "estimateLow": 40000, | |
| 701 | + "estimateHigh": 55000, | |
| 702 | + "isClosed": true, | |
| 703 | + "closingTime": "2026-08-28T03:36Z", | |
| 704 | + "currentBid": 70000, | |
| 705 | + "bidCurrency": "CNY", | |
| 706 | + "isSold": true, | |
| 707 | + "finalPrice": 87500, | |
| 708 | + "finalCurrency": "CNY", | |
| 709 | + "numberOfBids": 9, | |
| 710 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/4e3f39d/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fbe%2Fa3%2F111f9f964e6ca62a45f8f4047f8f%2F039-a.jpg", | |
| 711 | + "withdrawn": false | |
| 712 | + }, | |
| 713 | + { | |
| 714 | + "lotId": "1c747026-6524-42cc-b025-5baa03a0ab9a", | |
| 715 | + "lotNumber": "37", | |
| 716 | + "title": "1992年产 “飞天牌”贵州茅台酒 (铁盖) Kweichow Flying Fairy Moutai 1992 (Iron Capsule) (6 x 200ml)", | |
| 717 | + "creators": null, | |
| 718 | + "slug": "1992nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu", | |
| 719 | + "estimateLow": 22000, | |
| 720 | + "estimateHigh": 28000, | |
| 721 | + "isClosed": true, | |
| 722 | + "closingTime": "2026-08-28T03:37Z", | |
| 723 | + "currentBid": 28000, | |
| 724 | + "bidCurrency": "CNY", | |
| 725 | + "isSold": true, | |
| 726 | + "finalPrice": 35000, | |
| 727 | + "finalCurrency": "CNY", | |
| 728 | + "numberOfBids": 4, | |
| 729 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/a5f7a09/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F2e%2F70%2F60d808e44737aaadf1f29d46af9b%2F034-a.jpg", | |
| 730 | + "withdrawn": false | |
| 731 | + }, | |
| 732 | + { | |
| 733 | + "lotId": "3bb3f155-fa26-4159-9ebf-e240537a7139", | |
| 734 | + "lotNumber": "38", | |
| 735 | + "title": "1992年产 “飞天牌”贵州茅台酒 (铁盖) Kweichow Flying Fairy Moutai 1992 (Iron Capsule) (6 x 375ml)", | |
| 736 | + "creators": null, | |
| 737 | + "slug": "1992nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu-2", | |
| 738 | + "estimateLow": 40000, | |
| 739 | + "estimateHigh": 55000, | |
| 740 | + "isClosed": true, | |
| 741 | + "closingTime": "2026-08-28T03:38Z", | |
| 742 | + "currentBid": 40000, | |
| 743 | + "bidCurrency": "CNY", | |
| 744 | + "isSold": true, | |
| 745 | + "finalPrice": 50000, | |
| 746 | + "finalCurrency": "CNY", | |
| 747 | + "numberOfBids": 1, | |
| 748 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/e28bc84/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F81%2F18%2F2e44c0a346c784d530ee9d06ede7%2F040-a.jpg", | |
| 749 | + "withdrawn": false | |
| 750 | + }, | |
| 751 | + { | |
| 752 | + "lotId": "f6d13ac8-b6c6-4d81-be52-c892fb9a4dd9", | |
| 753 | + "lotNumber": "39", | |
| 754 | + "title": "1991年产 “飞天牌”贵州茅台酒 (铁盖) Kweichow Flying Fairy Moutai 1991 (Iron Capsule) (6 x 200ml)", | |
| 755 | + "creators": null, | |
| 756 | + "slug": "1991nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu", | |
| 757 | + "estimateLow": 22000, | |
| 758 | + "estimateHigh": 28000, | |
| 759 | + "isClosed": true, | |
| 760 | + "closingTime": "2026-08-28T03:39Z", | |
| 761 | + "currentBid": 24000, | |
| 762 | + "bidCurrency": "CNY", | |
| 763 | + "isSold": true, | |
| 764 | + "finalPrice": 30000, | |
| 765 | + "finalCurrency": "CNY", | |
| 766 | + "numberOfBids": 2, | |
| 767 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/e4ab47d/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F3b%2Fc2%2Fef6c7105427a996bc0cc9b36ef69%2F001-a.jpg", | |
| 768 | + "withdrawn": false | |
| 769 | + }, | |
| 770 | + { | |
| 771 | + "lotId": "ba1855b8-0a84-4219-bd9f-e181cc415c99", | |
| 772 | + "lotNumber": "40", | |
| 773 | + "title": "1991年产 “飞天牌”贵州茅台酒 (铁盖) Kweichow Flying Fairy Moutai 1991 (Iron Capsule) (6 x 375ml)", | |
| 774 | + "creators": null, | |
| 775 | + "slug": "1991nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu-2", | |
| 776 | + "estimateLow": 40000, | |
| 777 | + "estimateHigh": 55000, | |
| 778 | + "isClosed": true, | |
| 779 | + "closingTime": "2026-08-28T03:40Z", | |
| 780 | + "currentBid": 42000, | |
| 781 | + "bidCurrency": "CNY", | |
| 782 | + "isSold": true, | |
| 783 | + "finalPrice": 52500, | |
| 784 | + "finalCurrency": "CNY", | |
| 785 | + "numberOfBids": 2, | |
| 786 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/3d95b57/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fc3%2F1b%2Fd662b03d469eb6283009728a34fb%2F041-a.jpg", | |
| 787 | + "withdrawn": false | |
| 788 | + }, | |
| 789 | + { | |
| 790 | + "lotId": "8f71e958-c98b-4c96-b20d-b4fd872ba082", | |
| 791 | + "lotNumber": "41", | |
| 792 | + "title": "1985年产 “飞天牌”贵州茅台酒 Kweichow Flying Fairy Moutai 1985 (3 x 500ml)", | |
| 793 | + "creators": null, | |
| 794 | + "slug": "1985nian-chan-fei-tian-pai-gui-zhou-mao-tai-jiu", | |
| 795 | + "estimateLow": 50000, | |
| 796 | + "estimateHigh": 70000, | |
| 797 | + "isClosed": true, | |
| 798 | + "closingTime": "2026-08-28T03:41Z", | |
| 799 | + "currentBid": 50000, | |
| 800 | + "bidCurrency": "CNY", | |
| 801 | + "isSold": true, | |
| 802 | + "finalPrice": 62500, | |
| 803 | + "finalCurrency": "CNY", | |
| 804 | + "numberOfBids": 1, | |
| 805 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/5b2d8a4/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F5c%2F1c%2F9a0cde90476d889b8d7b629b82cf%2F031-a.jpg", | |
| 806 | + "withdrawn": false | |
| 807 | + }, | |
| 808 | + { | |
| 809 | + "lotId": "667504c2-773b-4caf-b939-a9eacf631e4d", | |
| 810 | + "lotNumber": "42", | |
| 811 | + "title": "1983-1985年产 “大飞天”贵州茅台酒 Kweichow Flying Fairy Moutai circa 1983-1985 (3 x 540ml)", | |
| 812 | + "creators": null, | |
| 813 | + "slug": "1983-1985nian-chan-da-fei-tian-gui-zhou-mao-tai", | |
| 814 | + "estimateLow": 50000, | |
| 815 | + "estimateHigh": 70000, | |
| 816 | + "isClosed": true, | |
| 817 | + "closingTime": "2026-08-28T03:42Z", | |
| 818 | + "currentBid": 50000, | |
| 819 | + "bidCurrency": "CNY", | |
| 820 | + "isSold": true, | |
| 821 | + "finalPrice": 62500, | |
| 822 | + "finalCurrency": "CNY", | |
| 823 | + "numberOfBids": 1, | |
| 824 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/f7514a9/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F07%2F4a%2Ff37c0e324b26b5501ec5fe9163db%2F019-a.jpg", | |
| 825 | + "withdrawn": false | |
| 826 | + }, | |
| 827 | + { | |
| 828 | + "lotId": "21d3b025-978d-4537-a760-180b0ac0cf04", | |
| 829 | + "lotNumber": "43", | |
| 830 | + "title": "2000年产 “飞天牌”珍品贵州茅台酒 (太阳标) Kweichow Flying Fairy Precious Moutai 2000 (White sticker) (12 x 500ml)", | |
| 831 | + "creators": null, | |
| 832 | + "slug": "2000nian-chan-fei-tian-pai-zhen-pin-gui-zhou-mao", | |
| 833 | + "estimateLow": 70000, | |
| 834 | + "estimateHigh": 95000, | |
| 835 | + "isClosed": true, | |
| 836 | + "closingTime": "2026-08-28T03:43Z", | |
| 837 | + "currentBid": 75000, | |
| 838 | + "bidCurrency": "CNY", | |
| 839 | + "isSold": true, | |
| 840 | + "finalPrice": 93750, | |
| 841 | + "finalCurrency": "CNY", | |
| 842 | + "numberOfBids": 2, | |
| 843 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/4a51929/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F4a%2F70%2Fc2585a884cdb9c678c32643bc89d%2F043-a.jpg", | |
| 844 | + "withdrawn": false | |
| 845 | + }, | |
| 846 | + { | |
| 847 | + "lotId": "b30b447c-f872-4a58-bf56-ad9959d37fbf", | |
| 848 | + "lotNumber": "44", | |
| 849 | + "title": "1997年产 “飞天牌”珍品贵州茅台酒 Kweichow Flying Fairy Precious Moutai 1997 (12 x 500ml)", | |
| 850 | + "creators": null, | |
| 851 | + "slug": "1997nian-chan-fei-tian-pai-zhen-pin-gui-zhou-mao", | |
| 852 | + "estimateLow": 85000, | |
| 853 | + "estimateHigh": 120000, | |
| 854 | + "isClosed": true, | |
| 855 | + "closingTime": "2026-08-28T03:45:58.039480Z", | |
| 856 | + "currentBid": 110000, | |
| 857 | + "bidCurrency": "CNY", | |
| 858 | + "isSold": true, | |
| 859 | + "finalPrice": 137500, | |
| 860 | + "finalCurrency": "CNY", | |
| 861 | + "numberOfBids": 6, | |
| 862 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/709363e/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Ff1%2F19%2F693696504232843e0efa6dade421%2F045-a.jpg", | |
| 863 | + "withdrawn": false | |
| 864 | + }, | |
| 865 | + { | |
| 866 | + "lotId": "2c2a1eac-6bd9-4fb5-ad67-ef183992a725", | |
| 867 | + "lotNumber": "45", | |
| 868 | + "title": "1998年产 “飞天牌”珍品贵州茅台酒 Kweichow Flying Fairy Precious Moutai 1998 (12 x 500ml)", | |
| 869 | + "creators": null, | |
| 870 | + "slug": "1998nian-chan-fei-tian-pai-zhen-pin-gui-zhou-mao", | |
| 871 | + "estimateLow": 80000, | |
| 872 | + "estimateHigh": 120000, | |
| 873 | + "isClosed": true, | |
| 874 | + "closingTime": "2026-08-28T03:46:08.398471Z", | |
| 875 | + "currentBid": 90000, | |
| 876 | + "bidCurrency": "CNY", | |
| 877 | + "isSold": true, | |
| 878 | + "finalPrice": 112500, | |
| 879 | + "finalCurrency": "CNY", | |
| 880 | + "numberOfBids": 3, | |
| 881 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/1812306/2147483647/strip/true/crop/2000x1778+0+0/resize/4096x3641!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fcb%2F98%2F7771d8c54e4bbef139f925a8c487%2F044-a.jpg", | |
| 882 | + "withdrawn": false | |
| 883 | + } | |
| 884 | + ] | |
| 885 | + }, | |
| 886 | + "fetchedAt": "2026-09-07T06:06:54.265Z" | |
| 887 | + }, | |
| 888 | + "expect": { | |
| 889 | + "minCount": 1, | |
| 890 | + "kinds": [ | |
| 891 | + "sale" | |
| 892 | + ], | |
| 893 | + "first": { | |
| 894 | + "kind": "sale", | |
| 895 | + "auctionHouse": "Sotheby's", | |
| 896 | + "currency": "CNY" | |
| 897 | + } | |
| 898 | + }, | |
| 899 | + "note": "Captured live by connectors/api/_auction-lib/smoke.ts on 2026-09-07 (45 records from this raw page).", | |
| 900 | + "capturedAt": "2026-09-07T06:06:54.271Z" | |
| 901 | +} | |
| \ No newline at end of file | ||
added
data/fixtures/sothebys/live-1.json
+958 −0
@@ -0,0 +1,958 @@ | ||
| 1 | +{ | |
| 2 | + "raw": { | |
| 3 | + "url": "https://www.sothebys.com/en/buy/auction/2026/important-watches-4-2", | |
| 4 | + "externalId": "2ce220d0-145a-4e9c-9370-4ee277bf195c#0", | |
| 5 | + "kind": "auction_lot", | |
| 6 | + "engine": "api", | |
| 7 | + "httpStatus": 200, | |
| 8 | + "payload": { | |
| 9 | + "kind": "auction_page", | |
| 10 | + "auction": { | |
| 11 | + "auctionId": "2ce220d0-145a-4e9c-9370-4ee277bf195c", | |
| 12 | + "url": "https://www.sothebys.com/en/buy/auction/2026/important-watches-4-2", | |
| 13 | + "title": "Important Watches", | |
| 14 | + "saleNumber": "HK1766", | |
| 15 | + "state": "Opened", | |
| 16 | + "type": "Live", | |
| 17 | + "departments": [ | |
| 18 | + "Watches" | |
| 19 | + ], | |
| 20 | + "currency": "HKD", | |
| 21 | + "location": "Hong Kong", | |
| 22 | + "startsAt": "2026-09-18T03:00Z", | |
| 23 | + "endsAt": "2026-09-18T03:00Z", | |
| 24 | + "closedAt": null, | |
| 25 | + "totalLots": 405 | |
| 26 | + }, | |
| 27 | + "offset": 0, | |
| 28 | + "lots": [ | |
| 29 | + { | |
| 30 | + "lotId": "1fabbc51-b69b-400f-8690-a6e970116c47", | |
| 31 | + "lotNumber": "2201", | |
| 32 | + "title": "A limited edition set of two pens, Circa 2008", | |
| 33 | + "creators": "F.P. Journe", | |
| 34 | + "slug": "a-limited-edition-set-of-two-pens-circa-2008", | |
| 35 | + "estimateLow": 42000, | |
| 36 | + "estimateHigh": 60000, | |
| 37 | + "isClosed": false, | |
| 38 | + "closingTime": null, | |
| 39 | + "currentBid": null, | |
| 40 | + "bidCurrency": null, | |
| 41 | + "isSold": false, | |
| 42 | + "finalPrice": null, | |
| 43 | + "finalCurrency": null, | |
| 44 | + "numberOfBids": 1, | |
| 45 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/0916fa5/2147483647/strip/true/crop/1500x2000+0+0/resize/4096x5461!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Fb4%2Fad%2F1321d29c431f8326254a1f55c3e2%2Fhk1766-dpxqm-090-05-t3-en01.jpg", | |
| 46 | + "withdrawn": false | |
| 47 | + }, | |
| 48 | + { | |
| 49 | + "lotId": "c79474f4-923b-4b3a-b27e-2a4328367b2a", | |
| 50 | + "lotNumber": "2202", | |
| 51 | + "title": "No. 8 | A brand new stainless steel jumping hour wristwatch with retrograde minute indication, Circa 2026", | |
| 52 | + "creators": "Ōtsuka Lōtec ", | |
| 53 | + "slug": "no-8-a-brand-new-stainless-steel-jumping-hour", | |
| 54 | + "estimateLow": 100000, | |
| 55 | + "estimateHigh": 200000, | |
| 56 | + "isClosed": false, | |
| 57 | + "closingTime": null, | |
| 58 | + "currentBid": null, | |
| 59 | + "bidCurrency": null, | |
| 60 | + "isSold": false, | |
| 61 | + "finalPrice": null, | |
| 62 | + "finalCurrency": null, | |
| 63 | + "numberOfBids": 3, | |
| 64 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/ee7b979/2147483647/strip/true/crop/3543x3543+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F79%2F11%2Fe47fe839450f8c19d607a988c7ce%2Fhk1766-dq3ly-103-03-t3-01.jpg", | |
| 65 | + "withdrawn": false | |
| 66 | + }, | |
| 67 | + { | |
| 68 | + "lotId": "0ef26304-c0e3-4cd6-9dd5-787c8ed7d48b", | |
| 69 | + "lotNumber": "2203", | |
| 70 | + "title": "Pendulette Réveil Souveraine | A stainless steel desk clock with alarm, Circa 2020", | |
| 71 | + "creators": "F.P. Journe", | |
| 72 | + "slug": "pendulette-reveil-souveraine-a-stainless-steel", | |
| 73 | + "estimateLow": 50000, | |
| 74 | + "estimateHigh": 200000, | |
| 75 | + "isClosed": false, | |
| 76 | + "closingTime": null, | |
| 77 | + "currentBid": null, | |
| 78 | + "bidCurrency": null, | |
| 79 | + "isSold": false, | |
| 80 | + "finalPrice": null, | |
| 81 | + "finalCurrency": null, | |
| 82 | + "numberOfBids": null, | |
| 83 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/e586ed9/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F87%2F51%2F315090bc4b7e9c312b5ae3d3f159%2Fhk1766-dnnkh-025-13-t3-01.jpg", | |
| 84 | + "withdrawn": false | |
| 85 | + }, | |
| 86 | + { | |
| 87 | + "lotId": "0b23c322-38aa-4d15-9c87-5bf6cac1b716", | |
| 88 | + "lotNumber": "2204", | |
| 89 | + "title": "Antarctique Passage de Drake “Glacier Blue” | A stainless steel bracelet watch with date, Circa 2024", | |
| 90 | + "creators": "Czapek", | |
| 91 | + "slug": "antarctique-passage-de-drake-glacier-blue-a", | |
| 92 | + "estimateLow": 80000, | |
| 93 | + "estimateHigh": 160000, | |
| 94 | + "isClosed": false, | |
| 95 | + "closingTime": null, | |
| 96 | + "currentBid": null, | |
| 97 | + "bidCurrency": null, | |
| 98 | + "isSold": false, | |
| 99 | + "finalPrice": null, | |
| 100 | + "finalCurrency": null, | |
| 101 | + "numberOfBids": null, | |
| 102 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/f938a50/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F71%2Fa6%2F65021f7940f38e168e4dcc6456f9%2Fhk1766-dq3pd-017-19-t3-01.jpg", | |
| 103 | + "withdrawn": false | |
| 104 | + }, | |
| 105 | + { | |
| 106 | + "lotId": "39184802-aeeb-4d6b-a12f-548fbcfe8da0", | |
| 107 | + "lotNumber": "2205", | |
| 108 | + "title": "Type 8 | A titanium wristwatch with rotating dial, Circa 2023", | |
| 109 | + "creators": "Ressence", | |
| 110 | + "slug": "type-8-a-titanium-wristwatch-with-rotating-dial", | |
| 111 | + "estimateLow": 100000, | |
| 112 | + "estimateHigh": 200000, | |
| 113 | + "isClosed": false, | |
| 114 | + "closingTime": null, | |
| 115 | + "currentBid": null, | |
| 116 | + "bidCurrency": null, | |
| 117 | + "isSold": false, | |
| 118 | + "finalPrice": null, | |
| 119 | + "finalCurrency": null, | |
| 120 | + "numberOfBids": 1, | |
| 121 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/6208594/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F65%2F68%2F3c2b22c24c109b4ea3af82952570%2Fhk1766-dq2sf-17-21-t3-01.jpg", | |
| 122 | + "withdrawn": false | |
| 123 | + }, | |
| 124 | + { | |
| 125 | + "lotId": "118ffaea-7769-42fe-8714-091c94da550a", | |
| 126 | + "lotNumber": "2206", | |
| 127 | + "title": "Royal Oak Offshore Complete Calendar, Reference 25807ST | A stainless steel triple calendar bracelet watch, Circa 2004", | |
| 128 | + "creators": "Audemars Piguet", | |
| 129 | + "slug": "royal-oak-offshore-complete-calendar-reference", | |
| 130 | + "estimateLow": 150000, | |
| 131 | + "estimateHigh": 300000, | |
| 132 | + "isClosed": false, | |
| 133 | + "closingTime": null, | |
| 134 | + "currentBid": null, | |
| 135 | + "bidCurrency": null, | |
| 136 | + "isSold": false, | |
| 137 | + "finalPrice": null, | |
| 138 | + "finalCurrency": null, | |
| 139 | + "numberOfBids": null, | |
| 140 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/581a876/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Ff5%2F33%2F6d3a0a0b4b70912673474e95dfd2%2Fhk1766-dnlv8-023-07-t3-01.jpg", | |
| 141 | + "withdrawn": false | |
| 142 | + }, | |
| 143 | + { | |
| 144 | + "lotId": "9b73a3b1-e41f-4886-8ec9-06e0d38bcc78", | |
| 145 | + "lotNumber": "2207", | |
| 146 | + "title": "Reference 2225 | A yellow gold and diamond-set wristwatch with polychrome enamel dial, Circa 1995", | |
| 147 | + "creators": "Jaquet Droz", | |
| 148 | + "slug": "reference-2225-a-yellow-gold-and-diamond-set", | |
| 149 | + "estimateLow": 80000, | |
| 150 | + "estimateHigh": 160000, | |
| 151 | + "isClosed": false, | |
| 152 | + "closingTime": null, | |
| 153 | + "currentBid": null, | |
| 154 | + "bidCurrency": null, | |
| 155 | + "isSold": false, | |
| 156 | + "finalPrice": null, | |
| 157 | + "finalCurrency": null, | |
| 158 | + "numberOfBids": null, | |
| 159 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/5e50790/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Fe9%2F31%2F571f6f7d46779d80bd299ee1326d%2Fhk1766-dpqf3-068-11-t3-01.jpg", | |
| 160 | + "withdrawn": false | |
| 161 | + }, | |
| 162 | + { | |
| 163 | + "lotId": "050b77db-6247-4652-8f50-ba2621b1c241", | |
| 164 | + "lotNumber": "2208", | |
| 165 | + "title": "San Marco \"Chung Chun\", Reference 139-70-9 | A limited edition platinum wristwatch with cloisonné enamel dial, Circa 1998", | |
| 166 | + "creators": "Ulysse Nardin", | |
| 167 | + "slug": "san-marco-chung-chun-reference-139-70-9-a-limited", | |
| 168 | + "estimateLow": 80000, | |
| 169 | + "estimateHigh": 160000, | |
| 170 | + "isClosed": false, | |
| 171 | + "closingTime": null, | |
| 172 | + "currentBid": null, | |
| 173 | + "bidCurrency": null, | |
| 174 | + "isSold": false, | |
| 175 | + "finalPrice": null, | |
| 176 | + "finalCurrency": null, | |
| 177 | + "numberOfBids": 2, | |
| 178 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/a0d31a8/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F21%2Fa7%2F00a658ac4f9e87ed33e81e8e9939%2Fhk1766-dpfvh-051-05-t3-01.jpg", | |
| 179 | + "withdrawn": false | |
| 180 | + }, | |
| 181 | + { | |
| 182 | + "lotId": "6f5d166d-b22b-4a66-abcd-1f09804f0ef1", | |
| 183 | + "lotNumber": "2210", | |
| 184 | + "title": "Master Minute Repeater, Reference 164 T4 50 | A limited edition titanium semi-skeletonised minute repeating wristwatch with spring torque and power reserve indication, Circa 2006", | |
| 185 | + "creators": "Jaeger-LeCoultre", | |
| 186 | + "slug": "master-minute-repeater-reference-164-t4-50-a", | |
| 187 | + "estimateLow": 300000, | |
| 188 | + "estimateHigh": 500000, | |
| 189 | + "isClosed": false, | |
| 190 | + "closingTime": null, | |
| 191 | + "currentBid": null, | |
| 192 | + "bidCurrency": null, | |
| 193 | + "isSold": false, | |
| 194 | + "finalPrice": null, | |
| 195 | + "finalCurrency": null, | |
| 196 | + "numberOfBids": null, | |
| 197 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/adca1f0/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Fe8%2Fdb%2F7120896e4281ae098116bb9bd777%2Fhk1766-dpt9c-084-06-t2-01.jpg", | |
| 198 | + "withdrawn": false | |
| 199 | + }, | |
| 200 | + { | |
| 201 | + "lotId": "89c527bb-fe1c-4dd9-89d4-b1eebf9d1156", | |
| 202 | + "lotNumber": "2211", | |
| 203 | + "title": "Royal Oak Quantieme Perpetuel, Reference 26574ST.OO.1220ST.02 | A stainless steel perpetual calendar bracelet watch with moon phases, 52 weeks and leap year indication, Circa 2016", | |
| 204 | + "creators": "Audemars Piguet", | |
| 205 | + "slug": "royal-oak-quantieme-perpetuel-reference-26574st-oo", | |
| 206 | + "estimateLow": 600000, | |
| 207 | + "estimateHigh": 800000, | |
| 208 | + "isClosed": false, | |
| 209 | + "closingTime": null, | |
| 210 | + "currentBid": null, | |
| 211 | + "bidCurrency": null, | |
| 212 | + "isSold": false, | |
| 213 | + "finalPrice": null, | |
| 214 | + "finalCurrency": null, | |
| 215 | + "numberOfBids": null, | |
| 216 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/d19f252/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F9a%2Fad%2Fcaa09ed84e0ebda67b0db9d8168c%2Fhk1766-dpxq6-090-01-t3-01.jpg", | |
| 217 | + "withdrawn": false | |
| 218 | + }, | |
| 219 | + { | |
| 220 | + "lotId": "a1aa7b8c-c64d-42c8-b621-cdefc0404b8b", | |
| 221 | + "lotNumber": "2212", | |
| 222 | + "title": "Carillon Tourbillon, Reference BRRP48GTBMR | A limited edition pink gold semi-skeletonised carillon minute repeating tourbillon wristwatch with power reserve indication, Circa 2013", | |
| 223 | + "creators": "Bulgari | Daniel Roth", | |
| 224 | + "slug": "carillon-tourbillon-reference-brrp48gtbmr-a", | |
| 225 | + "estimateLow": 450000, | |
| 226 | + "estimateHigh": 800000, | |
| 227 | + "isClosed": false, | |
| 228 | + "closingTime": null, | |
| 229 | + "currentBid": null, | |
| 230 | + "bidCurrency": null, | |
| 231 | + "isSold": false, | |
| 232 | + "finalPrice": null, | |
| 233 | + "finalCurrency": null, | |
| 234 | + "numberOfBids": null, | |
| 235 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/7db88d8/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F55%2F02%2F6c0cbceb4c2389ab74622516ef38%2Fhk1766-dpwf7-086-01-t2-01.jpg", | |
| 236 | + "withdrawn": false | |
| 237 | + }, | |
| 238 | + { | |
| 239 | + "lotId": "dac0f236-0b89-4d03-b45f-ab59aef70bbc", | |
| 240 | + "lotNumber": "2213", | |
| 241 | + "title": "Royal Oak 'Jumbo' Extra-Thin, Reference 15202IP.OO.1240IP.01 | A brand new limited edition platinum and titanium bracelet watch with date, Circa 2018", | |
| 242 | + "creators": "Audemars Piguet", | |
| 243 | + "slug": "royal-oak-jumbo-extra-thin-reference-15202ip-oo", | |
| 244 | + "estimateLow": 700000, | |
| 245 | + "estimateHigh": 1500000, | |
| 246 | + "isClosed": false, | |
| 247 | + "closingTime": null, | |
| 248 | + "currentBid": null, | |
| 249 | + "bidCurrency": null, | |
| 250 | + "isSold": false, | |
| 251 | + "finalPrice": null, | |
| 252 | + "finalCurrency": null, | |
| 253 | + "numberOfBids": 1, | |
| 254 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/8a95b50/2147483647/strip/true/crop/3543x3543+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F63%2F69%2F3a6fa7a6471fa35a65dca14b0d15%2Fhk1766-d4qf9-079-01-t1-01.jpg", | |
| 255 | + "withdrawn": false | |
| 256 | + }, | |
| 257 | + { | |
| 258 | + "lotId": "382cc085-a582-451a-b33a-eee7358e5134", | |
| 259 | + "lotNumber": "2214", | |
| 260 | + "title": "Luminor 1950 Tourbillon GMT, Reference PAM276 | A limited edition stainless steel dual time tourbillon wristwatch with power reserve indication, Circa 2008", | |
| 261 | + "creators": "Panerai", | |
| 262 | + "slug": "luminor-1950-tourbillon-gmt-reference-pam276-a", | |
| 263 | + "estimateLow": 200000, | |
| 264 | + "estimateHigh": 300000, | |
| 265 | + "isClosed": false, | |
| 266 | + "closingTime": null, | |
| 267 | + "currentBid": null, | |
| 268 | + "bidCurrency": null, | |
| 269 | + "isSold": false, | |
| 270 | + "finalPrice": null, | |
| 271 | + "finalCurrency": null, | |
| 272 | + "numberOfBids": null, | |
| 273 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/c53ba7e/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F2d%2F0f%2F9439a08349998768173e4676d1da%2Fhk1766-dpxqj-090-03-t3-01.jpg", | |
| 274 | + "withdrawn": false | |
| 275 | + }, | |
| 276 | + { | |
| 277 | + "lotId": "d15a0f05-e557-40f2-8e31-3cca605cfa8c", | |
| 278 | + "lotNumber": "2215", | |
| 279 | + "title": "Lo Scienziato Radiomir Tourbillon GMT Ceramica, Reference PAM348 | A limited edition black ceramic skeletonised dual time tourbillon wristwatch with power reserve indication, Circa 2010", | |
| 280 | + "creators": "Panerai", | |
| 281 | + "slug": "lo-scienziato-radiomir-tourbillon-gmt-ceramica", | |
| 282 | + "estimateLow": 240000, | |
| 283 | + "estimateHigh": 400000, | |
| 284 | + "isClosed": false, | |
| 285 | + "closingTime": null, | |
| 286 | + "currentBid": null, | |
| 287 | + "bidCurrency": null, | |
| 288 | + "isSold": false, | |
| 289 | + "finalPrice": null, | |
| 290 | + "finalCurrency": null, | |
| 291 | + "numberOfBids": null, | |
| 292 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/a25f597/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F61%2Fc7%2Fc2f30c674147a24287f7bd60a9d2%2Fhk1766-dpxqk-005-12-t3-01.jpg", | |
| 293 | + "withdrawn": false | |
| 294 | + }, | |
| 295 | + { | |
| 296 | + "lotId": "c69ebc7e-48a8-47a1-b595-b95da10ed243", | |
| 297 | + "lotNumber": "2216", | |
| 298 | + "title": "Royal Oak \"50th Anniversary\", Reference 77350CE | A black ceramic bracelet watch with date, Circa 2022", | |
| 299 | + "creators": "Audemars Piguet", | |
| 300 | + "slug": "royal-oak-50th-anniversary-reference-77350ce-a", | |
| 301 | + "estimateLow": 350000, | |
| 302 | + "estimateHigh": 500000, | |
| 303 | + "isClosed": false, | |
| 304 | + "closingTime": null, | |
| 305 | + "currentBid": null, | |
| 306 | + "bidCurrency": null, | |
| 307 | + "isSold": false, | |
| 308 | + "finalPrice": null, | |
| 309 | + "finalCurrency": null, | |
| 310 | + "numberOfBids": null, | |
| 311 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/ce74235/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Ff7%2Fa0%2Fe94091d44af7a3c016b96a28d79f%2Fhk1766-dq27z-099-05-t2-01.jpg", | |
| 312 | + "withdrawn": false | |
| 313 | + }, | |
| 314 | + { | |
| 315 | + "lotId": "e62ea79e-75c6-4081-b949-cb1d5a5bf833", | |
| 316 | + "lotNumber": "2217", | |
| 317 | + "title": "1521 NH | A stainless steel dual time wristwatch with three-dimensional globe dial and mother-of-pearl chapter ring, Circa 2004", | |
| 318 | + "creators": "Magellan", | |
| 319 | + "slug": "1521-nh-a-stainless-steel-dual-time-wristwatch", | |
| 320 | + "estimateLow": 42000, | |
| 321 | + "estimateHigh": 80000, | |
| 322 | + "isClosed": false, | |
| 323 | + "closingTime": null, | |
| 324 | + "currentBid": null, | |
| 325 | + "bidCurrency": null, | |
| 326 | + "isSold": false, | |
| 327 | + "finalPrice": null, | |
| 328 | + "finalCurrency": null, | |
| 329 | + "numberOfBids": null, | |
| 330 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/a07abb9/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F8d%2F71%2F3cf622244b8894ee93178c62c12b%2Fhk1766-dpfv6-048-04-t3-01.jpg", | |
| 331 | + "withdrawn": true | |
| 332 | + }, | |
| 333 | + { | |
| 334 | + "lotId": "cf2595f6-01b0-4a9b-b30d-bafaab4d53b0", | |
| 335 | + "lotNumber": "2218", | |
| 336 | + "title": "Type 8 | A titanium wristwatch with rotating dial, Circa 2023", | |
| 337 | + "creators": "Ressence", | |
| 338 | + "slug": "type-8-a-titanium-wristwatch-with-rotating-dial-2", | |
| 339 | + "estimateLow": 80000, | |
| 340 | + "estimateHigh": 120000, | |
| 341 | + "isClosed": false, | |
| 342 | + "closingTime": null, | |
| 343 | + "currentBid": null, | |
| 344 | + "bidCurrency": null, | |
| 345 | + "isSold": false, | |
| 346 | + "finalPrice": null, | |
| 347 | + "finalCurrency": null, | |
| 348 | + "numberOfBids": 1, | |
| 349 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/393ce9d/2147483647/strip/true/crop/3543x3543+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F94%2Fbd%2Fb7c7d2e24798959fa1733d099321%2Fhk1766-d3n4t-17-20-t3-01.jpg", | |
| 350 | + "withdrawn": false | |
| 351 | + }, | |
| 352 | + { | |
| 353 | + "lotId": "e9f1f354-8acd-4989-b036-750ae2ffb1d7", | |
| 354 | + "lotNumber": "2219", | |
| 355 | + "title": "Excalibur Spider Double Tourbillon, Reference DBEX0674 | A limited edition pink gold and forged carbon skeletonised double flying tourbillon wristwatch with power reserve indication, Circa 2018", | |
| 356 | + "creators": "Roger Dubuis", | |
| 357 | + "slug": "excalibur-spider-double-tourbillon-reference", | |
| 358 | + "estimateLow": 500000, | |
| 359 | + "estimateHigh": 800000, | |
| 360 | + "isClosed": false, | |
| 361 | + "closingTime": null, | |
| 362 | + "currentBid": null, | |
| 363 | + "bidCurrency": null, | |
| 364 | + "isSold": false, | |
| 365 | + "finalPrice": null, | |
| 366 | + "finalCurrency": null, | |
| 367 | + "numberOfBids": null, | |
| 368 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/343bf8f/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F92%2F48%2F7b6b1f3348c187dcfe3f5df5581d%2Fhk1766-dpqf7-069-01-t2-01.jpg", | |
| 369 | + "withdrawn": false | |
| 370 | + }, | |
| 371 | + { | |
| 372 | + "lotId": "3be39b56-1672-479a-b708-95a59567850e", | |
| 373 | + "lotNumber": "2220", | |
| 374 | + "title": "Streamliner Flyback Chronograph ‘Funky Blue’, Reference 6902-1201 | A stainless steel flyback chronograph bracelet watch, Circa 2023", | |
| 375 | + "creators": "H. Moser & Cie", | |
| 376 | + "slug": "streamliner-flyback-chronograph-funky-blue", | |
| 377 | + "estimateLow": 120000, | |
| 378 | + "estimateHigh": 240000, | |
| 379 | + "isClosed": false, | |
| 380 | + "closingTime": null, | |
| 381 | + "currentBid": null, | |
| 382 | + "bidCurrency": null, | |
| 383 | + "isSold": false, | |
| 384 | + "finalPrice": null, | |
| 385 | + "finalCurrency": null, | |
| 386 | + "numberOfBids": 1, | |
| 387 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/7a9d070/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Fb0%2Fe0%2Ff342e7ee4becacff22c373f60f13%2Fhk1766-dpxqb-090-02-t2-01.jpg", | |
| 388 | + "withdrawn": false | |
| 389 | + }, | |
| 390 | + { | |
| 391 | + "lotId": "947cc41c-e551-499a-bbda-d4872fbbd306", | |
| 392 | + "lotNumber": "2222", | |
| 393 | + "title": "Classic Origin ‘Revolution & The Rake’ | A limited edition stainless steel wristwatch with sector dial and bracelet, Circa 2021", | |
| 394 | + "creators": "Laurent Ferrier", | |
| 395 | + "slug": "classic-origin-revolution-the-rake-a-limited", | |
| 396 | + "estimateLow": 200000, | |
| 397 | + "estimateHigh": 400000, | |
| 398 | + "isClosed": false, | |
| 399 | + "closingTime": null, | |
| 400 | + "currentBid": null, | |
| 401 | + "bidCurrency": null, | |
| 402 | + "isSold": false, | |
| 403 | + "finalPrice": null, | |
| 404 | + "finalCurrency": null, | |
| 405 | + "numberOfBids": 1, | |
| 406 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/7d65582/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Fed%2F73%2F7a4911694f7d9869be710d42ffe5%2Fhk1766-dnlv6-023-05-t3-01.jpg", | |
| 407 | + "withdrawn": false | |
| 408 | + }, | |
| 409 | + { | |
| 410 | + "lotId": "0bd85034-4edc-4ded-92a4-23f421ad3fa7", | |
| 411 | + "lotNumber": "2223", | |
| 412 | + "title": "Pilote / Driver | An unusual limited edition, deeply curved rectangular white gold driver’s rear-wound wristwatch with integrated white gold deployant buckle, Circa 1998", | |
| 413 | + "creators": "Cartier, Paris", | |
| 414 | + "slug": "pilote-driver-an-unusual-limited-edition-deeply", | |
| 415 | + "estimateLow": 50000, | |
| 416 | + "estimateHigh": 65000, | |
| 417 | + "isClosed": false, | |
| 418 | + "closingTime": null, | |
| 419 | + "currentBid": null, | |
| 420 | + "bidCurrency": null, | |
| 421 | + "isSold": false, | |
| 422 | + "finalPrice": null, | |
| 423 | + "finalCurrency": null, | |
| 424 | + "numberOfBids": 4, | |
| 425 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/ee7359d/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F24%2F55%2Fcfebb0b3487f8e05ae6010bd54dc%2Fhk1766-dkmc9-t1-01.jpg", | |
| 426 | + "withdrawn": false | |
| 427 | + }, | |
| 428 | + { | |
| 429 | + "lotId": "bbeaaaa0-33a7-4e57-9b67-9464f851ad60", | |
| 430 | + "lotNumber": "2224", | |
| 431 | + "title": "Pilote / Driver | An unusual limited edition deeply curved rectangular yellow gold driver’s rear-wound wristwatch with integrated gold deployant buckle, Circa 1997", | |
| 432 | + "creators": "Cartier, Paris", | |
| 433 | + "slug": "pilote-driver-an-unusual-limited-edition-deeply-2", | |
| 434 | + "estimateLow": 40000, | |
| 435 | + "estimateHigh": 65000, | |
| 436 | + "isClosed": false, | |
| 437 | + "closingTime": null, | |
| 438 | + "currentBid": null, | |
| 439 | + "bidCurrency": null, | |
| 440 | + "isSold": false, | |
| 441 | + "finalPrice": null, | |
| 442 | + "finalCurrency": null, | |
| 443 | + "numberOfBids": 4, | |
| 444 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/f2c6490/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Ff4%2Fe5%2F3853d84545e8925373c19600c42a%2Fhk1766-dkmbz-t1-01.jpg", | |
| 445 | + "withdrawn": false | |
| 446 | + }, | |
| 447 | + { | |
| 448 | + "lotId": "9dc7a890-a50b-4cf2-b110-eb62247dd6fa", | |
| 449 | + "lotNumber": "2225", | |
| 450 | + "title": "Driver, Reference 2453B | An unusual and very rare limited edition, deeply curved rectangular white gold driver’s rear-wound wristwatch with integrated white gold deployant buckle, Circa 1999", | |
| 451 | + "creators": "Cartier", | |
| 452 | + "slug": "driver-reference-2453b-an-unusual-and-very-rare", | |
| 453 | + "estimateLow": 55000, | |
| 454 | + "estimateHigh": 80000, | |
| 455 | + "isClosed": false, | |
| 456 | + "closingTime": null, | |
| 457 | + "currentBid": null, | |
| 458 | + "bidCurrency": null, | |
| 459 | + "isSold": false, | |
| 460 | + "finalPrice": null, | |
| 461 | + "finalCurrency": null, | |
| 462 | + "numberOfBids": 6, | |
| 463 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/3639c0e/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Ff9%2F10%2Fb03c5cc34a998f5455d8bf36e7b6%2Fhk1766-dkmdq-t1-01.jpg", | |
| 464 | + "withdrawn": false | |
| 465 | + }, | |
| 466 | + { | |
| 467 | + "lotId": "b19b39e2-83f3-423c-826c-073669e6ab0e", | |
| 468 | + "lotNumber": "2226", | |
| 469 | + "title": "Tank Basculante \"CPCP\", Reference 2499 | A yellow gold reversible wristwatch, Circa 2000", | |
| 470 | + "creators": "Cartier", | |
| 471 | + "slug": "tank-basculante-cpcp-reference-2499-a-yellow-gold", | |
| 472 | + "estimateLow": 120000, | |
| 473 | + "estimateHigh": 200000, | |
| 474 | + "isClosed": false, | |
| 475 | + "closingTime": null, | |
| 476 | + "currentBid": null, | |
| 477 | + "bidCurrency": null, | |
| 478 | + "isSold": false, | |
| 479 | + "finalPrice": null, | |
| 480 | + "finalCurrency": null, | |
| 481 | + "numberOfBids": 1, | |
| 482 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/01cd4b9/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Fdd%2Ff7%2F9a13b3b8456f8bd30eed57d90af1%2Fhk1766-dphgr-054-01-t2-01.jpg", | |
| 483 | + "withdrawn": false | |
| 484 | + }, | |
| 485 | + { | |
| 486 | + "lotId": "a2c466fd-b7c9-4445-8fca-24169666fe39", | |
| 487 | + "lotNumber": "2227", | |
| 488 | + "title": "Santos Dumont, Reference 1575 1 | A limited edition platinum wristwatch, Circa 1994", | |
| 489 | + "creators": "Cartier", | |
| 490 | + "slug": "santos-dumont-reference-1575-1-a-limited-edition", | |
| 491 | + "estimateLow": 200000, | |
| 492 | + "estimateHigh": 600000, | |
| 493 | + "isClosed": false, | |
| 494 | + "closingTime": null, | |
| 495 | + "currentBid": null, | |
| 496 | + "bidCurrency": null, | |
| 497 | + "isSold": false, | |
| 498 | + "finalPrice": null, | |
| 499 | + "finalCurrency": null, | |
| 500 | + "numberOfBids": null, | |
| 501 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/c151b0a/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F65%2F83%2Fe9a7fde9463c9f085179fcea27a4%2Fhk1766-dnnkb-025-08-t3-01.jpg", | |
| 502 | + "withdrawn": false | |
| 503 | + }, | |
| 504 | + { | |
| 505 | + "lotId": "c0a08bc2-65ff-4189-ba3e-a73a09cecc37", | |
| 506 | + "lotNumber": "2228", | |
| 507 | + "title": "Tank à Guichets \"CPCP\", Reference 2817 | A limited edition pink gold jumping hour wristwatch, Circa 2004", | |
| 508 | + "creators": "Cartier", | |
| 509 | + "slug": "tank-a-guichets-cpcp-reference-2817-a-limited", | |
| 510 | + "estimateLow": 400000, | |
| 511 | + "estimateHigh": 700000, | |
| 512 | + "isClosed": false, | |
| 513 | + "closingTime": null, | |
| 514 | + "currentBid": null, | |
| 515 | + "bidCurrency": null, | |
| 516 | + "isSold": false, | |
| 517 | + "finalPrice": null, | |
| 518 | + "finalCurrency": null, | |
| 519 | + "numberOfBids": 3, | |
| 520 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/1061f2c/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Fb0%2F6a%2Fb83d949d4d8e9414e1bcefb29398%2Fhk1766-dq6g9-114-02-t2-01.jpg", | |
| 521 | + "withdrawn": false | |
| 522 | + }, | |
| 523 | + { | |
| 524 | + "lotId": "67ed422a-6267-4b22-96e4-06169c228ea8", | |
| 525 | + "lotNumber": "2229", | |
| 526 | + "title": "New York retailed | Clip de Revers | A yellow and pink gold, diamond and ruby-set lyre-form clip watch, Circa 1937", | |
| 527 | + "creators": "Cartier", | |
| 528 | + "slug": "new-york-retailed-clip-de-revers-a-yellow-and-pink", | |
| 529 | + "estimateLow": 40000, | |
| 530 | + "estimateHigh": 65000, | |
| 531 | + "isClosed": false, | |
| 532 | + "closingTime": null, | |
| 533 | + "currentBid": null, | |
| 534 | + "bidCurrency": null, | |
| 535 | + "isSold": false, | |
| 536 | + "finalPrice": null, | |
| 537 | + "finalCurrency": null, | |
| 538 | + "numberOfBids": 2, | |
| 539 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/7350c11/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Fa6%2Fa0%2Ffcf00b37440ead606ad0ac72c180%2Fhk1766-dklzr-t1-01.jpg", | |
| 540 | + "withdrawn": false | |
| 541 | + }, | |
| 542 | + { | |
| 543 | + "lotId": "f9715f53-2f19-40ad-a786-93cf395a6001", | |
| 544 | + "lotNumber": "2230", | |
| 545 | + "title": "A yellow gold purse watch with black dial and sliding covers, Circa 1955", | |
| 546 | + "creators": "Movado for Cartier, Paris", | |
| 547 | + "slug": "a-yellow-gold-purse-watch-with-black-dial-and", | |
| 548 | + "estimateLow": 32000, | |
| 549 | + "estimateHigh": 50000, | |
| 550 | + "isClosed": false, | |
| 551 | + "closingTime": null, | |
| 552 | + "currentBid": null, | |
| 553 | + "bidCurrency": null, | |
| 554 | + "isSold": false, | |
| 555 | + "finalPrice": null, | |
| 556 | + "finalCurrency": null, | |
| 557 | + "numberOfBids": 1, | |
| 558 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/2226054/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F2e%2F8e%2F079a5197445194addfe1acd4e2ab%2Fhk1766-dn9ph-t1-02.jpg", | |
| 559 | + "withdrawn": false | |
| 560 | + }, | |
| 561 | + { | |
| 562 | + "lotId": "9168a4ea-71fe-4347-8270-a983bf9e89a6", | |
| 563 | + "lotNumber": "2231", | |
| 564 | + "title": "New York retailed | Clip de Revers | A yellow gold lapel clip watch with movement by James Schulz, Circa 1945", | |
| 565 | + "creators": "Cartier, James Schulz", | |
| 566 | + "slug": "new-york-retailed-clip-de-revers-a-yellow-gold", | |
| 567 | + "estimateLow": 15000, | |
| 568 | + "estimateHigh": 20000, | |
| 569 | + "isClosed": false, | |
| 570 | + "closingTime": null, | |
| 571 | + "currentBid": null, | |
| 572 | + "bidCurrency": null, | |
| 573 | + "isSold": false, | |
| 574 | + "finalPrice": null, | |
| 575 | + "finalCurrency": null, | |
| 576 | + "numberOfBids": 1, | |
| 577 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/d303ef0/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F36%2Ff4%2F9020a62f4f6d9f84fb56c4a420a5%2Fhk1766-dn9qj-t1-01.jpg", | |
| 578 | + "withdrawn": false | |
| 579 | + }, | |
| 580 | + { | |
| 581 | + "lotId": "20aca3c4-57cd-4a3c-94df-7f3c5f157098", | |
| 582 | + "lotNumber": "2232", | |
| 583 | + "title": "A yellow gold hundred francs coin watch, Circa 1930", | |
| 584 | + "creators": "Cartier", | |
| 585 | + "slug": "a-yellow-gold-hundred-francs-coin-watch-circa-1930", | |
| 586 | + "estimateLow": 80000, | |
| 587 | + "estimateHigh": 160000, | |
| 588 | + "isClosed": false, | |
| 589 | + "closingTime": null, | |
| 590 | + "currentBid": null, | |
| 591 | + "bidCurrency": null, | |
| 592 | + "isSold": false, | |
| 593 | + "finalPrice": null, | |
| 594 | + "finalCurrency": null, | |
| 595 | + "numberOfBids": null, | |
| 596 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/a572f11/2147483647/strip/true/crop/3543x3543+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F03%2Fe3%2F7aa9151f49da908b603ebc1a0e19%2Fhk1766-dn8l5-012-01-t3-06.jpg", | |
| 597 | + "withdrawn": false | |
| 598 | + }, | |
| 599 | + { | |
| 600 | + "lotId": "56b5b0e5-211c-4819-9812-296b46c3ed6c", | |
| 601 | + "lotNumber": "2233", | |
| 602 | + "title": "Tank Chinoise \"CPCP\", Reference 2685G | A limited edition platinum wristwatch, Circa 2005", | |
| 603 | + "creators": "Cartier", | |
| 604 | + "slug": "tank-chinoise-cpcp-reference-2685g-a-limited", | |
| 605 | + "estimateLow": 150000, | |
| 606 | + "estimateHigh": 300000, | |
| 607 | + "isClosed": false, | |
| 608 | + "closingTime": null, | |
| 609 | + "currentBid": null, | |
| 610 | + "bidCurrency": null, | |
| 611 | + "isSold": false, | |
| 612 | + "finalPrice": null, | |
| 613 | + "finalCurrency": null, | |
| 614 | + "numberOfBids": null, | |
| 615 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/7b0f857/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Fe3%2Fd1%2Ff1fb0c144caab44bce4e8ce86630%2Fhk1766-dpcxv-023-11-t3-01.jpg", | |
| 616 | + "withdrawn": false | |
| 617 | + }, | |
| 618 | + { | |
| 619 | + "lotId": "be0b0bb1-4189-41a7-9de6-00b2775f896c", | |
| 620 | + "lotNumber": "2234", | |
| 621 | + "title": "Cloche \"Collection Privé\", Reference WGCC0004 | A limited edition platinum wristwatch, Circa 2021", | |
| 622 | + "creators": "Cartier", | |
| 623 | + "slug": "cloche-collection-prive-reference-wgcc0004-a", | |
| 624 | + "estimateLow": 280000, | |
| 625 | + "estimateHigh": 400000, | |
| 626 | + "isClosed": false, | |
| 627 | + "closingTime": null, | |
| 628 | + "currentBid": null, | |
| 629 | + "bidCurrency": null, | |
| 630 | + "isSold": false, | |
| 631 | + "finalPrice": null, | |
| 632 | + "finalCurrency": null, | |
| 633 | + "numberOfBids": 1, | |
| 634 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/7c0ad5e/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Fc9%2Fc4%2F2414c2fc401285816173a7606278%2Fhk1766-dnlvy-023-08-t3-01.jpg", | |
| 635 | + "withdrawn": false | |
| 636 | + }, | |
| 637 | + { | |
| 638 | + "lotId": "dd83b3fb-962d-445f-8b21-a1ca375091de", | |
| 639 | + "lotNumber": "2235", | |
| 640 | + "title": "Tortue, Reference WGTO0008 | A limited edition platinum wristwatch, Circa 2024", | |
| 641 | + "creators": "Cartier", | |
| 642 | + "slug": "tortue-reference-wgto0008-a-limited-edition", | |
| 643 | + "estimateLow": 120000, | |
| 644 | + "estimateHigh": 200000, | |
| 645 | + "isClosed": false, | |
| 646 | + "closingTime": null, | |
| 647 | + "currentBid": null, | |
| 648 | + "bidCurrency": null, | |
| 649 | + "isSold": false, | |
| 650 | + "finalPrice": null, | |
| 651 | + "finalCurrency": null, | |
| 652 | + "numberOfBids": 2, | |
| 653 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/4ebdff6/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F67%2F1c%2F0871846a4a36bc1a17ff859d8dcb%2Fhk1766-dpt5v-075-01-t3-01.jpg", | |
| 654 | + "withdrawn": false | |
| 655 | + }, | |
| 656 | + { | |
| 657 | + "lotId": "874dc673-ecdd-4137-bed3-bcd469459a56", | |
| 658 | + "lotNumber": "2236", | |
| 659 | + "title": " Tank À Vis \"CPCP\", Reference 2554 | A white gold wristwatch with date and wandering hours, Circa 2006", | |
| 660 | + "creators": "Cartier", | |
| 661 | + "slug": "tank-a-vis-cpcp-reference-2554-a-white-gold", | |
| 662 | + "estimateLow": 240000, | |
| 663 | + "estimateHigh": 480000, | |
| 664 | + "isClosed": false, | |
| 665 | + "closingTime": null, | |
| 666 | + "currentBid": null, | |
| 667 | + "bidCurrency": null, | |
| 668 | + "isSold": false, | |
| 669 | + "finalPrice": null, | |
| 670 | + "finalCurrency": null, | |
| 671 | + "numberOfBids": null, | |
| 672 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/0724b54/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Fd0%2Fdb%2Fa3e25e3d48eba2410b24c9aba677%2Fhk1766-dp4bf-039-02-t2-01.jpg", | |
| 673 | + "withdrawn": false | |
| 674 | + }, | |
| 675 | + { | |
| 676 | + "lotId": "7cd0a7a2-6eee-41ff-988c-d7ab238143a9", | |
| 677 | + "lotNumber": "2237", | |
| 678 | + "title": "An onyx, silver-gilt, gold, enamel and diamond-set 8-day desk clock, Circa 1919", | |
| 679 | + "creators": "Cartier, Paris", | |
| 680 | + "slug": "an-onyx-silver-gilt-gold-enamel-and-diamond-set-8", | |
| 681 | + "estimateLow": 55000, | |
| 682 | + "estimateHigh": 80000, | |
| 683 | + "isClosed": false, | |
| 684 | + "closingTime": null, | |
| 685 | + "currentBid": null, | |
| 686 | + "bidCurrency": null, | |
| 687 | + "isSold": false, | |
| 688 | + "finalPrice": null, | |
| 689 | + "finalCurrency": null, | |
| 690 | + "numberOfBids": 1, | |
| 691 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/0840333/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Fc8%2Fa3%2F1612777140e585bedac47081610d%2Fhk1766-dnb5z-t1-01.jpg", | |
| 692 | + "withdrawn": false | |
| 693 | + }, | |
| 694 | + { | |
| 695 | + "lotId": "660fc569-d778-4568-a822-97afe9108d82", | |
| 696 | + "lotNumber": "2238", | |
| 697 | + "title": "An agate, yellow gold, rock crystal and enamel 8-day desk clock with luminescent indexes, Circa 1926", | |
| 698 | + "creators": "Cartier, Paris", | |
| 699 | + "slug": "an-agate-yellow-gold-rock-crystal-and-enamel-8-day", | |
| 700 | + "estimateLow": 65000, | |
| 701 | + "estimateHigh": 95000, | |
| 702 | + "isClosed": false, | |
| 703 | + "closingTime": null, | |
| 704 | + "currentBid": null, | |
| 705 | + "bidCurrency": null, | |
| 706 | + "isSold": false, | |
| 707 | + "finalPrice": null, | |
| 708 | + "finalCurrency": null, | |
| 709 | + "numberOfBids": null, | |
| 710 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/13d5303/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F16%2F08%2F4a7e07e147a28a4640a37692f333%2Fhk1766-dn999-t1-01.jpg", | |
| 711 | + "withdrawn": false | |
| 712 | + }, | |
| 713 | + { | |
| 714 | + "lotId": "8d7ef951-0834-4f06-8a94-0fcc5581926d", | |
| 715 | + "lotNumber": "2239", | |
| 716 | + "title": "Carré à Coin Coupés | A square yellow gold wristwatch with chamfered corners and cylindrical T-bar lugs, Circa 1947", | |
| 717 | + "creators": "Cartier, Paris", | |
| 718 | + "slug": "carre-a-coin-coupes-a-square-yellow-gold", | |
| 719 | + "estimateLow": 120000, | |
| 720 | + "estimateHigh": 160000, | |
| 721 | + "isClosed": false, | |
| 722 | + "closingTime": null, | |
| 723 | + "currentBid": null, | |
| 724 | + "bidCurrency": null, | |
| 725 | + "isSold": false, | |
| 726 | + "finalPrice": null, | |
| 727 | + "finalCurrency": null, | |
| 728 | + "numberOfBids": null, | |
| 729 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/702a832/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F7c%2F19%2F0a58982b4cc798990718ad092368%2Fhk1766-dkm9s-091-22-rx-t3-01.jpg", | |
| 730 | + "withdrawn": false | |
| 731 | + }, | |
| 732 | + { | |
| 733 | + "lotId": "2ec2a1c6-6619-49c9-8ad7-285690ab83cd", | |
| 734 | + "lotNumber": "2240", | |
| 735 | + "title": "Baignoire | An oval yellow gold lady’s wristwatch with original gold deployant buckle, Circa 1966-67", | |
| 736 | + "creators": "Cartier, London", | |
| 737 | + "slug": "baignoire-an-oval-yellow-gold-ladys-wristwatch", | |
| 738 | + "estimateLow": 120000, | |
| 739 | + "estimateHigh": 160000, | |
| 740 | + "isClosed": false, | |
| 741 | + "closingTime": null, | |
| 742 | + "currentBid": null, | |
| 743 | + "bidCurrency": null, | |
| 744 | + "isSold": false, | |
| 745 | + "finalPrice": null, | |
| 746 | + "finalCurrency": null, | |
| 747 | + "numberOfBids": null, | |
| 748 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/5b5c786/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Fc8%2F2d%2F036d2a204b35b49ea7007dac352f%2Fhk1766-dkm95-091-29-rx-t3-01.jpg", | |
| 749 | + "withdrawn": false | |
| 750 | + }, | |
| 751 | + { | |
| 752 | + "lotId": "c4be4aa5-729a-4c55-aa2d-c09da374081f", | |
| 753 | + "lotNumber": "2241", | |
| 754 | + "title": "Maxi Pebble | A very rare yellow gold wristwatch with geometric off-set dial and original gold deployant buckle, Circa 1972-73", | |
| 755 | + "creators": "Cartier, London", | |
| 756 | + "slug": "maxi-pebble-a-very-rare-yellow-gold-wristwatch", | |
| 757 | + "estimateLow": 1600000, | |
| 758 | + "estimateHigh": 2200000, | |
| 759 | + "isClosed": false, | |
| 760 | + "closingTime": null, | |
| 761 | + "currentBid": null, | |
| 762 | + "bidCurrency": null, | |
| 763 | + "isSold": false, | |
| 764 | + "finalPrice": null, | |
| 765 | + "finalCurrency": null, | |
| 766 | + "numberOfBids": 1, | |
| 767 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/63e2c9b/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F0e%2Fa4%2F0bfd3b9a4c7594862d47d7f815cd%2Fhk1766-dlj4l-091-11-t1-01.jpg", | |
| 768 | + "withdrawn": false | |
| 769 | + }, | |
| 770 | + { | |
| 771 | + "lotId": "24c5ffb7-cec8-4757-bccc-e6688882da4a", | |
| 772 | + "lotNumber": "2242", | |
| 773 | + "title": "Midi Pebble | An extremely rare mid-sized yellow gold wristwatch with geometric off-set dial and original gold deployant buckle, Circa 1973-74", | |
| 774 | + "creators": "Cartier, London", | |
| 775 | + "slug": "midi-pebble-an-extremely-rare-mid-sized-yellow", | |
| 776 | + "estimateLow": 950000, | |
| 777 | + "estimateHigh": 1500000, | |
| 778 | + "isClosed": false, | |
| 779 | + "closingTime": null, | |
| 780 | + "currentBid": null, | |
| 781 | + "bidCurrency": null, | |
| 782 | + "isSold": false, | |
| 783 | + "finalPrice": null, | |
| 784 | + "finalCurrency": null, | |
| 785 | + "numberOfBids": null, | |
| 786 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/2736b7f/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F7f%2F6d%2F4e09d0914f4196bac9eb54bb6cff%2Fhk1766-dkn63-091-46-t3-01.jpg", | |
| 787 | + "withdrawn": false | |
| 788 | + }, | |
| 789 | + { | |
| 790 | + "lotId": "eaccf673-ad67-4fee-8733-e5abd0ca43a7", | |
| 791 | + "lotNumber": "2243", | |
| 792 | + "title": "Bamboo Coussin, Reference 78102 | A yellow gold wristwatch, Circa 1975", | |
| 793 | + "creators": "Cartier", | |
| 794 | + "slug": "bamboo-coussin-reference-78102-a-yellow-gold", | |
| 795 | + "estimateLow": 400000, | |
| 796 | + "estimateHigh": 800000, | |
| 797 | + "isClosed": false, | |
| 798 | + "closingTime": null, | |
| 799 | + "currentBid": null, | |
| 800 | + "bidCurrency": null, | |
| 801 | + "isSold": false, | |
| 802 | + "finalPrice": null, | |
| 803 | + "finalCurrency": null, | |
| 804 | + "numberOfBids": 1, | |
| 805 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/f02250d/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F77%2F1e%2Fc10676e742a5a3c13b35d18d5aa7%2Fhk1766-dmr6z-014-01-t2-01.jpg", | |
| 806 | + "withdrawn": false | |
| 807 | + }, | |
| 808 | + { | |
| 809 | + "lotId": "032df186-0a6b-4531-abfd-a4805f26f329", | |
| 810 | + "lotNumber": "2244", | |
| 811 | + "title": "Bamboo Coussin, Reference 78110 | A yellow gold wristwatch, Circa 1975", | |
| 812 | + "creators": "Cartier", | |
| 813 | + "slug": "bamboo-coussin-reference-78110-a-yellow-gold", | |
| 814 | + "estimateLow": 300000, | |
| 815 | + "estimateHigh": 600000, | |
| 816 | + "isClosed": false, | |
| 817 | + "closingTime": null, | |
| 818 | + "currentBid": null, | |
| 819 | + "bidCurrency": null, | |
| 820 | + "isSold": false, | |
| 821 | + "finalPrice": null, | |
| 822 | + "finalCurrency": null, | |
| 823 | + "numberOfBids": 1, | |
| 824 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/67d79c8/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Fe5%2F1a%2F6b0f43c04702bbcb9e5fee3fea68%2Fhk1766-dpxxk-092-01-t3-01.jpg", | |
| 825 | + "withdrawn": false | |
| 826 | + }, | |
| 827 | + { | |
| 828 | + "lotId": "191e53f0-c7dc-4fab-9946-225946304fa6", | |
| 829 | + "lotNumber": "2245", | |
| 830 | + "title": "Reverso | A yellow gold reversible dual time wristwatch, Circa 1970", | |
| 831 | + "creators": "Cartier", | |
| 832 | + "slug": "reverso-a-yellow-gold-reversible-dual-time", | |
| 833 | + "estimateLow": 220000, | |
| 834 | + "estimateHigh": 350000, | |
| 835 | + "isClosed": false, | |
| 836 | + "closingTime": null, | |
| 837 | + "currentBid": null, | |
| 838 | + "bidCurrency": null, | |
| 839 | + "isSold": false, | |
| 840 | + "finalPrice": null, | |
| 841 | + "finalCurrency": null, | |
| 842 | + "numberOfBids": null, | |
| 843 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/c1e2fef/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Fe4%2Fe1%2Fe739d08b456b8203059e70371ba4%2Fhk1766-dpwqv-089-01-t3-01.jpg", | |
| 844 | + "withdrawn": false | |
| 845 | + }, | |
| 846 | + { | |
| 847 | + "lotId": "0eb0353d-ae67-48c9-8e0d-98747ffe48ef", | |
| 848 | + "lotNumber": "2246", | |
| 849 | + "title": "Octagonal | A very rare Lady's three colour gold octagonal bracelet watch with pink gold deployant buckle, Circa 1971", | |
| 850 | + "creators": "Cartier, London", | |
| 851 | + "slug": "octagonal-a-very-rare-ladys-three-colour-gold", | |
| 852 | + "estimateLow": 800000, | |
| 853 | + "estimateHigh": 1200000, | |
| 854 | + "isClosed": false, | |
| 855 | + "closingTime": null, | |
| 856 | + "currentBid": null, | |
| 857 | + "bidCurrency": null, | |
| 858 | + "isSold": false, | |
| 859 | + "finalPrice": null, | |
| 860 | + "finalCurrency": null, | |
| 861 | + "numberOfBids": null, | |
| 862 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/58b0ae0/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F8a%2F16%2F48c2bf4a4f14be45281f835b151a%2Fhk1766-dmr6v-013-01-t1-01.jpg", | |
| 863 | + "withdrawn": false | |
| 864 | + }, | |
| 865 | + { | |
| 866 | + "lotId": "43347e62-cd7e-4481-b905-c835e88e0029", | |
| 867 | + "lotNumber": "2247", | |
| 868 | + "title": "Reference 3727 | A yellow gold, diamond and red agate-set bracelet watch with red agate dial, Made in 1977", | |
| 869 | + "creators": "Patek Philippe", | |
| 870 | + "slug": "reference-3727-a-yellow-gold-diamond-and-red-agate", | |
| 871 | + "estimateLow": 200000, | |
| 872 | + "estimateHigh": 400000, | |
| 873 | + "isClosed": false, | |
| 874 | + "closingTime": null, | |
| 875 | + "currentBid": null, | |
| 876 | + "bidCurrency": null, | |
| 877 | + "isSold": false, | |
| 878 | + "finalPrice": null, | |
| 879 | + "finalCurrency": null, | |
| 880 | + "numberOfBids": 2, | |
| 881 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/8143ac6/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2Fd0%2Fdb%2F07407a734bc0a476b5465e0160e7%2Fhk1766-dn4cf-005-02-t3-01.jpg", | |
| 882 | + "withdrawn": false | |
| 883 | + }, | |
| 884 | + { | |
| 885 | + "lotId": "1ac2b17f-0969-46c5-b8c6-b6c8e4daa6cc", | |
| 886 | + "lotNumber": "2248", | |
| 887 | + "title": "London retailed | Mignonette | A silver-gilt and enamel 8-day miniature travelling clock with original Cartier London presentation case, Circa 1911", | |
| 888 | + "creators": "Cartier, Paris", | |
| 889 | + "slug": "london-retailed-mignonette-a-silver-gilt-and", | |
| 890 | + "estimateLow": 28000, | |
| 891 | + "estimateHigh": 45000, | |
| 892 | + "isClosed": false, | |
| 893 | + "closingTime": null, | |
| 894 | + "currentBid": null, | |
| 895 | + "bidCurrency": null, | |
| 896 | + "isSold": false, | |
| 897 | + "finalPrice": null, | |
| 898 | + "finalCurrency": null, | |
| 899 | + "numberOfBids": 1, | |
| 900 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/fe08f9d/2147483647/strip/true/crop/3543x3543+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2F68%2F03%2F1de869a54d5fb08759799d729e9d%2Fhk1766-dklt4-t1-01.jpg", | |
| 901 | + "withdrawn": false | |
| 902 | + }, | |
| 903 | + { | |
| 904 | + "lotId": "cb4425ea-d713-4b18-a4fc-39df4f16e88e", | |
| 905 | + "lotNumber": "2249", | |
| 906 | + "title": "Reference 5401BA | A yellow gold skeletonised bracelet watch, Circa 1971", | |
| 907 | + "creators": "Audemars Piguet", | |
| 908 | + "slug": "reference-5401ba-a-yellow-gold-skeletonised", | |
| 909 | + "estimateLow": 200000, | |
| 910 | + "estimateHigh": 400000, | |
| 911 | + "isClosed": false, | |
| 912 | + "closingTime": null, | |
| 913 | + "currentBid": null, | |
| 914 | + "bidCurrency": null, | |
| 915 | + "isSold": false, | |
| 916 | + "finalPrice": null, | |
| 917 | + "finalCurrency": null, | |
| 918 | + "numberOfBids": 1, | |
| 919 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/2fbbed1/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F98%2F0b%2F2e504c9949059654bf85dbfbfd9f%2Fhk1766-dnkx2-021-01-t3-01.jpg", | |
| 920 | + "withdrawn": false | |
| 921 | + }, | |
| 922 | + { | |
| 923 | + "lotId": "91844ee6-3b68-4d3e-87d1-f384857a639b", | |
| 924 | + "lotNumber": "2250", | |
| 925 | + "title": "Audemars Piguet | A white gold and diamond-set skeletonised bracelet watch, Circa 1990", | |
| 926 | + "creators": "Audemars Piguet", | |
| 927 | + "slug": "audemars-piguet-a-white-gold-and-diamond-set", | |
| 928 | + "estimateLow": 240000, | |
| 929 | + "estimateHigh": 400000, | |
| 930 | + "isClosed": false, | |
| 931 | + "closingTime": null, | |
| 932 | + "currentBid": null, | |
| 933 | + "bidCurrency": null, | |
| 934 | + "isSold": false, | |
| 935 | + "finalPrice": null, | |
| 936 | + "finalCurrency": null, | |
| 937 | + "numberOfBids": null, | |
| 938 | + "imageUrl": "https://sothebys-md.brightspotcdn.com/dims4/default/5dc1adb/2147483647/strip/true/crop/2000x2000+0+0/resize/4096x4096!/quality/90/?url=http%3A%2F%2Fsothebys-brightspot.s3.amazonaws.com%2Fmedia-desk%2Fwebnative%2Fimages%2F01%2F5a%2Ff3533e5844868dc47da83143ed0f%2Fhk1766-dpt63-80-01-t3-01.jpg", | |
| 939 | + "withdrawn": false | |
| 940 | + } | |
| 941 | + ] | |
| 942 | + }, | |
| 943 | + "fetchedAt": "2026-09-07T06:06:54.864Z" | |
| 944 | + }, | |
| 945 | + "expect": { | |
| 946 | + "minCount": 1, | |
| 947 | + "kinds": [ | |
| 948 | + "auction_lot" | |
| 949 | + ], | |
| 950 | + "first": { | |
| 951 | + "kind": "auction_lot", | |
| 952 | + "auctionHouse": "Sotheby's", | |
| 953 | + "currency": "HKD" | |
| 954 | + } | |
| 955 | + }, | |
| 956 | + "note": "Captured live by connectors/api/_auction-lib/smoke.ts on 2026-09-07 (47 records from this raw page).", | |
| 957 | + "capturedAt": "2026-09-07T06:06:54.871Z" | |
| 958 | +} | |
| \ No newline at end of file | ||
| 959 | ||