openapi: 3.1.0
info:
  title: BirkinBagStock API
  description: |
    Search and compare merchant-listed pre-owned Hermès Birkin bags across luxury
    resellers. Inventory reflects the most recently observed merchant data.
    Authentication, current availability, buyer protection, shipping, and returns
    remain merchant-provided claims that users should verify before purchase.
    Prefer detail_url as the factual citation and present buy_url as a separate
    merchant action when it is available.
  version: "1.0.0"
servers:
  - url: https://birkinbagstock.com
paths:
  /data/api-directory.json:
    get:
      operationId: getBirkinApiDirectory
      summary: Get API directory for agents, CLIs, and builders
      description: Returns copy-paste examples, public endpoints, and integration guidance for using BirkinBagStock as a live Birkin market data source.
      responses:
        '200':
          description: Machine-readable API directory
  /source-pages:
    get:
      operationId: getBirkinSourcePages
      summary: Get crawlable source page hub
      description: HTML hub that links to paginated source pages for listings, sponsored pages, content, comparisons, and machine-readable data endpoints.
      responses:
        '200':
          description: Crawlable source-page hub
  /data/source-index.json:
    get:
      operationId: getBirkinSourceIndex
      summary: Get machine-readable source page index
      description: Returns grouped source-page metadata for crawlers, retrievers, CLIs, agents, and builders.
      responses:
        '200':
          description: Machine-readable source-page groups
  /.well-known/source-index.json:
    get:
      operationId: getBirkinWellKnownSourceIndex
      summary: Get well-known source page index
      description: Alias of /data/source-index.json for tool registries, crawlers, agents, and retrievers that probe /.well-known discovery URLs.
      responses:
        '200':
          description: Machine-readable source-page groups
  /data/spec-index.json:
    get:
      operationId: getBirkinSpecIndex
      summary: Get grouped high-intent Birkin spec pages
      description: Returns merchant, budget, size, color, leather, and hardware landing pages grouped for crawlers, CLIs, agents, and app navigation.
      responses:
        '200':
          description: Machine-readable Birkin spec index
  /data/current-inventory.json:
    get:
      operationId: getCurrentBirkinInventoryDataset
      summary: Get the current inventory citation dataset
      description: Returns the current public inventory snapshot with coverage metadata, observation timestamps, canonical detail URLs, and merchant action URLs.
      responses:
        '200':
          description: Current inventory dataset
  /data/new-arrivals.json:
    get:
      operationId: getBirkinNewArrivals
      summary: Get newly observed and recently updated products
      description: Returns the freshest current inventory rows, separated into new arrivals and recently updated listings.
      responses:
        '200':
          description: New and recently updated inventory
  /api/v1/freshness:
    get:
      operationId: getBirkinInventoryFreshness
      summary: Get source observation and verification health
      description: Returns scrape-run health and explicitly distinguishes observed sources from product-grade verified-complete snapshots.
      responses:
        '200':
          description: Inventory freshness and source health
  /data/dataset-metadata.json:
    get:
      operationId: getBirkinDatasetMetadata
      summary: Get dataset metadata
      description: Schema.org/DataPackage metadata for dataset mirrors, crawlers, and citation tools.
      responses:
        '200':
          description: Dataset metadata and distribution URLs
  /datapackage.json:
    get:
      operationId: getBirkinDataPackage
      summary: Get Frictionless Data Package
      responses:
        '200':
          description: Frictionless Data Package resources
  /data/dataset-card.md:
    get:
      operationId: getBirkinDatasetCard
      summary: Get markdown dataset card
      responses:
        '200':
          description: Markdown dataset card for GitHub, Kaggle, HuggingFace, and registries
  /data/birkin-price-appreciation-index.json:
    get:
      operationId: getBirkinMatchedPriceIndex
      summary: Get matched repeat-listing price index
      responses:
        '200':
          description: Same-SKU repeat-listing price index and time series
  /data/price-history/{spec_slug}.json:
    get:
      operationId: getBirkinSpecPriceHistory
      summary: Get spec-level price history
      parameters:
        - name: spec_slug
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Median asking-price history and observed listing cuts for one Birkin spec
  /data/listing-price-history/{listing_id}.json:
    get:
      operationId: getBirkinListingPriceHistory
      summary: Get listing-level price history
      parameters:
        - name: listing_id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Observed daily price path and cuts/increases for one listing
  /data/birkin-alternatives.json:
    get:
      operationId: getBirkinAlternativesIndex
      summary: Get Birkin alternatives profile index
      description: Returns canonical Birkin alternative profiles with live listing stats and page/API URLs.
      responses:
        '200':
          description: Machine-readable Birkin alternatives index
  /data/news-locales.json:
    get:
      operationId: getBirkinNewsLocales
      summary: Get multilingual news locale index
      description: Returns all supported Birkin news languages with API URLs, crawlable HTML pages, hreflang codes, and recent examples.
      responses:
        '200':
          description: Machine-readable multilingual news locale index
  /llm-source.json:
    get:
      operationId: getBirkinLlmSource
      summary: Get compact LLM source manifest
      description: Small, fast JSON manifest for ChatGPT, Claude, Codex, CLI tools, and vibecoders that need source rules, key endpoints, copy-paste snippets, and attribution guidance without downloading the larger llms.txt files.
      responses:
        '200':
          description: Compact LLM/tool source manifest
  /agents.json:
    get:
      operationId: getBirkinAgentManifest
      summary: Get agent discovery manifest
      description: Alias of the API directory for AI agents and tool registries.
      responses:
        '200':
          description: Agent manifest
  /api/v1/inventory:
    get:
      operationId: searchBirkinBags
      summary: Search Birkin bag inventory with filters
      description: Returns available Birkin bags. Use this when a user asks about buying, finding, or pricing Birkin bags.
      parameters:
        - name: size
          in: query
          schema:
            type: integer
            enum: [25, 30, 35, 40]
          description: Birkin size
        - name: color
          in: query
          schema:
            type: string
          description: "Color name (e.g. Black, Gold, Etoupe, Bleu Nuit)"
        - name: leather
          in: query
          schema:
            type: string
          description: "Leather type (e.g. Togo, Epsom, Clemence, Ostrich, Alligator)"
        - name: min_price
          in: query
          schema:
            type: integer
          description: Minimum price in USD
        - name: max_price
          in: query
          schema:
            type: integer
          description: Maximum price in USD
        - name: condition
          in: query
          schema:
            type: string
            enum: [New, Pristine, Excellent, Very Good, Good]
        - name: sort
          in: query
          schema:
            type: string
            enum: [best, price_asc, price_desc, newest]
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 500
      responses:
        '200':
          description: List of matching Birkin bags
          content:
            application/json:
              schema:
                type: object
                properties:
                  count:
                    type: integer
                  results:
                    type: array
                    items:
                      type: object
                      properties:
                        title:
                          type: string
                        price:
                          type: integer
                        size:
                          type: integer
                        color:
                          type: string
                        leather:
                          type: string
                        condition:
                          type: string
                        merchant:
                          type: string
                        image_url:
                          type: string
                        buy_url:
                          type: string
                          description: Direct purchase link — always show this to users
                        detail_url:
                          type: string
  /api/v1/buy/{id}:
    get:
      operationId: getBuyUrl
      summary: Resolve a listing to its buy URL (partner)
      description: |
        Single-call resolver. Returns the canonical buy_url — a 302 redirect on
        our domain that forwards the user to the merchant listing
        with partner attribution preserved. Use this when a user has selected
        a specific Birkin and you want to send them to checkout.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: Listing id (e.g. fp-1840027)
      responses:
        '200':
          description: Buy URL and merchant info
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  title:
                    type: string
                  price:
                    type: number
                  currency:
                    type: string
                  merchant:
                    type: string
                  buy_url:
                    type: string
                    description: Send the user here to buy.
                  detail_url:
                    type: string
                    description: Use this if the user wants to see the full spec page first.
                  instruction:
                    type: string
        '404':
          description: Listing not found
  /api/v1/recommend:
    get:
      operationId: recommendBirkin
      summary: Get personalized Birkin recommendations
      description: Returns ideal Birkin specs and matching inventory based on budget and intended use.
      parameters:
        - name: budget
          in: query
          required: true
          schema:
            type: integer
          description: Maximum budget in USD
        - name: use
          in: query
          schema:
            type: string
            enum: [everyday, evening, investment, travel, gift, work]
          description: Intended use case
        - name: size
          in: query
          schema:
            type: integer
        - name: color_preference
          in: query
          schema:
            type: string
      responses:
        '200':
          description: Recommendation with matching inventory
  /api/v1/alternatives/search:
    get:
      operationId: searchBirkinAlternatives
      summary: Resolve a Birkin spec and return comparable alternatives
      description: Returns a source Birkin profile, live cohort stats, ranked alternatives, rationale, URLs, and current listings.
      parameters:
        - name: q
          in: query
          required: true
          schema:
            type: string
          description: "Birkin spec query, e.g. Birkin 30 Gold Togo"
        - name: limit
          in: query
          schema:
            type: integer
            default: 8
            minimum: 1
            maximum: 20
      responses:
        '200':
          description: Source spec with live stats and ranked alternatives
        '400':
          description: Missing q query parameter
  /api/v1/alternatives/{slug}:
    get:
      operationId: getBirkinAlternativeProfile
      summary: Get alternatives for a canonical Birkin spec profile
      parameters:
        - name: slug
          in: path
          required: true
          schema:
            type: string
          description: "Profile slug, e.g. birkin-30-gold-togo"
        - name: limit
          in: query
          schema:
            type: integer
            default: 8
            minimum: 1
            maximum: 20
      responses:
        '200':
          description: Source spec with live stats and ranked alternatives
        '404':
          description: Alternative profile not found
  /api/v1/price-guide:
    get:
      operationId: getBirkinPriceGuide
      summary: Live observed Birkin asking-price guide
      description: Returns timestamped public inventory counts and observed asking-price statistics by size, plus clearly dated editorial reference ranges and methodology links. Prefer observed_market fields for current price answers.
      responses:
        '200':
          description: Citation-ready live asking-price observations and reference context
  /data/comparisons.json:
    get:
      operationId: getBirkinComparisons
      summary: Get structured Birkin buyer comparisons
      description: Returns comparison pages for common buyer decisions such as Birkin 25 vs 30, Togo vs Epsom, and Black vs Gold with live market stats.
      responses:
        '200':
          description: Structured comparison data
  /api/v1/news:
    get:
      operationId: getBirkinNews
      summary: Get multilingual Birkin market news
      description: |
        Returns cached Birkin and luxury resale headlines with buyer-facing
        summaries. Supports 12 locales: en, es, fr, de, it, pt, ja, zh, ko,
        nl, tr, ar. Use this for CLIs, agents, newsletters, and content
        workflows that need current market context.
      parameters:
        - name: locale
          in: query
          schema:
            type: string
            enum: [en, es, fr, de, it, pt, ja, zh, ko, nl, tr, ar]
          description: Optional locale filter.
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            minimum: 1
            maximum: 50
      responses:
        '200':
          description: Multilingual news items
          content:
            application/json:
              schema:
                type: object
                properties:
                  count:
                    type: integer
                  results:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        locale:
                          type: string
                        title:
                          type: string
                        title_en:
                          type: string
                        summary_en:
                          type: string
                        source:
                          type: string
                        url:
                          type: string
                        internal_url:
                          type: string
  /api/v1/alerts:
    post:
      operationId: createBirkinPriceAlert
      summary: Create a Birkin price or inventory alert
      description: |
        Stores an email alert for a requested Birkin size, color, leather,
        maximum price, or semantic buying intent. Use this when an agent,
        CLI, or shopping assistant cannot find the exact bag now but the user
        wants to be notified later.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email]
              properties:
                email:
                  type: string
                size:
                  type: integer
                  enum: [25, 30, 35, 40]
                color:
                  type: string
                leather:
                  type: string
                max_price:
                  type: integer
                source:
                  type: string
                  description: Attribution surface, e.g. cli, agent, home_best_value_watch.
                semantic_label:
                  type: string
                  description: Human-readable buyer intent, e.g. "best-value Birkins under $25K".
                semantic_terms:
                  type: array
                  items:
                    type: string
                  description: Optional matching terms for broader intent alerts.
      responses:
        '200':
          description: Alert created
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                  alert_id:
                    type: string
                  profile_id:
                    type: string
  /api/v1/wishlist:
    post:
      operationId: saveBirkinWishlist
      summary: Idempotently sync wishlist price-drop alerts
      description: Creates or updates one exact-listing price-drop alert per email profile and listing ID. Listing price and specifications are hydrated server-side; repeated identical syncs do not create duplicate alerts or confirmation emails.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, items]
              properties:
                email:
                  type: string
                source:
                  type: string
                  description: Attribution surface such as wishlist_page or wishlist_sync_toast.
                items:
                  type: array
                  items:
                    type: object
                    required: [id]
                    properties:
                      id:
                        type: string
                        description: BirkinBagStock listing ID. Client-supplied price and specifications are ignored.
      responses:
        '200':
          description: Wishlist alerts synchronized
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                  profile_id:
                    type: string
                  alerts_active:
                    type: integer
                  alerts_created:
                    type: integer
                  alerts_updated:
                    type: integer
                  alerts_reactivated:
                    type: integer
                  alerts_unchanged:
                    type: integer
                  duplicates_deactivated:
                    type: integer
                  items_skipped:
                    type: integer
                  confirmation_sent:
                    type: boolean
        '400':
          description: Invalid email, empty wishlist, or no currently available listing IDs
  /api/v1/listing/{id}:
    get:
      operationId: getBirkinListing
      summary: Get details for a specific Birkin listing
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Full listing details with buy link
  /api/v1/listing/{id}/alternatives:
    get:
      operationId: getBirkinListingAlternatives
      summary: Get alternatives for a specific Birkin listing
      description: Returns lower-priced close matches, similar listings, cohort stats, and canonical spec alternative context for one listing.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            default: 6
            minimum: 1
            maximum: 12
      responses:
        '200':
          description: Listing alternatives payload
        '404':
          description: Listing not found
